diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index d2f761a1c5d7f..a55dfb3562022 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -174,6 +174,10 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { Const::new_var(tcx, vid) } + fn new_value(tcx: TyCtxt<'tcx>, valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Self { + Const::new_value(tcx, valtree, ty) + } + fn new_bound( interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 048e509ec88e0..b2d1044dba0b6 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -122,6 +122,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type RegionAssumptions = &'tcx ty::List>; + type TypingEnv = ty::TypingEnv<'tcx>; + type ParamEnv = ty::ParamEnv<'tcx>; type Predicate = Predicate<'tcx>; @@ -156,6 +158,30 @@ impl<'tcx> Interner for TyCtxt<'tcx> { // See trait-system-refactor-initiative#234. } + fn param_env_normalized_for_post_analysis(self, defid: Self::DefId) -> Self::ParamEnv { + self.param_env_normalized_for_post_analysis(defid) + } + + fn erase_and_anonymize_regions>(self, value: T) -> T { + self.erase_and_anonymize_regions(value) + } + + fn const_eval_resolve_for_typeck( + self, + typing_env: Self::TypingEnv, + ct: ty::AliasConst<'tcx>, + span: Self::Span, + ) -> Result, Option> { + match self.const_eval_resolve_for_typeck(typing_env, ct, span) { + Ok(Ok(vt)) => Ok(Ok(vt)), + Ok(Err(ty)) => Ok(Err(ty)), + Err(e) => match e { + rustc_middle::mir::interpret::ErrorHandled::Reported(e, _) => Err(Some(e.into())), + rustc_middle::mir::interpret::ErrorHandled::TooGeneric(_) => Err(None), + }, + } + } + fn expand_abstract_consts>>(self, t: T) -> T { self.expand_abstract_consts(t) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ddaa01640b64b..56915bf25a16d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1240,6 +1240,16 @@ pub struct TypingEnv<'tcx> { pub param_env: ParamEnv<'tcx>, } +impl<'tcx> rustc_type_ir::inherent::TypingEnv> for TypingEnv<'tcx> { + fn fully_monomorphized() -> Self { + Self::fully_monomorphized() + } + + fn post_analysis(tcx: TyCtxt<'tcx>, def_id: DefId) -> TypingEnv<'tcx> { + Self::post_analysis(tcx, def_id) + } +} + impl<'tcx> TypingEnv<'tcx> { pub fn new(param_env: ParamEnv<'tcx>, typing_mode: TypingMode<'tcx>) -> Self { Self { typing_mode: TypingModeEqWrapper(typing_mode), param_env } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index a0abc918107df..2c4f06129200e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1412,9 +1412,109 @@ where match self.opaque_accesses.rerun_always(RerunReason::EvaluateConst)? {} } - self.delegate.evaluate_const(param_env, alias_const, |ty| { - self.normalize(GoalSource::Misc, param_env, ty) - }) + let cx = self.cx(); + + // Delegate evaluation if GCE is used. + if cx.features().generic_const_exprs() { + return Ok(self.delegate.evaluate_const(param_env, alias_const, |ty| { + self.normalize(GoalSource::Misc, param_env, ty) + })?); + } + + let alias_const = self.resolve_vars_if_possible(alias_const); + + // Postpone evaluation of constants that depend on generic parameters or + // inference variables. + // + // We use `TypingMode::PostAnalysis` here which is not *technically* correct + // to be revealing opaque types here as borrowcheck has not run yet. However, + // CTFE itself uses `TypingMode::PostAnalysis` unconditionally even during + // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). + // As a result we always use a revealed env when resolving the instance to evaluate. + // + // FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself + // instead of having this logic here + let (args, typing_env) = match alias_const.kind { + // Generic params are allowed in `AnonConstKind::RepeatExprCount` for backcompat + // reasons as long as evaluation doesn't rely on them to succeed. + ty::AliasConstKind::Anon { def_id } + if matches!( + cx.anon_const_kind(def_id.into()), + ty::AnonConstKind::RepeatExprCount + ) => + { + if alias_const.has_non_region_infer() { + // Diagnostics will sometimes replace the identity args of anon consts in + // array repeat expr counts with inference variables so we have to handle this + // even though it is not something we should ever actually encounter. + // + // Array repeat expr counts are allowed to syntactically use generic parameters + // but must not actually depend on them in order to evalaute successfully. This means + // that it is actually fine to evalaute them in their own environment rather than with + // the actually provided generic arguments. + cx.delay_bug("AnonConst with infer args but no error reported"); + } + + // The generic args of repeat expr counts under `min_const_generics` are not supposed to + // affect evaluation of the constant as this would make it a "truly" generic const arg. + // To prevent this we discard all the generic arguments and evalaute with identity args + // and in its own environment instead of the current environment we are normalizing in. + let args = GenericArgs::identity_for_item(cx, def_id.into()); + let typing_env = TypingEnv::post_analysis(cx, def_id.into()); + + (args, typing_env) + } + _ => { + // We are only dealing with "truly" generic/uninferred constants here: + // - GCEConsts have been handled separately + // - Repeat expr count back compat consts have also been handled separately + // So we are free to simply defer evaluation here. + // + // FIXME: This assumes that `args` are normalized which is not necessarily true + // + // Const patterns are converted to type system constants before being + // evaluated. However, we don't care about them here as pattern evaluation + // logic does not go through type system normalization. If it did this would + // be a backwards compatibility problem as we do not enforce "syntactic" non- + // usage of generic parameters like we do here. + if alias_const.args.has_non_region_param() + || alias_const.args.has_non_region_infer() + || alias_const.args.has_non_region_placeholders() + { + return Ok(None); + } + + // Since there is no generic parameter, we can just drop the environment + // to prevent query cycle. + let typing_env = TypingEnv::fully_monomorphized(); + + (alias_const.args, typing_env) + } + }; + + let alias_const = ty::AliasConst::new(cx, alias_const.kind, args); + let erased_alias_const = cx.erase_and_anonymize_regions(alias_const); + + // FIXME: `def_span` will point at the definition of this const; ideally, we'd point at + // where it gets used as a const generic. + let span = alias_const.kind.def_span(cx); + + match cx.const_eval_resolve_for_typeck(typing_env, erased_alias_const, span) { + Ok(Ok(val)) => { + let ty = self.normalize(GoalSource::Misc, param_env, alias_const.type_of(cx))?; + Ok(Some(I::Const::new_value(cx, val, ty))) + } + + Err(Some(e)) => Ok(Some(I::Const::new_error(cx, e))), + + Ok(Err(_)) => { + cx.delay_bug("Type system constant with non valtree'able type evaluated but no error emitted"); + Ok(None) + } + + // TooGeneric or otherwise somehow failed CTFE. + Err(None) => Ok(None), + } } pub(super) fn evaluate_const_and_instantiate_projection_term( diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index b08cf4c5876a9..1be0b443500e9 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -245,6 +245,8 @@ pub trait Const>: fn new_var(interner: I, var: ty::ConstVid) -> Self; + fn new_value(interner: I, valtree: I::ValTree, ty: I::Ty) -> Self; + fn new_bound(interner: I, debruijn: ty::DebruijnIndex, bound_const: ty::BoundConst) -> Self; fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; @@ -621,6 +623,15 @@ pub trait ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable { fn caller_bounds(self) -> impl Iterator; } +#[rust_analyzer::prefer_underscore_import] +pub trait TypingEnv: + Copy + Clone + Debug + PartialEq + Eq + Hash + TypeFoldable + TypeVisitable +{ + fn fully_monomorphized() -> Self; + + fn post_analysis(cx: I, def_id: I::DefId) -> Self; +} + #[rust_analyzer::prefer_underscore_import] pub trait Features: Copy { fn generic_const_exprs(self) -> bool; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index d230791304527..1d67c6589ac43 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -231,6 +231,8 @@ pub trait Interner: + SliceLike> + TypeFoldable; + type TypingEnv: TypingEnv; + // Predicates type ParamEnv: ParamEnv; type Predicate: Predicate; @@ -322,6 +324,17 @@ pub trait Interner: fn renormalize_rigid_aliases(self) -> bool; + fn param_env_normalized_for_post_analysis(self, defid: Self::DefId) -> Self::ParamEnv; + + fn erase_and_anonymize_regions>(self, value: T) -> T; + + fn const_eval_resolve_for_typeck( + self, + typing_env: Self::TypingEnv, + ct: ty::AliasConst, + span: Self::Span, + ) -> Result, Option>; + fn coroutine_hidden_types( self, def_id: Self::CoroutineId,