Set groundwork for proper const normalization
This commit is contained in:
parent
53e3907bcb
commit
238d113b07
18 changed files with 366 additions and 225 deletions
|
|
@ -1,7 +1,8 @@
|
|||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty;
|
||||
|
||||
use super::InferCtxt;
|
||||
use crate::infer::Term;
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
|
|
@ -11,24 +12,32 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
/// of the given projection. This allows us to proceed with projections
|
||||
/// while they cannot be resolved yet due to missing information or
|
||||
/// simply due to the lack of access to the trait resolution machinery.
|
||||
pub fn projection_ty_to_infer(
|
||||
pub fn projection_term_to_infer(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
projection_ty: ty::AliasTy<'tcx>,
|
||||
alias_term: ty::AliasTerm<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
recursion_depth: usize,
|
||||
obligations: &mut PredicateObligations<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
) -> Term<'tcx> {
|
||||
debug_assert!(!self.next_trait_solver());
|
||||
let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id));
|
||||
|
||||
let span = self.tcx.def_span(alias_term.def_id);
|
||||
let infer_var = if alias_term.kind(self.tcx).is_type() {
|
||||
self.next_ty_var(span).into()
|
||||
} else {
|
||||
self.next_const_var(span).into()
|
||||
};
|
||||
|
||||
let projection =
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
|
||||
projection_term: projection_ty.into(),
|
||||
term: ty_var.into(),
|
||||
projection_term: alias_term,
|
||||
term: infer_var,
|
||||
}));
|
||||
let obligation =
|
||||
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
|
||||
obligations.push(obligation);
|
||||
ty_var
|
||||
|
||||
infer_var
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -243,10 +243,18 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
ty::AliasTermKind::ProjectionTy
|
||||
}
|
||||
}
|
||||
DefKind::AssocConst => {
|
||||
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
|
||||
{
|
||||
ty::AliasTermKind::InherentConst
|
||||
} else {
|
||||
ty::AliasTermKind::ProjectionConst
|
||||
}
|
||||
}
|
||||
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
|
||||
DefKind::TyAlias => ty::AliasTermKind::FreeTy,
|
||||
DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
|
||||
DefKind::AnonConst | DefKind::Const | DefKind::Ctor(_, CtorKind::Const) => {
|
||||
DefKind::Const => ty::AliasTermKind::FreeConst,
|
||||
DefKind::AnonConst | DefKind::Ctor(_, CtorKind::Const) => {
|
||||
ty::AliasTermKind::UnevaluatedConst
|
||||
}
|
||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||
|
|
|
|||
|
|
@ -3195,7 +3195,7 @@ define_print! {
|
|||
|
||||
ty::AliasTerm<'tcx> {
|
||||
match self.kind(cx.tcx()) {
|
||||
ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)),
|
||||
ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => p!(pretty_print_inherent_projection(*self)),
|
||||
ty::AliasTermKind::ProjectionTy => {
|
||||
if !(cx.should_print_verbose() || with_reduced_queries())
|
||||
&& cx.tcx().is_impl_trait_in_trait(self.def_id)
|
||||
|
|
@ -3205,7 +3205,8 @@ define_print! {
|
|||
p!(print_def_path(self.def_id, self.args));
|
||||
}
|
||||
}
|
||||
| ty::AliasTermKind::FreeTy
|
||||
ty::AliasTermKind::FreeTy
|
||||
| ty::AliasTermKind::FreeConst
|
||||
| ty::AliasTermKind::OpaqueTy
|
||||
| ty::AliasTermKind::UnevaluatedConst
|
||||
| ty::AliasTermKind::ProjectionConst => {
|
||||
|
|
|
|||
|
|
@ -966,7 +966,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)),
|
||||
ty::AliasTermKind::InherentTy
|
||||
| ty::AliasTermKind::InherentConst
|
||||
| ty::AliasTermKind::FreeTy
|
||||
| ty::AliasTermKind::FreeConst
|
||||
| ty::AliasTermKind::UnevaluatedConst
|
||||
| ty::AliasTermKind::ProjectionConst => None,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -568,6 +568,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
|
||||
// Lower the named constant to a THIR pattern.
|
||||
let args = self.typeck_results.node_args(id);
|
||||
// FIXME(mgca): we will need to special case IACs here to have type system compatible
|
||||
// generic args, instead of how we represent them in body expressions.
|
||||
let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
|
||||
let mut pattern = self.const_to_pat(c, ty, id, span);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,19 +19,25 @@ where
|
|||
goal: Goal<I, ty::NormalizesTo<I>>,
|
||||
) -> QueryResult<I> {
|
||||
let cx = self.cx();
|
||||
let free_ty = goal.predicate.alias;
|
||||
let free_alias = goal.predicate.alias;
|
||||
|
||||
// Check where clauses
|
||||
self.add_goals(
|
||||
GoalSource::Misc,
|
||||
cx.predicates_of(free_ty.def_id)
|
||||
.iter_instantiated(cx, free_ty.args)
|
||||
cx.predicates_of(free_alias.def_id)
|
||||
.iter_instantiated(cx, free_alias.args)
|
||||
.map(|pred| goal.with(cx, pred)),
|
||||
);
|
||||
|
||||
let actual = cx.type_of(free_ty.def_id).instantiate(cx, free_ty.args);
|
||||
self.instantiate_normalizes_to_term(goal, actual.into());
|
||||
let actual = if free_alias.kind(cx).is_type() {
|
||||
cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args)
|
||||
} else {
|
||||
// FIXME(mgca): once const items are actual aliases defined as equal to type system consts
|
||||
// this should instead return that.
|
||||
panic!("normalizing free const aliases in the type system is unsupported");
|
||||
};
|
||||
|
||||
self.instantiate_normalizes_to_term(goal, actual.into());
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@ where
|
|||
D: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
pub(super) fn normalize_inherent_associated_type(
|
||||
pub(super) fn normalize_inherent_associated_term(
|
||||
&mut self,
|
||||
goal: Goal<I, ty::NormalizesTo<I>>,
|
||||
) -> QueryResult<I> {
|
||||
let cx = self.cx();
|
||||
let inherent = goal.predicate.alias.expect_ty(cx);
|
||||
let inherent = goal.predicate.alias;
|
||||
|
||||
let impl_def_id = cx.parent(inherent.def_id);
|
||||
let impl_args = self.fresh_args_for_item(impl_def_id);
|
||||
|
|
@ -48,8 +48,13 @@ where
|
|||
.map(|pred| goal.with(cx, pred)),
|
||||
);
|
||||
|
||||
let normalized = cx.type_of(inherent.def_id).instantiate(cx, inherent_args);
|
||||
self.instantiate_normalizes_to_term(goal, normalized.into());
|
||||
let normalized = if inherent.kind(cx).is_type() {
|
||||
cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into()
|
||||
} else {
|
||||
// FIXME(mgca): Properly handle IACs in the type system
|
||||
panic!("normalizing inherent associated consts in the type system is unsupported");
|
||||
};
|
||||
self.instantiate_normalizes_to_term(goal, normalized);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,9 +48,13 @@ where
|
|||
})
|
||||
})
|
||||
}
|
||||
ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal),
|
||||
ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => {
|
||||
self.normalize_inherent_associated_term(goal)
|
||||
}
|
||||
ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal),
|
||||
ty::AliasTermKind::FreeTy => self.normalize_free_alias(goal),
|
||||
ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => {
|
||||
self.normalize_free_alias(goal)
|
||||
}
|
||||
ty::AliasTermKind::UnevaluatedConst => self.normalize_anon_const(goal),
|
||||
}
|
||||
}
|
||||
|
|
@ -333,6 +337,8 @@ where
|
|||
cx.type_of(target_item_def_id).map_bound(|ty| ty.into())
|
||||
}
|
||||
ty::AliasTermKind::ProjectionConst => {
|
||||
// FIXME(mgca): once const items are actual aliases defined as equal to type system consts
|
||||
// this should instead return that.
|
||||
if cx.features().associated_const_equality() {
|
||||
panic!("associated const projection is not supported yet")
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ pub use self::dyn_compatibility::{
|
|||
pub use self::engine::{ObligationCtxt, TraitEngineExt};
|
||||
pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation};
|
||||
pub use self::normalize::NormalizeExt;
|
||||
pub use self::project::{normalize_inherent_projection, normalize_projection_ty};
|
||||
pub use self::project::{normalize_inherent_projection, normalize_projection_term};
|
||||
pub use self::select::{
|
||||
EvaluationCache, EvaluationResult, IntercrateAmbiguityCause, OverflowError, SelectionCache,
|
||||
SelectionContext,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! Deeply normalize types using the old trait solver.
|
||||
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_infer::infer::at::At;
|
||||
use rustc_infer::infer::{InferCtxt, InferOk};
|
||||
use rustc_infer::traits::{
|
||||
|
|
@ -10,15 +11,12 @@ use rustc_macros::extension;
|
|||
use rustc_middle::span_bug;
|
||||
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::ty::{
|
||||
self, AliasTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
|
||||
self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
|
||||
TypeVisitableExt, TypingMode,
|
||||
};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::{
|
||||
BoundVarReplacer, PlaceholderReplacer, SelectionContext, project,
|
||||
with_replaced_escaping_bound_vars,
|
||||
};
|
||||
use super::{BoundVarReplacer, PlaceholderReplacer, SelectionContext, project};
|
||||
use crate::error_reporting::InferCtxtErrorExt;
|
||||
use crate::error_reporting::traits::OverflowCause;
|
||||
use crate::solve::NextSolverError;
|
||||
|
|
@ -179,8 +177,10 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) }
|
||||
}
|
||||
|
||||
fn normalize_trait_projection(&mut self, data: AliasTy<'tcx>) -> Ty<'tcx> {
|
||||
if !data.has_escaping_bound_vars() {
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn normalize_trait_projection(&mut self, proj: AliasTerm<'tcx>) -> Term<'tcx> {
|
||||
if !proj.has_escaping_bound_vars() {
|
||||
// When we don't have escaping bound vars we can normalize ambig aliases
|
||||
// to inference variables (done in `normalize_projection_ty`). This would
|
||||
// be wrong if there were escaping bound vars as even if we instantiated
|
||||
|
|
@ -189,23 +189,15 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
//
|
||||
// Also, as an optimization: when we don't have escaping bound vars, we don't
|
||||
// need to replace them with placeholders (see branch below).
|
||||
let data = data.fold_with(self);
|
||||
let normalized_ty = project::normalize_projection_ty(
|
||||
let proj = proj.fold_with(self);
|
||||
project::normalize_projection_term(
|
||||
self.selcx,
|
||||
self.param_env,
|
||||
data,
|
||||
proj,
|
||||
self.cause.clone(),
|
||||
self.depth,
|
||||
self.obligations,
|
||||
);
|
||||
debug!(
|
||||
?self.depth,
|
||||
?ty,
|
||||
?normalized_ty,
|
||||
obligations.len = ?self.obligations.len(),
|
||||
"AssocTypeNormalizer: normalized type"
|
||||
);
|
||||
normalized_ty.expect_type()
|
||||
)
|
||||
} else {
|
||||
// If there are escaping bound vars, we temporarily replace the
|
||||
// bound vars with placeholders. Note though, that in the case
|
||||
|
|
@ -218,72 +210,64 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
// Note: this isn't necessarily the final approach here; we may
|
||||
// want to figure out how to register obligations with escaping vars
|
||||
// or handle this some other way.
|
||||
|
||||
let infcx = self.selcx.infcx;
|
||||
let (data, mapped_regions, mapped_types, mapped_consts) =
|
||||
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
|
||||
let data = data.fold_with(self);
|
||||
let normalized_ty = project::opt_normalize_projection_term(
|
||||
let (proj, mapped_regions, mapped_types, mapped_consts) =
|
||||
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, proj);
|
||||
let proj = proj.fold_with(self);
|
||||
let normalized_term = project::opt_normalize_projection_term(
|
||||
self.selcx,
|
||||
self.param_env,
|
||||
data.into(),
|
||||
proj,
|
||||
self.cause.clone(),
|
||||
self.depth,
|
||||
self.obligations,
|
||||
)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|term| term.expect_type())
|
||||
.map(|normalized_ty| {
|
||||
PlaceholderReplacer::replace_placeholders(
|
||||
infcx,
|
||||
mapped_regions,
|
||||
mapped_types,
|
||||
mapped_consts,
|
||||
&self.universes,
|
||||
normalized_ty,
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|| ty.super_fold_with(self));
|
||||
.unwrap_or(proj.to_term(infcx.tcx));
|
||||
|
||||
debug!(
|
||||
?self.depth,
|
||||
?ty,
|
||||
?normalized_ty,
|
||||
obligations.len = ?self.obligations.len(),
|
||||
"AssocTypeNormalizer: normalized type"
|
||||
);
|
||||
normalized_ty
|
||||
PlaceholderReplacer::replace_placeholders(
|
||||
infcx,
|
||||
mapped_regions,
|
||||
mapped_types,
|
||||
mapped_consts,
|
||||
&self.universes,
|
||||
normalized_term,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_inherent_projection(&mut self, data: AliasTy<'tcx>) -> Ty<'tcx> {
|
||||
if !data.has_escaping_bound_vars() {
|
||||
// This branch is *mostly* just an optimization: when we don't
|
||||
// have escaping bound vars, we don't need to replace them with
|
||||
// placeholders (see branch below). *Also*, we know that we can
|
||||
// register an obligation to *later* project, since we know
|
||||
// there won't be bound vars there.
|
||||
|
||||
let data = data.fold_with(self);
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn normalize_inherent_projection(&mut self, inherent: AliasTerm<'tcx>) -> Term<'tcx> {
|
||||
if !inherent.has_escaping_bound_vars() {
|
||||
// When we don't have escaping bound vars we can normalize ambig aliases
|
||||
// to inference variables (done in `normalize_projection_ty`). This would
|
||||
// be wrong if there were escaping bound vars as even if we instantiated
|
||||
// the bound vars with placeholders, we wouldn't be able to map them back
|
||||
// after normalization succeeded.
|
||||
//
|
||||
// Also, as an optimization: when we don't have escaping bound vars, we don't
|
||||
// need to replace them with placeholders (see branch below).
|
||||
|
||||
let inherent = inherent.fold_with(self);
|
||||
project::normalize_inherent_projection(
|
||||
self.selcx,
|
||||
self.param_env,
|
||||
data,
|
||||
inherent,
|
||||
self.cause.clone(),
|
||||
self.depth,
|
||||
self.obligations,
|
||||
)
|
||||
} else {
|
||||
let infcx = self.selcx.infcx;
|
||||
let (data, mapped_regions, mapped_types, mapped_consts) =
|
||||
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
|
||||
let data = data.fold_with(self);
|
||||
let ty = project::normalize_inherent_projection(
|
||||
let (inherent, mapped_regions, mapped_types, mapped_consts) =
|
||||
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, inherent);
|
||||
let inherent = inherent.fold_with(self);
|
||||
let inherent = project::normalize_inherent_projection(
|
||||
self.selcx,
|
||||
self.param_env,
|
||||
data,
|
||||
inherent,
|
||||
self.cause.clone(),
|
||||
self.depth,
|
||||
self.obligations,
|
||||
|
|
@ -295,16 +279,18 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
mapped_types,
|
||||
mapped_consts,
|
||||
&self.universes,
|
||||
ty,
|
||||
inherent,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_free_alias(&mut self, data: AliasTy<'tcx>) -> Ty<'tcx> {
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> {
|
||||
let recursion_limit = self.cx().recursion_limit();
|
||||
if !recursion_limit.value_within_limit(self.depth) {
|
||||
self.selcx.infcx.err_ctxt().report_overflow_error(
|
||||
OverflowCause::DeeplyNormalize(data.into()),
|
||||
OverflowCause::DeeplyNormalize(free.into()),
|
||||
self.cause.span,
|
||||
false,
|
||||
|diag| {
|
||||
|
|
@ -315,9 +301,13 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
|
||||
let infcx = self.selcx.infcx;
|
||||
self.obligations.extend(
|
||||
infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map(
|
||||
// FIXME(BoxyUwU):
|
||||
// FIXME(lazy_type_alias):
|
||||
// It seems suspicious to instantiate the predicates with arguments that might be bound vars,
|
||||
// we might wind up instantiating one of these bound vars underneath a hrtb.
|
||||
infcx.tcx.predicates_of(free.def_id).instantiate_own(infcx.tcx, free.args).map(
|
||||
|(mut predicate, span)| {
|
||||
if data.has_escaping_bound_vars() {
|
||||
if free.has_escaping_bound_vars() {
|
||||
(predicate, ..) = BoundVarReplacer::replace_bound_vars(
|
||||
infcx,
|
||||
&mut self.universes,
|
||||
|
|
@ -325,13 +315,21 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
);
|
||||
}
|
||||
let mut cause = self.cause.clone();
|
||||
cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, data.def_id));
|
||||
cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, free.def_id));
|
||||
Obligation::new(infcx.tcx, cause, self.param_env, predicate)
|
||||
},
|
||||
),
|
||||
);
|
||||
self.depth += 1;
|
||||
let res = infcx.tcx.type_of(data.def_id).instantiate(infcx.tcx, data.args).fold_with(self);
|
||||
let res = if free.kind(infcx.tcx).is_type() {
|
||||
infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into()
|
||||
} else {
|
||||
// FIXME(mgca): once const items are actual aliases defined as equal to type system consts
|
||||
// this should instead use that rather than evaluating.
|
||||
super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env)
|
||||
.super_fold_with(self)
|
||||
.into()
|
||||
};
|
||||
self.depth -= 1;
|
||||
res
|
||||
}
|
||||
|
|
@ -415,28 +413,64 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::Projection => self.normalize_trait_projection(data),
|
||||
ty::Free => self.normalize_free_alias(data),
|
||||
ty::Inherent => self.normalize_inherent_projection(data),
|
||||
|
||||
ty::Projection => self.normalize_trait_projection(data.into()).expect_type(),
|
||||
ty::Inherent => self.normalize_inherent_projection(data.into()).expect_type(),
|
||||
ty::Free => self.normalize_free_alias(data.into()).expect_type(),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
let tcx = self.selcx.tcx();
|
||||
if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &constant)
|
||||
{
|
||||
constant
|
||||
if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &ct) {
|
||||
return ct;
|
||||
}
|
||||
|
||||
// Doing "proper" normalization of const aliases is inherently cyclic until const items
|
||||
// are real aliases instead of having bodies. We gate proper const alias handling behind
|
||||
// mgca to avoid breaking stable code, though this should become the "main" codepath long
|
||||
// before mgca is stabilized.
|
||||
//
|
||||
// FIXME(BoxyUwU): Enabling this by default is blocked on a refactoring to how const items
|
||||
// are represented.
|
||||
if tcx.features().min_generic_const_args() {
|
||||
let uv = match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => uv,
|
||||
_ => return ct.super_fold_with(self),
|
||||
};
|
||||
|
||||
let ct = match tcx.def_kind(uv.def) {
|
||||
DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) {
|
||||
DefKind::Trait => self.normalize_trait_projection(uv.into()),
|
||||
DefKind::Impl { of_trait: false } => {
|
||||
self.normalize_inherent_projection(uv.into())
|
||||
}
|
||||
kind => unreachable!(
|
||||
"unexpected `DefKind` for const alias' resolution's parent def: {:?}",
|
||||
kind
|
||||
),
|
||||
},
|
||||
DefKind::Const | DefKind::AnonConst => self.normalize_free_alias(uv.into()),
|
||||
kind => {
|
||||
unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind)
|
||||
}
|
||||
};
|
||||
|
||||
// We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
|
||||
// unnormalized after const evaluation returns.
|
||||
ct.expect_const().super_fold_with(self)
|
||||
} else {
|
||||
let constant = constant.super_fold_with(self);
|
||||
debug!(?constant, ?self.param_env);
|
||||
with_replaced_escaping_bound_vars(
|
||||
let ct = ct.super_fold_with(self);
|
||||
return super::with_replaced_escaping_bound_vars(
|
||||
self.selcx.infcx,
|
||||
&mut self.universes,
|
||||
constant,
|
||||
|constant| super::evaluate_const(self.selcx.infcx, constant, self.param_env),
|
||||
ct,
|
||||
|ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env),
|
||||
)
|
||||
.super_fold_with(self)
|
||||
.super_fold_with(self);
|
||||
// We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
|
||||
// unnormalized after const evaluation returns.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use std::ops::ControlFlow;
|
|||
use rustc_data_structures::sso::SsoHashSet;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
|
|
@ -172,6 +171,7 @@ pub(super) enum ProjectAndUnifyResult<'tcx> {
|
|||
/// ```
|
||||
/// If successful, this may result in additional obligations. Also returns
|
||||
/// the projection cache key used to track these additional obligations.
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
#[instrument(level = "debug", skip(selcx))]
|
||||
pub(super) fn poly_project_and_unify_term<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
|
|
@ -201,6 +201,7 @@ pub(super) fn poly_project_and_unify_term<'cx, 'tcx>(
|
|||
/// If successful, this may result in additional obligations.
|
||||
///
|
||||
/// See [poly_project_and_unify_term] for an explanation of the return value.
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
#[instrument(level = "debug", skip(selcx))]
|
||||
fn project_and_unify_term<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
|
|
@ -258,34 +259,28 @@ fn project_and_unify_term<'cx, 'tcx>(
|
|||
/// there are unresolved type variables in the projection, we will
|
||||
/// instantiate it with a fresh type variable `$X` and generate a new
|
||||
/// obligation `<T as Trait>::Item == $X` for later.
|
||||
pub fn normalize_projection_ty<'a, 'b, 'tcx>(
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
pub fn normalize_projection_term<'a, 'b, 'tcx>(
|
||||
selcx: &'a mut SelectionContext<'b, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
projection_ty: ty::AliasTy<'tcx>,
|
||||
alias_term: ty::AliasTerm<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
depth: usize,
|
||||
obligations: &mut PredicateObligations<'tcx>,
|
||||
) -> Term<'tcx> {
|
||||
opt_normalize_projection_term(
|
||||
selcx,
|
||||
param_env,
|
||||
projection_ty.into(),
|
||||
cause.clone(),
|
||||
depth,
|
||||
obligations,
|
||||
)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_else(move || {
|
||||
// if we bottom out in ambiguity, create a type variable
|
||||
// and a deferred predicate to resolve this when more type
|
||||
// information is available.
|
||||
opt_normalize_projection_term(selcx, param_env, alias_term, cause.clone(), depth, obligations)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_else(move || {
|
||||
// if we bottom out in ambiguity, create a type variable
|
||||
// and a deferred predicate to resolve this when more type
|
||||
// information is available.
|
||||
|
||||
selcx
|
||||
.infcx
|
||||
.projection_ty_to_infer(param_env, projection_ty, cause, depth + 1, obligations)
|
||||
.into()
|
||||
})
|
||||
selcx
|
||||
.infcx
|
||||
.projection_term_to_infer(param_env, alias_term, cause, depth + 1, obligations)
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
/// The guts of `normalize`: normalize a specific projection like `<T
|
||||
|
|
@ -298,6 +293,7 @@ pub fn normalize_projection_ty<'a, 'b, 'tcx>(
|
|||
/// often immediately appended to another obligations vector. So now this
|
||||
/// function takes an obligations vector and appends to it directly, which is
|
||||
/// slightly uglier but avoids the need for an extra short-lived allocation.
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
|
||||
pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
|
||||
selcx: &'a mut SelectionContext<'b, 'tcx>,
|
||||
|
|
@ -456,6 +452,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
|
|||
/// an error for this obligation, but we legitimately should not,
|
||||
/// because it contains `[type error]`. Yuck! (See issue #29857 for
|
||||
/// one case where this arose.)
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
fn normalize_to_error<'a, 'tcx>(
|
||||
selcx: &SelectionContext<'a, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
|
@ -469,9 +466,10 @@ fn normalize_to_error<'a, 'tcx>(
|
|||
| ty::AliasTermKind::InherentTy
|
||||
| ty::AliasTermKind::OpaqueTy
|
||||
| ty::AliasTermKind::FreeTy => selcx.infcx.next_ty_var(cause.span).into(),
|
||||
ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => {
|
||||
selcx.infcx.next_const_var(cause.span).into()
|
||||
}
|
||||
ty::AliasTermKind::FreeConst
|
||||
| ty::AliasTermKind::InherentConst
|
||||
| ty::AliasTermKind::UnevaluatedConst
|
||||
| ty::AliasTermKind::ProjectionConst => selcx.infcx.next_const_var(cause.span).into(),
|
||||
};
|
||||
let mut obligations = PredicateObligations::new();
|
||||
obligations.push(Obligation {
|
||||
|
|
@ -484,36 +482,37 @@ fn normalize_to_error<'a, 'tcx>(
|
|||
}
|
||||
|
||||
/// Confirm and normalize the given inherent projection.
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
|
||||
pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
|
||||
selcx: &'a mut SelectionContext<'b, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
alias_ty: ty::AliasTy<'tcx>,
|
||||
alias_term: ty::AliasTerm<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
depth: usize,
|
||||
obligations: &mut PredicateObligations<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
) -> ty::Term<'tcx> {
|
||||
let tcx = selcx.tcx();
|
||||
|
||||
if !tcx.recursion_limit().value_within_limit(depth) {
|
||||
// Halt compilation because it is important that overflows never be masked.
|
||||
tcx.dcx().emit_fatal(InherentProjectionNormalizationOverflow {
|
||||
span: cause.span,
|
||||
ty: alias_ty.to_string(),
|
||||
ty: alias_term.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let args = compute_inherent_assoc_ty_args(
|
||||
let args = compute_inherent_assoc_term_args(
|
||||
selcx,
|
||||
param_env,
|
||||
alias_ty,
|
||||
alias_term,
|
||||
cause.clone(),
|
||||
depth,
|
||||
obligations,
|
||||
);
|
||||
|
||||
// Register the obligations arising from the impl and from the associated type itself.
|
||||
let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, args);
|
||||
let predicates = tcx.predicates_of(alias_term.def_id).instantiate(tcx, args);
|
||||
for (predicate, span) in predicates {
|
||||
let predicate = normalize_with_depth_to(
|
||||
selcx,
|
||||
|
|
@ -531,7 +530,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
|
|||
// cause code, inherent projections will be printed with identity instantiation in
|
||||
// diagnostics which is not ideal.
|
||||
// Consider creating separate cause codes for this specific situation.
|
||||
ObligationCauseCode::WhereClause(alias_ty.def_id, span),
|
||||
ObligationCauseCode::WhereClause(alias_term.def_id, span),
|
||||
);
|
||||
|
||||
obligations.push(Obligation::with_depth(
|
||||
|
|
@ -543,27 +542,33 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
|
|||
));
|
||||
}
|
||||
|
||||
let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, args);
|
||||
let term: Term<'tcx> = if alias_term.kind(tcx).is_type() {
|
||||
tcx.type_of(alias_term.def_id).instantiate(tcx, args).into()
|
||||
} else {
|
||||
get_associated_const_value(selcx, alias_term.to_term(tcx).expect_const(), param_env).into()
|
||||
};
|
||||
|
||||
let mut ty = selcx.infcx.resolve_vars_if_possible(ty);
|
||||
if ty.has_aliases() {
|
||||
ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations);
|
||||
let mut term = selcx.infcx.resolve_vars_if_possible(term);
|
||||
if term.has_aliases() {
|
||||
term =
|
||||
normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, term, obligations);
|
||||
}
|
||||
|
||||
ty
|
||||
term
|
||||
}
|
||||
|
||||
pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
pub fn compute_inherent_assoc_term_args<'a, 'b, 'tcx>(
|
||||
selcx: &'a mut SelectionContext<'b, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
alias_ty: ty::AliasTy<'tcx>,
|
||||
alias_term: ty::AliasTerm<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
depth: usize,
|
||||
obligations: &mut PredicateObligations<'tcx>,
|
||||
) -> ty::GenericArgsRef<'tcx> {
|
||||
let tcx = selcx.tcx();
|
||||
|
||||
let impl_def_id = tcx.parent(alias_ty.def_id);
|
||||
let impl_def_id = tcx.parent(alias_term.def_id);
|
||||
let impl_args = selcx.infcx.fresh_args_for_item(cause.span, impl_def_id);
|
||||
|
||||
let mut impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args);
|
||||
|
|
@ -580,7 +585,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
|
|||
|
||||
// Infer the generic parameters of the impl by unifying the
|
||||
// impl type with the self type of the projection.
|
||||
let mut self_ty = alias_ty.self_ty();
|
||||
let mut self_ty = alias_term.self_ty();
|
||||
if !selcx.infcx.next_trait_solver() {
|
||||
self_ty = normalize_with_depth_to(
|
||||
selcx,
|
||||
|
|
@ -602,7 +607,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
alias_ty.rebase_inherent_args_onto_impl(impl_args, tcx)
|
||||
alias_term.rebase_inherent_args_onto_impl(impl_args, tcx)
|
||||
}
|
||||
|
||||
enum Projected<'tcx> {
|
||||
|
|
@ -630,6 +635,7 @@ impl<'tcx> Progress<'tcx> {
|
|||
///
|
||||
/// IMPORTANT:
|
||||
/// - `obligation` must be fully normalized
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
#[instrument(level = "info", skip(selcx))]
|
||||
fn project<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
|
|
@ -896,7 +902,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||
ImplSource::UserDefined(impl_data) => {
|
||||
// We have to be careful when projecting out of an
|
||||
// impl because of specialization. If we are not in
|
||||
// codegen (i.e., projection mode is not "any"), and the
|
||||
// codegen (i.e., `TypingMode` is not `PostAnalysis`), and the
|
||||
// impl's type is declared as default, then we disable
|
||||
// projection (even if the trait ref is fully
|
||||
// monomorphic). In the case where trait ref is not
|
||||
|
|
@ -1189,6 +1195,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||
});
|
||||
}
|
||||
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
fn confirm_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTermObligation<'tcx>,
|
||||
|
|
@ -1222,6 +1229,7 @@ fn confirm_candidate<'cx, 'tcx>(
|
|||
result
|
||||
}
|
||||
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
fn confirm_select_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTermObligation<'tcx>,
|
||||
|
|
@ -1873,6 +1881,7 @@ fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>(
|
|||
.with_addl_obligations(nested)
|
||||
}
|
||||
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
fn confirm_param_env_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTermObligation<'tcx>,
|
||||
|
|
@ -1926,9 +1935,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
|
|||
) {
|
||||
Ok(InferOk { value: _, obligations }) => {
|
||||
nested_obligations.extend(obligations);
|
||||
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
|
||||
// FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take
|
||||
// a term instead.
|
||||
assoc_term_own_obligations(selcx, obligation, &mut nested_obligations);
|
||||
Progress { term: cache_entry.term, obligations: nested_obligations }
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
@ -1942,6 +1949,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
fn confirm_impl_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTermObligation<'tcx>,
|
||||
|
|
@ -1955,8 +1963,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
|||
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
|
||||
|
||||
let param_env = obligation.param_env;
|
||||
let assoc_ty = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) {
|
||||
Ok(assoc_ty) => assoc_ty,
|
||||
let assoc_term = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) {
|
||||
Ok(assoc_term) => assoc_term,
|
||||
Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))),
|
||||
};
|
||||
|
||||
|
|
@ -1965,10 +1973,10 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
|||
// has impossible-to-satisfy predicates (since those were
|
||||
// allowed in <https://github.com/rust-lang/rust/pull/135480>),
|
||||
// or because the impl is literally missing the definition.
|
||||
if !assoc_ty.item.defaultness(tcx).has_value() {
|
||||
if !assoc_term.item.defaultness(tcx).has_value() {
|
||||
debug!(
|
||||
"confirm_impl_candidate: no associated type {:?} for {:?}",
|
||||
assoc_ty.item.name(),
|
||||
assoc_term.item.name(),
|
||||
obligation.predicate
|
||||
);
|
||||
if tcx.impl_self_is_guaranteed_unsized(impl_def_id) {
|
||||
|
|
@ -1979,7 +1987,11 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
|||
return Ok(Projected::NoProgress(obligation.predicate.to_term(tcx)));
|
||||
} else {
|
||||
return Ok(Projected::Progress(Progress {
|
||||
term: Ty::new_misc_error(tcx).into(),
|
||||
term: if obligation.predicate.kind(tcx).is_type() {
|
||||
Ty::new_misc_error(tcx).into()
|
||||
} else {
|
||||
ty::Const::new_misc_error(tcx).into()
|
||||
},
|
||||
obligations: nested,
|
||||
}));
|
||||
}
|
||||
|
|
@ -1992,27 +2004,32 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
|||
// * `args` is `[u32]`
|
||||
// * `args` ends up as `[u32, S]`
|
||||
let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args);
|
||||
let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node);
|
||||
let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
|
||||
let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_term.defining_node);
|
||||
|
||||
let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const {
|
||||
let did = assoc_ty.item.def_id;
|
||||
let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did);
|
||||
let uv = ty::UnevaluatedConst::new(did, identity_args);
|
||||
ty::EarlyBinder::bind(ty::Const::new_unevaluated(tcx, uv).into())
|
||||
let term = if obligation.predicate.kind(tcx).is_type() {
|
||||
tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into())
|
||||
} else {
|
||||
tcx.type_of(assoc_ty.item.def_id).map_bound(|ty| ty.into())
|
||||
ty::EarlyBinder::bind(
|
||||
get_associated_const_value(
|
||||
selcx,
|
||||
obligation.predicate.to_term(tcx).expect_const(),
|
||||
param_env,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
};
|
||||
|
||||
let progress = if !tcx.check_args_compatible(assoc_ty.item.def_id, args) {
|
||||
let err = Ty::new_error_with_message(
|
||||
tcx,
|
||||
obligation.cause.span,
|
||||
"impl item and trait item have different parameters",
|
||||
);
|
||||
Progress { term: err.into(), obligations: nested }
|
||||
let progress = if !tcx.check_args_compatible(assoc_term.item.def_id, args) {
|
||||
let msg = "impl item and trait item have different parameters";
|
||||
let span = obligation.cause.span;
|
||||
let err = if obligation.predicate.kind(tcx).is_type() {
|
||||
Ty::new_error_with_message(tcx, span, msg).into()
|
||||
} else {
|
||||
ty::Const::new_error_with_message(tcx, span, msg).into()
|
||||
};
|
||||
Progress { term: err, obligations: nested }
|
||||
} else {
|
||||
assoc_ty_own_obligations(selcx, obligation, &mut nested);
|
||||
assoc_term_own_obligations(selcx, obligation, &mut nested);
|
||||
Progress { term: term.instantiate(tcx, args), obligations: nested }
|
||||
};
|
||||
Ok(Projected::Progress(progress))
|
||||
|
|
@ -2020,7 +2037,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
|||
|
||||
// Get obligations corresponding to the predicates from the where-clause of the
|
||||
// associated type itself.
|
||||
fn assoc_ty_own_obligations<'cx, 'tcx>(
|
||||
// FIXME(mgca): While this supports constants, it is only used for types by default right now
|
||||
fn assoc_term_own_obligations<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTermObligation<'tcx>,
|
||||
nested: &mut PredicateObligations<'tcx>,
|
||||
|
|
@ -2090,3 +2108,15 @@ impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn get_associated_const_value<'tcx>(
|
||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||
alias_ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> ty::Const<'tcx> {
|
||||
// FIXME(mgca): We shouldn't be invoking ctfe here, instead const items should be aliases to type
|
||||
// system consts that we can retrieve with some `query const_arg_of_alias` query. Evaluating the
|
||||
// constant is "close enough" to getting the actual rhs of the const item for now even if it might
|
||||
// lead to some cycles
|
||||
super::evaluate_const(selcx.infcx, alias_ct, param_env)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -406,7 +406,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
|
||||
|
||||
let mut assume = predicate.trait_ref.args.const_at(2);
|
||||
// FIXME(mgca): We should shallowly normalize this.
|
||||
if self.tcx().features().generic_const_exprs() {
|
||||
assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
use std::iter;
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
|
||||
use rustc_middle::bug;
|
||||
|
|
@ -486,7 +487,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
/// Pushes the obligations required for an inherent alias to be WF
|
||||
/// into `self.out`.
|
||||
// FIXME(inherent_associated_types): Merge this function with `fn compute_alias`.
|
||||
fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
|
||||
fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTerm<'tcx>) {
|
||||
// An inherent projection is well-formed if
|
||||
//
|
||||
// (a) its predicates hold (*)
|
||||
|
|
@ -498,7 +499,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
if !data.self_ty().has_escaping_bound_vars() {
|
||||
// FIXME(inherent_associated_types): Should this happen inside of a snapshot?
|
||||
// FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm!
|
||||
let args = traits::project::compute_inherent_assoc_ty_args(
|
||||
let args = traits::project::compute_inherent_assoc_term_args(
|
||||
&mut traits::SelectionContext::new(self.infcx),
|
||||
self.param_env,
|
||||
data,
|
||||
|
|
@ -776,7 +777,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
self.out.extend(obligations);
|
||||
}
|
||||
ty::Alias(ty::Inherent, data) => {
|
||||
self.add_wf_preds_for_inherent_projection(data);
|
||||
self.add_wf_preds_for_inherent_projection(data.into());
|
||||
return; // Subtree handled by compute_inherent_projection.
|
||||
}
|
||||
|
||||
|
|
@ -961,9 +962,6 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
match c.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
if !c.has_escaping_bound_vars() {
|
||||
let obligations = self.nominal_obligations(uv.def, uv.args);
|
||||
self.out.extend(obligations);
|
||||
|
||||
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::ConstEvaluatable(c),
|
||||
));
|
||||
|
|
@ -975,6 +973,16 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
self.param_env,
|
||||
predicate,
|
||||
));
|
||||
|
||||
if tcx.def_kind(uv.def) == DefKind::AssocConst
|
||||
&& tcx.def_kind(tcx.parent(uv.def)) == (DefKind::Impl { of_trait: false })
|
||||
{
|
||||
self.add_wf_preds_for_inherent_projection(uv.into());
|
||||
return; // Subtree is handled by above function
|
||||
} else {
|
||||
let obligations = self.nominal_obligations(uv.def, uv.args);
|
||||
self.out.extend(obligations);
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Infer(_) => {
|
||||
|
|
|
|||
|
|
@ -32,8 +32,14 @@ fn normalize_canonicalized_projection_ty<'tcx>(
|
|||
let selcx = &mut SelectionContext::new(ocx.infcx);
|
||||
let cause = ObligationCause::dummy();
|
||||
let mut obligations = PredicateObligations::new();
|
||||
let answer =
|
||||
traits::normalize_projection_ty(selcx, param_env, goal, cause, 0, &mut obligations);
|
||||
let answer = traits::normalize_projection_term(
|
||||
selcx,
|
||||
param_env,
|
||||
goal.into(),
|
||||
cause,
|
||||
0,
|
||||
&mut obligations,
|
||||
);
|
||||
ocx.register_obligations(obligations);
|
||||
// #112047: With projections and opaques, we are able to create opaques that
|
||||
// are recursive (given some generic parameters of the opaque's type variables).
|
||||
|
|
@ -104,14 +110,14 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>(
|
|||
let answer = traits::normalize_inherent_projection(
|
||||
selcx,
|
||||
param_env,
|
||||
goal,
|
||||
goal.into(),
|
||||
cause,
|
||||
0,
|
||||
&mut obligations,
|
||||
);
|
||||
ocx.register_obligations(obligations);
|
||||
|
||||
Ok(NormalizationResult { normalized_ty: answer })
|
||||
Ok(NormalizationResult { normalized_ty: answer.expect_type() })
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -474,10 +474,15 @@ pub enum AliasTermKind {
|
|||
/// Currently only used if the type alias references opaque types.
|
||||
/// Can always be normalized away.
|
||||
FreeTy,
|
||||
/// An unevaluated const coming from a generic const expression.
|
||||
|
||||
/// An unevaluated anonymous constants.
|
||||
UnevaluatedConst,
|
||||
/// An unevaluated const coming from an associated const.
|
||||
ProjectionConst,
|
||||
/// A top level const item not part of a trait or impl.
|
||||
FreeConst,
|
||||
/// An associated const in an inherent `impl`
|
||||
InherentConst,
|
||||
}
|
||||
|
||||
impl AliasTermKind {
|
||||
|
|
@ -486,11 +491,27 @@ impl AliasTermKind {
|
|||
AliasTermKind::ProjectionTy => "associated type",
|
||||
AliasTermKind::ProjectionConst => "associated const",
|
||||
AliasTermKind::InherentTy => "inherent associated type",
|
||||
AliasTermKind::InherentConst => "inherent associated const",
|
||||
AliasTermKind::OpaqueTy => "opaque type",
|
||||
AliasTermKind::FreeTy => "type alias",
|
||||
AliasTermKind::FreeConst => "unevaluated constant",
|
||||
AliasTermKind::UnevaluatedConst => "unevaluated constant",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_type(self) -> bool {
|
||||
match self {
|
||||
AliasTermKind::ProjectionTy
|
||||
| AliasTermKind::InherentTy
|
||||
| AliasTermKind::OpaqueTy
|
||||
| AliasTermKind::FreeTy => true,
|
||||
|
||||
AliasTermKind::UnevaluatedConst
|
||||
| AliasTermKind::ProjectionConst
|
||||
| AliasTermKind::InherentConst
|
||||
| AliasTermKind::FreeConst => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ty::AliasTyKind> for AliasTermKind {
|
||||
|
|
@ -566,7 +587,10 @@ impl<I: Interner> AliasTerm<I> {
|
|||
| AliasTermKind::InherentTy
|
||||
| AliasTermKind::OpaqueTy
|
||||
| AliasTermKind::FreeTy => {}
|
||||
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
|
||||
AliasTermKind::InherentConst
|
||||
| AliasTermKind::FreeConst
|
||||
| AliasTermKind::UnevaluatedConst
|
||||
| AliasTermKind::ProjectionConst => {
|
||||
panic!("Cannot turn `UnevaluatedConst` into `AliasTy`")
|
||||
}
|
||||
}
|
||||
|
|
@ -603,18 +627,19 @@ impl<I: Interner> AliasTerm<I> {
|
|||
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
|
||||
)
|
||||
.into(),
|
||||
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
|
||||
I::Const::new_unevaluated(
|
||||
interner,
|
||||
ty::UnevaluatedConst::new(self.def_id, self.args),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
AliasTermKind::FreeConst
|
||||
| AliasTermKind::InherentConst
|
||||
| AliasTermKind::UnevaluatedConst
|
||||
| AliasTermKind::ProjectionConst => I::Const::new_unevaluated(
|
||||
interner,
|
||||
ty::UnevaluatedConst::new(self.def_id, self.args),
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The following methods work only with (trait) associated type projections.
|
||||
/// The following methods work only with (trait) associated term projections.
|
||||
impl<I: Interner> AliasTerm<I> {
|
||||
pub fn self_ty(self) -> I::Ty {
|
||||
self.args.type_at(0)
|
||||
|
|
@ -659,6 +684,31 @@ impl<I: Interner> AliasTerm<I> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The following methods work only with inherent associated term projections.
|
||||
impl<I: Interner> AliasTerm<I> {
|
||||
/// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
|
||||
///
|
||||
/// Does the following transformation:
|
||||
///
|
||||
/// ```text
|
||||
/// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
|
||||
///
|
||||
/// I_i impl args
|
||||
/// P_j GAT args
|
||||
/// ```
|
||||
pub fn rebase_inherent_args_onto_impl(
|
||||
self,
|
||||
impl_args: I::GenericArgs,
|
||||
interner: I,
|
||||
) -> I::GenericArgs {
|
||||
debug_assert!(matches!(
|
||||
self.kind(interner),
|
||||
AliasTermKind::InherentTy | AliasTermKind::InherentConst
|
||||
));
|
||||
interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> From<ty::AliasTy<I>> for AliasTerm<I> {
|
||||
fn from(ty: ty::AliasTy<I>) -> Self {
|
||||
AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }
|
||||
|
|
|
|||
|
|
@ -273,8 +273,10 @@ impl<I: Interner> Relate<I> for ty::AliasTerm<I> {
|
|||
false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
|
||||
)?,
|
||||
ty::AliasTermKind::ProjectionTy
|
||||
| ty::AliasTermKind::FreeConst
|
||||
| ty::AliasTermKind::FreeTy
|
||||
| ty::AliasTermKind::InherentTy
|
||||
| ty::AliasTermKind::InherentConst
|
||||
| ty::AliasTermKind::UnevaluatedConst
|
||||
| ty::AliasTermKind::ProjectionConst => {
|
||||
relate_args_invariantly(relation, a.args, b.args)?
|
||||
|
|
|
|||
|
|
@ -514,28 +514,6 @@ impl<I: Interner> AliasTy<I> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The following methods work only with inherent associated type projections.
|
||||
impl<I: Interner> AliasTy<I> {
|
||||
/// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
|
||||
///
|
||||
/// Does the following transformation:
|
||||
///
|
||||
/// ```text
|
||||
/// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
|
||||
///
|
||||
/// I_i impl args
|
||||
/// P_j GAT args
|
||||
/// ```
|
||||
pub fn rebase_inherent_args_onto_impl(
|
||||
self,
|
||||
impl_args: I::GenericArgs,
|
||||
interner: I,
|
||||
) -> I::GenericArgs {
|
||||
debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent);
|
||||
interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "nightly",
|
||||
|
|
|
|||
|
|
@ -39,14 +39,6 @@ error: unconstrained generic constant
|
|||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: required by a bound in `test1`
|
||||
--> $DIR/auxiliary/const_evaluatable_lib.rs:5:10
|
||||
|
|
||||
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
|
||||
| ----- required by a bound in this function
|
||||
LL | where
|
||||
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1`
|
||||
help: try adding a `where` bound
|
||||
|
|
||||
LL | fn user<T>() where [(); std::mem::size_of::<T>() - 1]: {
|
||||
|
|
@ -59,10 +51,13 @@ LL | let _ = const_evaluatable_lib::test1::<T>();
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: required by a bound in `test1`
|
||||
--> $DIR/auxiliary/const_evaluatable_lib.rs:3:27
|
||||
--> $DIR/auxiliary/const_evaluatable_lib.rs:5:10
|
||||
|
|
||||
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1`
|
||||
| ----- required by a bound in this function
|
||||
LL | where
|
||||
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1`
|
||||
help: try adding a `where` bound
|
||||
|
|
||||
LL | fn user<T>() where [(); std::mem::size_of::<T>() - 1]: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue