From 8c729bd0f3bc8726e50e05c0337d960ab4791a18 Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 14 Nov 2022 18:20:53 +0000 Subject: [PATCH] handle nested obligations in `satisfied_from_param_env` --- .../src/traits/const_evaluatable.rs | 60 +++++++++++-------- .../src/traits/fulfill.rs | 24 ++++---- .../doesnt_unify_evaluatable.rs | 15 +++++ .../doesnt_unify_evaluatable.stderr | 10 ++++ .../unifies_evaluatable.rs | 18 ++++++ .../ui/const-generics/issues/issue-83765.rs | 2 + .../const-generics/issues/issue-83765.stderr | 42 ++++++++++--- 7 files changed, 126 insertions(+), 45 deletions(-) create mode 100644 src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr create mode 100644 src/test/ui/const-generics/generic_const_exprs/assoc_const_unification/unifies_evaluatable.rs 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 { - 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() where [(); U::ASSOC]:, { + bar::<{ T::ASSOC }>(); + //~^ ERROR: unconstrained generic constant +} + +fn bar() {} + +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() where [(); T::ASSOC]:, { + bar::<{ T::ASSOC }>(); +} + +fn bar() -> [(); 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 { 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 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM` @@ -34,6 +34,19 @@ LL | fn bget(&self, index: [usize; DIM]) -> Option { = 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; | ^^^^^^^^^ 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`.