use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
+use rustc_infer::infer::at::At;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::traits::ImplSourceBuiltinData;
use rustc_middle::traits::select::OverflowError;
pub(super) struct InProgress;
+pub trait NormalizeExt<'tcx> {
+ /// Normalize a value using the `AssocTypeNormalizer`.
+ ///
+ /// This normalization should be used when the type contains inference variables or the
+ /// projection may be fallible.
+ fn normalize<T: TypeFoldable<'tcx>>(&self, t: T) -> InferOk<'tcx, T>;
+}
+
+impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> {
+ fn normalize<T: TypeFoldable<'tcx>>(&self, value: T) -> InferOk<'tcx, T> {
+ let mut selcx = SelectionContext::new(self.infcx);
+ let Normalized { value, obligations } =
+ normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
+ InferOk { value, obligations }
+ }
+}
+
/// When attempting to resolve `<T as TraitRef>::Name` ...
#[derive(Debug)]
pub enum ProjectionError<'tcx> {
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &PolyProjectionObligation<'tcx>,
) -> ProjectAndUnifyResult<'tcx> {
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
let r = infcx.commit_if_ok(|_snapshot| {
let old_universe = infcx.universe();
let placeholder_predicate =
) -> ProjectAndUnifyResult<'tcx> {
let mut obligations = vec![];
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
let normalized = match opt_normalize_projection_type(
selcx,
obligation.param_env,
// This allows users to omit re-mentioning all bounds on an associated type and just use an
// `impl Trait` for the assoc type to add more bounds.
let InferOk { value: actual, obligations: new } =
- selcx.infcx().replace_opaque_types_with_inference_vars(
+ selcx.infcx.replace_opaque_types_with_inference_vars(
actual,
obligation.cause.body_id,
obligation.cause.span,
}
}
-/// Normalizes any associated type projections in `value`, replacing
-/// them with a fully resolved type where possible. The return value
-/// combines the normalized result and any additional obligations that
-/// were incurred as result.
-pub fn normalize<'a, 'b, 'tcx, T>(
- selcx: &'a mut SelectionContext<'b, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- cause: ObligationCause<'tcx>,
- value: T,
-) -> Normalized<'tcx, T>
-where
- T: TypeFoldable<'tcx>,
-{
- let mut obligations = Vec::new();
- let value = normalize_to(selcx, param_env, cause, value, &mut obligations);
- Normalized { value, obligations }
-}
-
-pub fn normalize_to<'a, 'b, 'tcx, T>(
- selcx: &'a mut SelectionContext<'b, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- cause: ObligationCause<'tcx>,
- value: T,
- obligations: &mut Vec<PredicateObligation<'tcx>>,
-) -> T
-where
- T: TypeFoldable<'tcx>,
-{
- normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations)
-}
-
/// As `normalize`, but with a custom depth.
-pub fn normalize_with_depth<'a, 'b, 'tcx, T>(
+pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>(
selcx: &'a mut SelectionContext<'b, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
}
#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
-pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
+pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
selcx: &'a mut SelectionContext<'b, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
}
#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
-pub fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>(
+pub(crate) fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>(
selcx: &'a mut SelectionContext<'b, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
}
fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
- let value = self.selcx.infcx().resolve_vars_if_possible(value);
+ let value = self.selcx.infcx.resolve_vars_if_possible(value);
debug!(?value);
assert!(
Reveal::All => {
let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
- let obligation = Obligation::with_depth(
- self.tcx(),
- self.cause.clone(),
- recursion_limit.0,
- self.param_env,
- ty,
+ self.selcx.infcx.err_ctxt().report_overflow_error(
+ &ty,
+ self.cause.span,
+ true,
+ |_| {},
);
- self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true);
}
let substs = substs.fold_with(self);
// want to figure out how to register obligations with escaping vars
// or handle this some other way.
- let infcx = self.selcx.infcx();
+ 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 constant = constant.super_fold_with(self);
debug!(?constant, ?self.param_env);
with_replaced_escaping_bound_vars(
- self.selcx.infcx(),
+ self.selcx.infcx,
&mut self.universes,
constant,
|constant| constant.eval(tcx, self.param_env),
let universe = self.universe_for(debruijn);
let p = ty::PlaceholderConst { universe, name: bound_const };
self.mapped_consts.insert(p, bound_const);
- self.infcx.tcx.mk_const(ty::ConstKind::Placeholder(p), ct.ty())
+ self.infcx.tcx.mk_const(p, ct.ty())
}
_ => ct.super_fold_with(self),
}
}
}
-// The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came.
+/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came.
pub struct PlaceholderReplacer<'me, 'tcx> {
infcx: &'me InferCtxt<'tcx>,
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
// and a deferred predicate to resolve this when more type
// information is available.
- selcx
- .infcx()
- .infer_projection(param_env, projection_ty, cause, depth + 1, obligations)
- .into()
+ selcx.infcx.infer_projection(param_env, projection_ty, cause, depth + 1, obligations).into()
})
}
depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>,
) -> Result<Option<Term<'tcx>>, InProgress> {
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
// Don't use the projection cache in intercrate mode -
// the `infcx` may be re-used between intercrate in non-intercrate
// mode, which could lead to using incorrect cache results.
// an impl, where-clause etc) and hence we must
// re-normalize it
- let projected_term = selcx.infcx().resolve_vars_if_possible(projected_term);
+ let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term);
let mut result = if projected_term.has_projections() {
let mut normalizer = AssocTypeNormalizer::new(
param_env,
predicate: trait_ref.without_const().to_predicate(selcx.tcx()),
};
- let tcx = selcx.infcx().tcx;
+ let tcx = selcx.infcx.tcx;
let def_id = projection_ty.item_def_id;
- let new_value = selcx.infcx().next_ty_var(TypeVariableOrigin {
+ let new_value = selcx.infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::NormalizeProjectionType,
span: tcx.def_span(def_id),
});
obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
// FIXME(named-returns): Binders
let trait_predicate =
- ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs })
- .to_poly_trait_predicate();
+ ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs });
- let _ = selcx.infcx().commit_if_ok(|_| {
+ let _ = selcx.infcx.commit_if_ok(|_| {
match selcx.select(&obligation.with(tcx, trait_predicate)) {
Ok(Some(super::ImplSource::UserDefined(data))) => {
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
let tcx = selcx.tcx();
let self_ty = obligation.predicate.self_ty();
- let object_ty = selcx.infcx().shallow_resolve(self_ty);
+ let object_ty = selcx.infcx.shallow_resolve(self_ty);
let data = match object_ty.kind() {
ty::Dynamic(data, ..) => data,
ty::Infer(ty::TyVar(_)) => {
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
potentially_unnormalized_candidates: bool,
) {
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
for predicate in env_predicates {
let bound_predicate = predicate.kind();
- if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() {
+ if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) =
+ predicate.kind().skip_binder()
+ {
let data = bound_predicate.rebind(data);
if data.projection_def_id() != obligation.predicate.item_def_id {
continue;
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
// start out by selecting the predicate `T as TraitRef<...>`:
let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));
- let trait_obligation = obligation.with(selcx.tcx(), poly_trait_ref.to_poly_trait_predicate());
- let _ = selcx.infcx().commit_if_ok(|_| {
+ let trait_obligation = obligation.with(selcx.tcx(), poly_trait_ref);
+ let _ = selcx.infcx.commit_if_ok(|_| {
let impl_source = match selcx.select(&trait_obligation) {
Ok(Some(impl_source)) => impl_source,
Ok(None) => {
if obligation.param_env.reveal() == Reveal::All {
// NOTE(eddyb) inference variables can resolve to parameters, so
// assume `poly_trait_ref` isn't monomorphic, if it contains any.
- let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(poly_trait_ref);
+ let poly_trait_ref = selcx.infcx.resolve_vars_if_possible(poly_trait_ref);
!poly_trait_ref.still_further_specializable()
} else {
debug!(
// While a builtin impl may be known to exist, the associated type may not yet
// be known. Any type with multiple potential associated types is therefore
// not eligible.
- let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+ let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
let lang_items = selcx.tcx().lang_items();
if lang_items.discriminant_kind_trait() == Some(poly_trait_ref.def_id()) {
// type parameters, opaques, and unnormalized projections have pointer
// metadata if they're known (e.g. by the param_env) to be sized
ty::Param(_) | ty::Projection(..) | ty::Opaque(..)
- if selcx.infcx().predicate_must_hold_modulo_regions(
+ if selcx.infcx.predicate_must_hold_modulo_regions(
&obligation.with(
selcx.tcx(),
ty::Binder::dummy(
// when possible for this to work. See `auto-trait-projection-recursion.rs`
// for a case where this matters.
if progress.term.has_infer_regions() {
- progress.term =
- progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx()));
+ progress.term = progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx));
}
progress
}
obligation: &ProjectionTyObligation<'tcx>,
fn_pointer_impl_source: ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
- let fn_type = selcx.infcx().shallow_resolve(fn_pointer_impl_source.fn_ty);
+ let fn_type = selcx.infcx.shallow_resolve(fn_pointer_impl_source.fn_ty);
let sig = fn_type.fn_sig(selcx.tcx());
let Normalized { value: sig, obligations } = normalize_with_depth(
selcx,
poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
potentially_unnormalized_candidate: bool,
) -> Progress<'tcx> {
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
let cause = &obligation.cause;
let param_env = obligation.param_env;
// * `substs` ends up as `[u32, S]`
let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs);
let substs =
- translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node);
+ translate_substs(selcx.infcx, param_env, impl_def_id, substs, assoc_ty.defining_node);
let ty = tcx.bound_type_of(assoc_ty.item.def_id);
let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
let impl_fn_substs =
obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
let impl_fn_substs = translate_substs(
- selcx.infcx(),
+ selcx.infcx,
obligation.param_env,
data.impl_def_id,
impl_fn_substs,
},
));
- let ty = super::normalize_to(
+ let ty = normalize_with_depth_to(
selcx,
obligation.param_env,
cause.clone(),
+ obligation.recursion_depth + 1,
tcx.bound_trait_impl_trait_tys(impl_fn_def_id)
.map_bound(|tys| {
tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.item_def_id])
nested: &mut Vec<PredicateObligation<'tcx>>,
) {
let tcx = selcx.tcx();
- for predicate in tcx
+ let own = tcx
.predicates_of(obligation.predicate.item_def_id)
- .instantiate_own(tcx, obligation.predicate.substs)
- .predicates
- {
+ .instantiate_own(tcx, obligation.predicate.substs);
+ for (predicate, span) in std::iter::zip(own.predicates, own.spans) {
let normalized = normalize_with_depth_to(
selcx,
obligation.param_env,
predicate,
nested,
);
+
+ let nested_cause = if matches!(
+ obligation.cause.code(),
+ super::CompareImplItemObligation { .. }
+ | super::CheckAssociatedTypeBounds { .. }
+ | super::AscribeUserTypeProvePredicate(..)
+ ) {
+ obligation.cause.clone()
+ } else if span.is_dummy() {
+ ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ super::ItemObligation(obligation.predicate.item_def_id),
+ )
+ } else {
+ ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ super::BindingObligation(obligation.predicate.item_def_id, span),
+ )
+ };
nested.push(Obligation::with_depth(
tcx,
- obligation.cause.clone(),
+ nested_cause,
obligation.recursion_depth + 1,
obligation.param_env,
normalized,
selcx: &mut SelectionContext<'cx, 'tcx>,
predicate: ty::PolyProjectionPredicate<'tcx>,
) -> Option<Self> {
- let infcx = selcx.infcx();
+ let infcx = selcx.infcx;
// We don't do cross-snapshot caching of obligations with escaping regions,
// so there's no cache key to use
predicate.no_bound_vars().map(|predicate| {