about summary refs log tree commit diff
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2021-05-19 21:23:32 +0200
committerlcnr <rust@lcnr.de>2021-05-19 21:27:51 +0200
commit412e0404c05f19cd1fb0a8426361abfe2a0455ce (patch)
tree347933727759b65bcd9a4cdb8548823d254b1354
parent1773f14a24c49356b384e45ebb45643bc9bef2c4 (diff)
deal with `const_evaluatable_checked` in `ConstEquate`
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs24
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs1
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr12
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs22
-rw-r--r--src/test/ui/const-generics/issues/issue-62504.full.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-62504.rs2
7 files changed, 80 insertions, 6 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index fc9739f70d4..120680092ba 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -6,7 +6,7 @@ use rustc_errors::ErrorReported;
 use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
 use rustc_middle::mir::abstract_const::NotConstEvaluatable;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
@@ -591,7 +591,16 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                             )
                         }
                         (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
-                            ProcessResult::Unchanged
+                            if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+                                ProcessResult::Unchanged
+                            } else {
+                                // Two different constants using generic parameters ~> error.
+                                let expected_found = ExpectedFound::new(true, c1, c2);
+                                ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError(
+                                    expected_found,
+                                    TypeError::ConstMismatch(expected_found),
+                                ))
+                            }
                         }
                     }
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 08d452900c8..0cad3ddbf7d 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -557,6 +557,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ty::PredicateKind::ConstEquate(c1, c2) => {
                     debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
 
+                    if self.tcx().features().const_evaluatable_checked {
+                        // FIXME: we probably should only try to unify abstract constants
+                        // if the constants depend on generic parameters.
+                        //
+                        // Let's just see where this breaks :shrug:
+                        if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+                            (c1.val, c2.val)
+                        {
+                            if self
+                                .tcx()
+                                .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs)))
+                            {
+                                return Ok(EvaluatedToOk);
+                            }
+                        }
+                    }
+
                     let evaluate = |c: &'tcx ty::Const<'tcx>| {
                         if let ty::ConstKind::Unevaluated(unevaluated) = c.val {
                             self.infcx
@@ -591,7 +608,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             )
                         }
                         (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
-                            Ok(EvaluatedToAmbig)
+                            if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+                                Ok(EvaluatedToAmbig)
+                            } else {
+                                // Two different constants using generic parameters ~> error.
+                                Ok(EvaluatedToErr)
+                            }
                         }
                     }
                 }
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs
index 05049d9c2a6..26c4295cd9b 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs
@@ -9,6 +9,7 @@ struct Foo<T>(PhantomData<T>);
 fn test<T>() -> [u8; size_of::<T>()] {
     [0; size_of::<Foo<T>>()]
     //~^ ERROR unconstrained generic constant
+    //~| ERROR mismatched types
 }
 
 fn main() {
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr
index 7c11a47b2f0..2aeb9b961ff 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr
@@ -1,3 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/different-fn.rs:10:5
+   |
+LL |     [0; size_of::<Foo<T>>()]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::<T>()`, found `size_of::<Foo<T>>()`
+   |
+   = note: expected type `size_of::<T>()`
+              found type `size_of::<Foo<T>>()`
+
 error: unconstrained generic constant
   --> $DIR/different-fn.rs:10:9
    |
@@ -6,5 +15,6 @@ LL |     [0; size_of::<Foo<T>>()]
    |
    = help: try adding a `where` bound using this expression: `where [(); size_of::<Foo<T>>()]:`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs b/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs
new file mode 100644
index 00000000000..0f36ce383a8
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+// We previously always returned ambiguity when equating generic consts, even if they
+// only contain generic parameters. This is incorrect as trying to unify `N > 1` with `M > 1`
+// should fail.
+#![allow(incomplete_features)]
+#![feature(const_generics, const_evaluatable_checked)]
+
+enum Assert<const COND: bool> {}
+trait IsTrue {}
+impl IsTrue for Assert<true> {}
+
+struct Foo<const N: usize, const M: usize>;
+trait Bar<const N: usize, const M: usize> {}
+impl<const N: usize, const M: usize> Bar<N, M> for Foo<N, M>
+where
+    Assert<{ N > 1 }>: IsTrue,
+    Assert<{ M > 1 }>: IsTrue,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-62504.full.stderr b/src/test/ui/const-generics/issues/issue-62504.full.stderr
index f09af76325e..efbcdc3d2b7 100644
--- a/src/test/ui/const-generics/issues/issue-62504.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-62504.full.stderr
@@ -1,3 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-62504.rs:18:21
+   |
+LL |         ArrayHolder([0; Self::SIZE])
+   |                     ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
+   |
+   = note: expected type `X`
+              found type `Self::SIZE`
+
 error: constant expression depends on a generic parameter
   --> $DIR/issue-62504.rs:18:25
    |
@@ -6,5 +15,6 @@ LL |         ArrayHolder([0; Self::SIZE])
    |
    = note: this may fail depending on what value the parameter takes
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs
index 0b95754cab4..1b70cd1c376 100644
--- a/src/test/ui/const-generics/issues/issue-62504.rs
+++ b/src/test/ui/const-generics/issues/issue-62504.rs
@@ -17,7 +17,7 @@ impl<const X: usize> ArrayHolder<X> {
     pub const fn new() -> Self {
         ArrayHolder([0; Self::SIZE])
         //~^ ERROR constant expression depends on a generic parameter
-        //[min]~| ERROR mismatched types
+        //~| ERROR mismatched types
     }
 }