From 412e0404c05f19cd1fb0a8426361abfe2a0455ce Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 19 May 2021 21:23:32 +0200 Subject: [PATCH] deal with `const_evaluatable_checked` in `ConstEquate` --- .../src/traits/fulfill.rs | 13 ++++++++-- .../src/traits/select/mod.rs | 24 ++++++++++++++++++- .../const_evaluatable_checked/different-fn.rs | 1 + .../different-fn.stderr | 12 +++++++++- .../evaluated-to-ambig.rs | 22 +++++++++++++++++ .../issues/issue-62504.full.stderr | 12 +++++++++- .../ui/const-generics/issues/issue-62504.rs | 2 +- 7 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index fc9739f70d40d..120680092baaa 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 08d452900c8e1..0cad3ddbf7d54 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 05049d9c2a6ef..26c4295cd9b18 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(PhantomData); fn test() -> [u8; size_of::()] { [0; size_of::>()] //~^ 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 7c11a47b2f0f9..2aeb9b961ffde 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::>()] + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::()`, found `size_of::>()` + | + = note: expected type `size_of::()` + found type `size_of::>()` + error: unconstrained generic constant --> $DIR/different-fn.rs:10:9 | @@ -6,5 +15,6 @@ LL | [0; size_of::>()] | = help: try adding a `where` bound using this expression: `where [(); size_of::>()]:` -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 0000000000000..0f36ce383a84c --- /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 {} +trait IsTrue {} +impl IsTrue for Assert {} + +struct Foo; +trait Bar {} +impl Bar for Foo +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 f09af76325e96..efbcdc3d2b783 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 0b95754cab45d..1b70cd1c37669 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 ArrayHolder { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) //~^ ERROR constant expression depends on a generic parameter - //[min]~| ERROR mismatched types + //~| ERROR mismatched types } }