some type system cleanup
This commit is contained in:
parent
2b43e75c98
commit
5fb67e2ad4
9 changed files with 169 additions and 151 deletions
|
@ -85,25 +85,16 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
|
|||
),
|
||||
);
|
||||
|
||||
// Do not emit an error if normalization is known to fail but instead
|
||||
// keep the projection unnormalized. This is the case for projections
|
||||
// with a `T: Trait` where-clause and opaque types outside of the defining
|
||||
// scope.
|
||||
let result = if infcx.predicate_may_hold(&obligation) {
|
||||
self.fulfill_cx.register_predicate_obligation(infcx, obligation);
|
||||
let errors = self.fulfill_cx.select_all_or_error(infcx);
|
||||
if !errors.is_empty() {
|
||||
return Err(errors);
|
||||
}
|
||||
let ty = infcx.resolve_vars_if_possible(new_infer_ty);
|
||||
|
||||
// Alias is guaranteed to be fully structurally resolved,
|
||||
// so we can super fold here.
|
||||
ty.try_super_fold_with(self)?
|
||||
} else {
|
||||
alias_ty.try_super_fold_with(self)?
|
||||
};
|
||||
self.fulfill_cx.register_predicate_obligation(infcx, obligation);
|
||||
let errors = self.fulfill_cx.select_all_or_error(infcx);
|
||||
if !errors.is_empty() {
|
||||
return Err(errors);
|
||||
}
|
||||
|
||||
// Alias is guaranteed to be fully structurally resolved,
|
||||
// so we can super fold here.
|
||||
let ty = infcx.resolve_vars_if_possible(new_infer_ty);
|
||||
let result = ty.try_super_fold_with(self)?;
|
||||
self.depth -= 1;
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -178,6 +169,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
|
|||
Ok(t)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
||||
let infcx = self.at.infcx;
|
||||
debug_assert_eq!(ty, infcx.shallow_resolve(ty));
|
||||
|
@ -204,6 +196,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
|
||||
let infcx = self.at.infcx;
|
||||
debug_assert_eq!(ct, infcx.shallow_resolve(ct));
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
use crate::solve::EvalCtxt;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||
use rustc_middle::ty;
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub(super) fn normalize_anon_const(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
if let Some(normalized_const) = self.try_const_eval_resolve(
|
||||
goal.param_env,
|
||||
ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args),
|
||||
self.tcx()
|
||||
.type_of(goal.predicate.alias.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const ty should not rely on other generics"),
|
||||
) {
|
||||
self.eq(goal.param_env, normalized_const, goal.predicate.term.ct().unwrap())?;
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
} else {
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,8 +18,9 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
|
|||
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
|
||||
use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
|
||||
|
||||
mod anon_const;
|
||||
mod inherent;
|
||||
mod opaques;
|
||||
mod opaque_types;
|
||||
mod weak_types;
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
|
@ -31,34 +32,34 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
let def_id = goal.predicate.def_id();
|
||||
match self.tcx().def_kind(def_id) {
|
||||
DefKind::AssocTy | DefKind::AssocConst => {
|
||||
// To only compute normalization once for each projection we only
|
||||
// assemble normalization candidates if the expected term is an
|
||||
// unconstrained inference variable.
|
||||
//
|
||||
// Why: For better cache hits, since if we have an unconstrained RHS then
|
||||
// there are only as many cache keys as there are (canonicalized) alias
|
||||
// types in each normalizes-to goal. This also weakens inference in a
|
||||
// forwards-compatible way so we don't use the value of the RHS term to
|
||||
// affect candidate assembly for projections.
|
||||
//
|
||||
// E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
|
||||
// `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
|
||||
// `U` and equate it with `u32`. This means that we don't need a separate
|
||||
// projection cache in the solver, since we're piggybacking off of regular
|
||||
// goal caching.
|
||||
if self.term_is_fully_unconstrained(goal) {
|
||||
match self.tcx().associated_item(def_id).container {
|
||||
ty::AssocItemContainer::TraitContainer => {
|
||||
match self.tcx().associated_item(def_id).container {
|
||||
ty::AssocItemContainer::TraitContainer => {
|
||||
// To only compute normalization once for each projection we only
|
||||
// assemble normalization candidates if the expected term is an
|
||||
// unconstrained inference variable.
|
||||
//
|
||||
// Why: For better cache hits, since if we have an unconstrained RHS then
|
||||
// there are only as many cache keys as there are (canonicalized) alias
|
||||
// types in each normalizes-to goal. This also weakens inference in a
|
||||
// forwards-compatible way so we don't use the value of the RHS term to
|
||||
// affect candidate assembly for projections.
|
||||
//
|
||||
// E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
|
||||
// `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
|
||||
// `U` and equate it with `u32`. This means that we don't need a separate
|
||||
// projection cache in the solver, since we're piggybacking off of regular
|
||||
// goal caching.
|
||||
if self.term_is_fully_unconstrained(goal) {
|
||||
let candidates = self.assemble_and_evaluate_candidates(goal);
|
||||
self.merge_candidates(candidates)
|
||||
}
|
||||
ty::AssocItemContainer::ImplContainer => {
|
||||
self.normalize_inherent_associated_type(goal)
|
||||
} else {
|
||||
self.set_normalizes_to_hack_goal(goal);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.set_normalizes_to_hack_goal(goal);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ty::AssocItemContainer::ImplContainer => {
|
||||
self.normalize_inherent_associated_type(goal)
|
||||
}
|
||||
}
|
||||
}
|
||||
DefKind::AnonConst => self.normalize_anon_const(goal),
|
||||
|
@ -67,26 +68,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn normalize_anon_const(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
if let Some(normalized_const) = self.try_const_eval_resolve(
|
||||
goal.param_env,
|
||||
ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args),
|
||||
self.tcx()
|
||||
.type_of(goal.predicate.alias.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const ty should not rely on other generics"),
|
||||
) {
|
||||
self.eq(goal.param_env, normalized_const, goal.predicate.term.ct().unwrap())?;
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
} else {
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue