Skip to content
Draft
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
37 changes: 37 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,41 @@ 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: rustc_type_ir::AliasConst<Self>,
span: Self::Span,
) -> rustc_type_ir::ConstToValTreeResult<Self> {
// still not happy with this
match self.const_eval_resolve_for_typeck(typing_env, ct, span) {
Ok(Ok(vt)) => Ok(Ok(vt)),
Ok(Err(ty)) => Ok(Err(ty)),

Err(ty::context::interpret::ErrorHandled::Reported(info, span)) => {
Err(rustc_type_ir::ErrorHandled::Reported(
rustc_type_ir::ReportedErrorInfo {
error: info.into(),
allowed_in_infallible: info.is_allowed_in_infallible(),
},
span,
))
}

Err(ty::context::interpret::ErrorHandled::TooGeneric(span)) => {
Err(rustc_type_ir::ErrorHandled::TooGeneric(span))
}
}
}

fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T {
self.expand_abstract_consts(t)
}
Expand Down
22 changes: 22 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,10 @@ impl<'tcx> rustc_type_ir::inherent::ParamEnv<TyCtxt<'tcx>> for ParamEnv<'tcx> {
fn caller_bounds(self) -> impl Iterator<Item = ty::Clause<'tcx>> {
self.caller_bounds()
}

fn empty() -> Self {
Self::empty()
}
}

impl<'tcx> ParamEnv<'tcx> {
Expand Down Expand Up @@ -1240,6 +1244,24 @@ pub struct TypingEnv<'tcx> {
pub param_env: ParamEnv<'tcx>,
}

impl<'tcx> rustc_type_ir::inherent::TypingEnv<TyCtxt<'tcx>> for TypingEnv<'tcx> {
fn typing_mode(&self) -> TypingMode<'tcx> {
Self::typing_mode(&self)
}

fn new(param_env: ParamEnv<'tcx>, typing_mode: TypingMode<'tcx>) -> Self {
Self::new(param_env, typing_mode)
}

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
111 changes: 108 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,114 @@ 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();
let alias_const = self.resolve_vars_if_possible(alias_const);
let mut normalize_ty = |ty| self.normalize(GoalSource::Misc, param_env, ty);

let opt_anon_const_kind = match alias_const.kind {
ty::AliasConstKind::Anon { def_id } => {
Some((def_id, cx.anon_const_kind(def_id.into())))
}
_ => None,
};

// 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.
let (args, typing_env) = match opt_anon_const_kind {
// We handle `generic_const_exprs` separately as reasonable ways of handling constants in the type system
// completely fall apart under `generic_const_exprs` and makes this whole function Really hard to reason
// about if you have to consider gce whatsoever.
Some((_def_id, ty::AnonConstKind::GCE)) => {
return Ok(self.delegate.evaluate_const(param_env, alias_const, |ty| {
self.normalize(GoalSource::Misc, param_env, ty)
})?);
}

Some((def_id, 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.

// not sure about this
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)
}
Some((
_,
ty::AnonConstKind::MCG
| ty::AnonConstKind::NonTypeSystemAnon
| ty::AnonConstKind::NonTypeSystemInline,
))
| None => {
// 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);

use ty::ErrorHandled;

match cx.const_eval_resolve_for_typeck(typing_env, erased_alias_const, span) {
Ok(Ok(val)) => {
let Ok(ty) = normalize_ty(alias_const.type_of(cx)) else {
return Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution));
};
Ok(Some(I::Const::new_value(cx, val, ty)))
}
Ok(Err(_)) => Ok(None),

Err(ErrorHandled::Reported(r, _)) => Ok(Some(I::Const::new_error(cx, r.error))),
Err(ErrorHandled::TooGeneric(_)) => Ok(None),
}
}

pub(super) fn evaluate_const_and_instantiate_projection_term(
Expand Down
20 changes: 20 additions & 0 deletions compiler/rustc_type_ir/src/const_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,26 @@ impl StableHash for InferConst {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ReportedErrorInfo<I: Interner> {
pub error: I::ErrorGuaranteed,
/// Whether this error is allowed to show up even in otherwise "infallible" promoteds.
/// This is for things like overflows during size computation or resource exhaustion.
pub allowed_in_infallible: bool,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ErrorHandled<I: Interner> {
/// Already reported an error for this evaluation, and the compilation is
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
Reported(ReportedErrorInfo<I>, I::Span),
/// Don't emit an error, the evaluation failed because the MIR was generic
/// and the args didn't fully monomorphize it.
TooGeneric(I::Span),
}
pub type ConstToValTreeResult<I> =
Result<Result<<I as Interner>::ValTree, <I as Interner>::Ty>, ErrorHandled<I>>;

/// This datastructure is used to represent the value of constants used in the type system.
///
/// We explicitly choose a different datastructure from the way values are processed within
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_type_ir/src/infer_ctxt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ use derive_where::derive_where;
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, StableHash_NoContext};

use crate::data_structures::DelayedMap;
// use rustc_data_structures::stable_hash::StableHash;
use crate::inherent::*;
use crate::relate::RelateResult;
use crate::relate::combine::PredicateEmittingRelation;
use crate::solve::{TyOrConstInferVar, VisibleForLeakCheck};
use crate::{
self as ty, Interner, Region, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitableExt,
/* TypeVisitable */ TypeVisitableExt,
};

mod private {
Expand Down
26 changes: 25 additions & 1 deletion compiler/rustc_type_ir/src/inherent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use crate::relate::Relate;
use crate::solve::{AdtDestructorKind, SizedTraitKind};
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::{
self as ty, ClauseKind, CollectAndApply, FieldInfo, Interner, PredicateKind, Region, UpcastFrom,
self as ty, ClauseKind, CollectAndApply, FieldInfo, Interner, PredicateKind, Region,
TypingMode, UpcastFrom,
};

#[rust_analyzer::prefer_underscore_import]
Expand Down Expand Up @@ -245,6 +246,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) -> I::Const;

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 @@ -619,6 +622,27 @@ pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
#[rust_analyzer::prefer_underscore_import]
pub trait ParamEnv<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
fn caller_bounds(self) -> impl Iterator<Item = I::Clause>;

/// Construct a trait environment suitable for contexts where there are
/// no where-clauses in scope. In the majority of cases it is incorrect
/// to use an empty environment. See the [dev guide section][param_env_guide]
/// for information on what a `ParamEnv` is and how to acquire one.
///
/// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/typing_parameter_envs.html
fn empty() -> Self;
}

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

fn new(param_env: I::ParamEnv, typing_mode: TypingMode<I>) -> Self;

fn fully_monomorphized() -> Self;

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

#[rust_analyzer::prefer_underscore_import]
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 @@ -280,6 +282,17 @@ pub trait Interner:
// FIXME: remove in favor of explicit construction
fn alias_term_kind_from_def_id(self, def_id: Self::DefId) -> ty::AliasTermKind<Self>;

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,
) -> ty::ConstToValTreeResult<Self>;

fn trait_ref_and_own_args_for_alias(
self,
def_id: Self::TraitAssocTermId,
Expand Down
Loading