about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs60
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs24
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.rs15
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr10
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/unifies_evaluatable.rs18
-rw-r--r--src/test/ui/const-generics/issues/issue-83765.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-83765.stderr42
7 files changed, 126 insertions, 45 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index bf7396d6113..5df1f85ec41 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -18,6 +18,8 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitor};
 use rustc_span::Span;
 use std::ops::ControlFlow;
 
+use crate::traits::ObligationCtxt;
+
 /// Check if a given constant can be evaluated.
 #[instrument(skip(infcx), level = "debug")]
 pub fn is_const_evaluatable<'tcx>(
@@ -71,26 +73,27 @@ pub fn is_const_evaluatable<'tcx>(
         // See #74595 for more details about this.
         let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
         match concrete {
-          // If we're evaluating a generic foreign constant, under a nightly compiler while
-          // the current crate does not enable `feature(generic_const_exprs)`, abort
-          // compilation with a useful error.
-          Err(_) if tcx.sess.is_nightly_build()
-            && let Ok(Some(ac)) = tcx.expand_abstract_consts(ct)
-            && let ty::ConstKind::Expr(_) = ac.kind() => {
-              tcx.sess
-                  .struct_span_fatal(
-                      // Slightly better span than just using `span` alone
-                      if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
-                      "failed to evaluate generic const expression",
-                  )
-                  .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
-                  .span_suggestion_verbose(
-                      rustc_span::DUMMY_SP,
-                      "consider enabling this feature",
-                      "#![feature(generic_const_exprs)]\n",
-                      rustc_errors::Applicability::MaybeIncorrect,
-                  )
-                  .emit()
+            // If we're evaluating a generic foreign constant, under a nightly compiler while
+            // the current crate does not enable `feature(generic_const_exprs)`, abort
+            // compilation with a useful error.
+            Err(_) if tcx.sess.is_nightly_build()
+                && let Ok(Some(ac)) = tcx.expand_abstract_consts(ct)
+                && let ty::ConstKind::Expr(_) = ac.kind() => 
+            {
+                tcx.sess
+                    .struct_span_fatal(
+                        // Slightly better span than just using `span` alone
+                        if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
+                        "failed to evaluate generic const expression",
+                    )
+                    .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
+                    .span_suggestion_verbose(
+                        rustc_span::DUMMY_SP,
+                        "consider enabling this feature",
+                        "#![feature(generic_const_exprs)]\n",
+                        rustc_errors::Applicability::MaybeIncorrect,
+                    )
+                    .emit()
             }
 
             Err(ErrorHandled::TooGeneric) => {
@@ -130,12 +133,17 @@ fn satisfied_from_param_env<'tcx>(
     impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
         type BreakTy = ();
         fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-            if c.ty() == self.ct.ty()
-                && let Ok(_nested_obligations) = self
-                    .infcx
-                    .at(&ObligationCause::dummy(), self.param_env)
-                    .eq(c, self.ct)
-            {
+            if let Ok(()) = self.infcx.commit_if_ok(|_| {
+                let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
+                if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
+                    && let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct)
+                    && ocx.select_all_or_error().is_empty()
+                {
+                    Ok(())
+                } else {
+                    Err(())
+                }
+            }) {
                 ControlFlow::BREAK
             } else if let ty::ConstKind::Expr(e) = c.kind() {
                 e.visit_with(self)
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 9f4423605ab..806e031a4bb 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::obligation_forest::ProcessResult;
 use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
-use rustc_hir::def::DefKind;
 use rustc_infer::traits::ProjectionCacheKey;
 use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation};
 use rustc_middle::mir::interpret::ErrorHandled;
@@ -465,6 +464,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     // Let's just see where this breaks :shrug:
                     match (c1.kind(), c2.kind()) {
                         (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) => {
+                            // FIXME: remove
+                            use rustc_hir::def::DefKind;
                             if tcx.def_kind(a.def.did) == DefKind::AssocConst
                                 || tcx.def_kind(b.def.did) == DefKind::AssocConst
                             {
@@ -477,16 +478,17 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                                     ),
                                 );
                             }
-                            if let (Ok(Some(a)), Ok(Some(b))) = (
-                                    tcx.expand_abstract_consts(c1),
-                                    tcx.expand_abstract_consts(c2),
-                                ) && a.ty() == b.ty() &&
-                                  let Ok(new_obligations) = infcx
-                                      .at(&obligation.cause, obligation.param_env)
-                                      .eq(a, b) {
-                                            return ProcessResult::Changed(mk_pending(
-                                                new_obligations.into_obligations(),
-                                            ));
+
+                            if let Ok(Some(a)) = tcx.expand_abstract_consts(c1)
+                                && let Ok(Some(b)) = tcx.expand_abstract_consts(c2)
+                                && a.ty() == b.ty() 
+                                && let Ok(new_obligations) = infcx
+                                    .at(&obligation.cause, obligation.param_env)
+                                    .eq(a, b) 
+                                {
+                                    return ProcessResult::Changed(mk_pending(
+                                        new_obligations.into_obligations(),
+                                    ));
                                 }
                         }
                         _ => {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.rs b/src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.rs
new file mode 100644
index 00000000000..c8f7553da79
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.rs
@@ -0,0 +1,15 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    const ASSOC: usize;
+}
+
+fn foo<T: Trait, U: Trait>() where [(); U::ASSOC]:, {
+    bar::<{ T::ASSOC }>();
+    //~^ ERROR: unconstrained generic constant
+}
+
+fn bar<const N: usize>() {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr b/src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr
new file mode 100644
index 00000000000..e4a0cabe572
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr
@@ -0,0 +1,10 @@
+error: unconstrained generic constant
+  --> $DIR/doesnt_unify_evaluatable.rs:9:11
+   |
+LL |     bar::<{ T::ASSOC }>();
+   |           ^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { T::ASSOC }]:`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/unifies_evaluatable.rs b/src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/unifies_evaluatable.rs
new file mode 100644
index 00000000000..6597b9f2b3f
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/unifies_evaluatable.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    const ASSOC: usize;
+}
+
+fn foo<T: Trait, U: Trait>() where [(); T::ASSOC]:, {
+    bar::<{ T::ASSOC }>();
+}
+
+fn bar<const N: usize>() -> [(); N] {
+    [(); N]
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-83765.rs b/src/test/ui/const-generics/issues/issue-83765.rs
index 674efa723cf..cf59763675b 100644
--- a/src/test/ui/const-generics/issues/issue-83765.rs
+++ b/src/test/ui/const-generics/issues/issue-83765.rs
@@ -59,9 +59,11 @@ impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T,
         assert!(DIM >= T::DIM);
         if !self.inbounds(index) {
             //~^ ERROR mismatched types
+            //~^^ ERROR unconstrained generic constant
             return None;
         }
         let size = self.size();
+        //~^ ERROR unconstrained generic constant
         let newindex: [usize; T::DIM] = Default::default();
         //~^ ERROR the trait bound
         self.reference.bget(newindex)
diff --git a/src/test/ui/const-generics/issues/issue-83765.stderr b/src/test/ui/const-generics/issues/issue-83765.stderr
index 3cf1aab3a8b..f84fd014635 100644
--- a/src/test/ui/const-generics/issues/issue-83765.stderr
+++ b/src/test/ui/const-generics/issues/issue-83765.stderr
@@ -17,7 +17,7 @@ LL |     fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
               found constant `DIM`
 
 error[E0308]: method not compatible with trait
-  --> $DIR/issue-83765.rs:84:5
+  --> $DIR/issue-83765.rs:86:5
    |
 LL |     fn size(&self) -> [usize; DIM] {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
@@ -26,7 +26,7 @@ LL |     fn size(&self) -> [usize; DIM] {
               found constant `DIM`
 
 error[E0308]: method not compatible with trait
-  --> $DIR/issue-83765.rs:96:5
+  --> $DIR/issue-83765.rs:98:5
    |
 LL |     fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
@@ -34,6 +34,19 @@ LL |     fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
    = note: expected constant `Self::DIM`
               found constant `DIM`
 
+error: unconstrained generic constant
+  --> $DIR/issue-83765.rs:60:18
+   |
+LL |         if !self.inbounds(index) {
+   |                  ^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
+note: required by a bound in `TensorSize::inbounds`
+  --> $DIR/issue-83765.rs:16:39
+   |
+LL |     fn inbounds(&self, index: [usize; Self::DIM]) -> bool {
+   |                                       ^^^^^^^^^ required by this bound in `TensorSize::inbounds`
+
 error[E0308]: mismatched types
   --> $DIR/issue-83765.rs:60:27
    |
@@ -43,8 +56,21 @@ LL |         if !self.inbounds(index) {
    = note: expected constant `Self::DIM`
               found constant `DIM`
 
+error: unconstrained generic constant
+  --> $DIR/issue-83765.rs:65:25
+   |
+LL |         let size = self.size();
+   |                         ^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
+note: required by a bound in `TensorSize::size`
+  --> $DIR/issue-83765.rs:15:31
+   |
+LL |     fn size(&self) -> [usize; Self::DIM];
+   |                               ^^^^^^^^^ required by this bound in `TensorSize::size`
+
 error[E0277]: the trait bound `[usize; _]: Default` is not satisfied
-  --> $DIR/issue-83765.rs:65:41
+  --> $DIR/issue-83765.rs:67:41
    |
 LL |         let newindex: [usize; T::DIM] = Default::default();
    |                                         ^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[usize; _]`
@@ -55,7 +81,7 @@ LL | impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a
    |                                                                                                  +++++++++++++++++++++++++
 
 error: unconstrained generic constant
-  --> $DIR/issue-83765.rs:86:24
+  --> $DIR/issue-83765.rs:88:24
    |
 LL |         self.reference.size()
    |                        ^^^^
@@ -68,7 +94,7 @@ LL |     fn size(&self) -> [usize; Self::DIM];
    |                               ^^^^^^^^^ required by this bound in `TensorSize::size`
 
 error[E0308]: mismatched types
-  --> $DIR/issue-83765.rs:86:9
+  --> $DIR/issue-83765.rs:88:9
    |
 LL |         self.reference.size()
    |         ^^^^^^^^^^^^^^^^^^^^^ expected `DIM`, found `Self::DIM`
@@ -77,7 +103,7 @@ LL |         self.reference.size()
               found constant `Self::DIM`
 
 error: unconstrained generic constant
-  --> $DIR/issue-83765.rs:98:24
+  --> $DIR/issue-83765.rs:100:24
    |
 LL |         self.reference.bget(index).map(&self.closure)
    |                        ^^^^
@@ -90,7 +116,7 @@ LL |     fn bget(&self, index: [usize; Self::DIM]) -> Option<Self::Element>;
    |                                   ^^^^^^^^^ required by this bound in `Broadcastable::bget`
 
 error[E0308]: mismatched types
-  --> $DIR/issue-83765.rs:98:29
+  --> $DIR/issue-83765.rs:100:29
    |
 LL |         self.reference.bget(index).map(&self.closure)
    |                             ^^^^^ expected `Self::DIM`, found `DIM`
@@ -98,7 +124,7 @@ LL |         self.reference.bget(index).map(&self.closure)
    = note: expected constant `Self::DIM`
               found constant `DIM`
 
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.