diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index e5b212eb757..ca5ea7d053a 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -198,7 +198,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( ( ty::PredicateKind::ConstEvaluatable(a), ty::PredicateKind::ConstEvaluatable(b), - ) => tcx.try_unify_abstract_consts(self_param_env.and((a, b))), + ) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(), ( ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)), ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0a8a1bec9b8..33ed3b96aa8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1101,8 +1101,6 @@ fn check_type_defn<'tcx, F>( // Explicit `enum` discriminant values must const-evaluate successfully. if let Some(discr_def_id) = variant.explicit_discr { - let discr_substs = InternalSubsts::identity_for_item(tcx, discr_def_id.to_def_id()); - let cause = traits::ObligationCause::new( tcx.def_span(discr_def_id), wfcx.body_id, @@ -1112,10 +1110,7 @@ fn check_type_defn<'tcx, F>( cause, wfcx.param_env, ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable( - ty::UnevaluatedConst::new( - ty::WithOptConstParam::unknown(discr_def_id.to_def_id()), - discr_substs, - ), + ty::Const::from_anon_const(tcx, discr_def_id), )) .to_predicate(tcx), )); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index db8f8de68f2..2e84e1d0160 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -318,10 +318,10 @@ impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> { fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { let def_id = self.tcx.hir().local_def_id(c.hir_id); let ct = ty::Const::from_anon_const(self.tcx, def_id); - if let ty::ConstKind::Unevaluated(uv) = ct.kind() { + if let ty::ConstKind::Unevaluated(_) = ct.kind() { let span = self.tcx.hir().span(c.hir_id); self.preds.insert(( - ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv)) + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct)) .to_predicate(self.tcx), span, )); diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 315e3794f15..f998e608344 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -263,6 +263,10 @@ pub fn eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 { self.try_eval_usize(tcx, param_env) .unwrap_or_else(|| bug!("expected usize, got {:#?}", self)) } + + pub fn is_ct_infer(self) -> bool { + matches!(self.kind(), ty::ConstKind::Infer(_)) + } } pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index a6d0678e99d..bac7e9aae8b 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -256,7 +256,7 @@ fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) { self.add_substs(substs); } ty::PredicateKind::ConstEvaluatable(uv) => { - self.add_unevaluated_const(uv); + self.add_const(uv); } ty::PredicateKind::ConstEquate(expected, found) => { self.add_const(expected); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0d7d4054bb3..de5d2683477 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -682,7 +682,7 @@ pub enum PredicateKind<'tcx> { Coerce(CoercePredicate<'tcx>), /// Constant initializer must evaluate successfully. - ConstEvaluatable(ty::UnevaluatedConst<'tcx>), + ConstEvaluatable(ty::Const<'tcx>), /// Constants must be equal. The first component is the const that is expected. ConstEquate(Const<'tcx>, Const<'tcx>), diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 66354196b4e..0b06ccc19ec 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2702,8 +2702,8 @@ pub struct PrintClosureAsImpl<'tcx> { print_value_path(closure_def_id, &[]), write("` implements the trait `{}`", kind)) } - ty::PredicateKind::ConstEvaluatable(uv) => { - p!("the constant `", print_value_path(uv.def.did, uv.substs), "` can be evaluated") + ty::PredicateKind::ConstEvaluatable(ct) => { + p!("the constant `", print(ct), "` can be evaluated") } ty::PredicateKind::ConstEquate(c1, c2) => { p!("the constant `", print(c1), "` equals `", print(c2), "`") diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 1164cf3e01a..d09d3609fb4 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -166,8 +166,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind) } - ty::PredicateKind::ConstEvaluatable(uv) => { - write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs) + ty::PredicateKind::ConstEvaluatable(ct) => { + write!(f, "ConstEvaluatable({ct:?})") } ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), ty::PredicateKind::TypeWellFormedFromEnv(ty) => { diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index c2a83ca9dbb..c9930e8ad0a 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -188,6 +188,14 @@ pub fn expect_const(self) -> ty::Const<'tcx> { _ => bug!("expected a const, but found another kind"), } } + + pub fn is_non_region_infer(self) -> bool { + match self.unpack() { + GenericArgKind::Lifetime(_) => false, + GenericArgKind::Type(ty) => ty.is_ty_infer(), + GenericArgKind::Const(ct) => ct.is_ct_infer(), + } + } } impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> { diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index a3e11bbf056..91db9698c41 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -112,6 +112,22 @@ pub fn walk(self) -> TypeWalker<'tcx> { } } +impl<'tcx> ty::Const<'tcx> { + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```text + /// isize => { isize } + /// Foo> => { Foo>, Bar, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(self) -> TypeWalker<'tcx> { + TypeWalker::new(self.into()) + } +} + /// We push `GenericArg`s on the stack in reverse order so as to /// maintain a pre-order traversal. As of the time of this /// writing, the fact that the traversal is pre-order is not diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index b36b893c78e..81a50481061 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -159,15 +159,7 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow ControlFlow::CONTINUE, - ty::PredicateKind::ConstEvaluatable(uv) - if self.def_id_visitor.tcx().features().generic_const_exprs => - { - let tcx = self.def_id_visitor.tcx(); - if let Ok(Some(ct)) = AbstractConst::new(tcx, uv) { - self.visit_abstract_const_expr(tcx, ct)?; - } - ControlFlow::CONTINUE - } + ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self), ty::PredicateKind::WellFormed(arg) => arg.visit_with(self), _ => bug!("unexpected predicate: {:?}", predicate), } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index b06f24ddf2e..2e5a607a980 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -161,11 +161,20 @@ pub fn try_unify_abstract_consts<'tcx>( #[instrument(skip(infcx), level = "debug")] pub fn is_const_evaluatable<'tcx>( infcx: &InferCtxt<'tcx>, - uv: ty::UnevaluatedConst<'tcx>, + ct: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, span: Span, ) -> Result<(), NotConstEvaluatable> { let tcx = infcx.tcx; + let uv = match ct.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + ty::ConstKind::Param(_) + | ty::ConstKind::Bound(_, _) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Value(_) + | ty::ConstKind::Error(_) => return Ok(()), + ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer), + }; if tcx.features().generic_const_exprs { if let Some(ct) = AbstractConst::new(tcx, uv)? { @@ -285,7 +294,7 @@ fn satisfied_from_param_env<'tcx>( for pred in param_env.caller_bounds() { match pred.kind().skip_binder() { ty::PredicateKind::ConstEvaluatable(uv) => { - if let Some(b_ct) = AbstractConst::new(tcx, uv)? { + if let Some(b_ct) = AbstractConst::from_const(tcx, uv)? { let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env }; // Try to unify with each subtree in the AbstractConst to allow for diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 4e8baa2dfab..382e5f0acc7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1304,7 +1304,10 @@ fn report_selection_error( } match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::ConstEvaluatable(uv) => { + ty::PredicateKind::ConstEvaluatable(ct) => { + let ty::ConstKind::Unevaluated(uv) = ct.kind() else { + bug!("const evaluatable failed for non-unevaluated const `{ct:?}`"); + }; let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); let const_span = self.tcx.def_span(uv.def.did); @@ -2368,7 +2371,7 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { if predicate.references_error() || self.is_tainted_by_errors() { return; } - let subst = data.substs.iter().find(|g| g.has_non_region_infer()); + let subst = data.walk().find(|g| g.is_non_region_infer()); if let Some(subst) = subst { let err = self.emit_inference_failure_err( body_id, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index d4c73427386..a417e1440b9 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -476,9 +476,7 @@ fn process_obligation( Err(NotConstEvaluatable::MentionsInfer) => { pending_obligation.stalled_on.clear(); pending_obligation.stalled_on.extend( - uv.substs - .iter() - .filter_map(TyOrConstInferVar::maybe_from_generic_arg), + uv.walk().filter_map(TyOrConstInferVar::maybe_from_generic_arg), ); ProcessResult::Unchanged } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 635cdde0e8e..0870833cc35 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -148,13 +148,8 @@ pub fn predicate_obligations<'tcx>( wf.compute(a.into()); wf.compute(b.into()); } - ty::PredicateKind::ConstEvaluatable(uv) => { - let obligations = wf.nominal_obligations(uv.def.did, uv.substs); - wf.out.extend(obligations); - - for arg in uv.substs.iter() { - wf.compute(arg); - } + ty::PredicateKind::ConstEvaluatable(ct) => { + wf.compute(ct.into()); } ty::PredicateKind::ConstEquate(c1, c2) => { wf.compute(c1.into()); @@ -476,14 +471,14 @@ fn compute(&mut self, arg: GenericArg<'tcx>) { // obligations are handled by the parent (e.g. `ty::Ref`). GenericArgKind::Lifetime(_) => continue, - GenericArgKind::Const(constant) => { - match constant.kind() { + GenericArgKind::Const(ct) => { + match ct.kind() { ty::ConstKind::Unevaluated(uv) => { let obligations = self.nominal_obligations(uv.def.did, uv.substs); self.out.extend(obligations); let predicate = - ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv)) + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct)) .to_predicate(self.tcx()); let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( @@ -500,7 +495,7 @@ fn compute(&mut self, arg: GenericArg<'tcx>) { cause, self.recursion_depth, self.param_env, - ty::Binder::dummy(ty::PredicateKind::WellFormed(constant.into())) + ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into())) .to_predicate(self.tcx()), )); }