Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> 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,
Expand Down
26 changes: 26 additions & 0 deletions compiler/rustc_middle/src/ty/context/impl_interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {

type RegionAssumptions = &'tcx ty::List<ty::ArgOutlivesClause<'tcx>>;

type TypingEnv = ty::TypingEnv<'tcx>;

type ParamEnv = ty::ParamEnv<'tcx>;
type Predicate = Predicate<'tcx>;

Expand Down Expand Up @@ -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<T: TypeFoldable<Self>>(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<Result<Self::ValTree, Self::Ty>, Option<Self::ErrorGuaranteed>> {

@BoxyUwU BoxyUwU Sep 8, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@khyperia's right that this is a scary return type :3 I think we would ideally make this a bespoke enum and maybe even change the original const_eval_resolve_for_typeck query to return it 🤔

I think that can be a future PR tho

View changes since the review

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<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T {
self.expand_abstract_consts(t)
}
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,16 @@ pub struct TypingEnv<'tcx> {
pub param_env: ParamEnv<'tcx>,
}

impl<'tcx> rustc_type_ir::inherent::TypingEnv<TyCtxt<'tcx>> 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 }
Expand Down
106 changes: 103 additions & 3 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_type_ir/src/inherent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ pub trait Const<I: Interner<Const = Self>>:

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<I>) -> Self;

fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
Expand Down Expand Up @@ -621,6 +623,15 @@ pub trait ParamEnv<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
fn caller_bounds(self) -> impl Iterator<Item = I::Clause>;
}

#[rust_analyzer::prefer_underscore_import]
pub trait TypingEnv<I: Interner>:
Copy + Clone + Debug + PartialEq + Eq + Hash + TypeFoldable<I> + TypeVisitable<I>
{
fn fully_monomorphized() -> Self;

fn post_analysis(cx: I, def_id: I::DefId) -> Self;
}

#[rust_analyzer::prefer_underscore_import]
pub trait Features<I: Interner>: Copy {
fn generic_const_exprs(self) -> bool;
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_type_ir/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ pub trait Interner:
+ SliceLike<Item = ty::OutlivesClause<Self, Self::GenericArg>>
+ TypeFoldable<Self>;

type TypingEnv: TypingEnv<Self>;

// Predicates
type ParamEnv: ParamEnv<Self>;
type Predicate: Predicate<Self>;
Expand Down Expand Up @@ -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<T: TypeFoldable<Self>>(self, value: T) -> T;

fn const_eval_resolve_for_typeck(
self,
typing_env: Self::TypingEnv,
ct: ty::AliasConst<Self>,
span: Self::Span,
) -> Result<Result<Self::ValTree, Self::Ty>, Option<Self::ErrorGuaranteed>>;

fn coroutine_hidden_types(
self,
def_id: Self::CoroutineId,
Expand Down
Loading