1//! Deeply normalize types using the old trait solver.
23use rustc_data_structures::stack::ensure_sufficient_stack;
4use rustc_errors::msg;
5use rustc_hir::def::DefKind;
6use rustc_infer::infer::at::At;
7use rustc_infer::infer::{InferCtxt, InferOk};
8use rustc_infer::traits::{
9FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
10};
11use rustc_macros::extension;
12use rustc_middle::span_bug;
13use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
14use rustc_middle::ty::{
15self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
16TypeVisitableExt, TypingMode,
17};
18use tracing::{debug, instrument};
1920use super::{BoundVarReplacer, PlaceholderReplacer, SelectionContext, project};
21use crate::error_reporting::InferCtxtErrorExt;
22use crate::error_reporting::traits::OverflowCause;
23use crate::solve::NextSolverError;
2425impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> {
#[doc = " Normalize a value using the `AssocTypeNormalizer`."]
#[doc = ""]
#[doc =
" This normalization should be used when the type contains inference variables or the"]
#[doc = " projection may be fallible."]
fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T)
-> InferOk<'tcx, T> {
if self.infcx.next_trait_solver() {
InferOk { value, obligations: PredicateObligations::new() }
} else {
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 }
}
}
#[doc =
" Deeply normalizes `value`, replacing all aliases which can by normalized in"]
#[doc =
" the current environment. In the new solver this errors in case normalization"]
#[doc = " fails or is ambiguous."]
#[doc = ""]
#[doc =
" In the old solver this simply uses `normalizes` and adds the nested obligations"]
#[doc =
" to the `fulfill_cx`. This is necessary as we otherwise end up recomputing the"]
#[doc =
" same goals in both a temporary and the shared context which negatively impacts"]
#[doc = " performance as these don\'t share caching."]
#[doc = ""]
#[doc =
" FIXME(-Znext-solver=no): For performance reasons, we currently reuse an existing"]
#[doc =
" fulfillment context in the old solver. Once we have removed the old solver, we"]
#[doc = " can remove the `fulfill_cx` parameter on this function."]
fn deeply_normalize<T,
E>(self, value: T, fulfill_cx: &mut dyn TraitEngine<'tcx, E>)
-> Result<T, Vec<E>> where T: TypeFoldable<TyCtxt<'tcx>>,
E: FromSolverError<'tcx, NextSolverError<'tcx>> {
if self.infcx.next_trait_solver() {
crate::solve::deeply_normalize(self, value)
} else {
if fulfill_cx.has_pending_obligations() {
let pending_obligations = fulfill_cx.pending_obligations();
::rustc_middle::util::bug::span_bug_fmt(pending_obligations[0].cause.span,
format_args!("deeply_normalize should not be called with pending obligations: {0:#?}",
pending_obligations));
}
let value =
self.normalize(value).into_value_registering_obligations(self.infcx,
&mut *fulfill_cx);
let errors =
fulfill_cx.evaluate_obligations_error_on_ambiguity(self.infcx);
let value = self.infcx.resolve_vars_if_possible(value);
if errors.is_empty() {
Ok(value)
} else {
let _ = fulfill_cx.collect_remaining_errors(self.infcx);
Err(errors)
}
}
}
}#[extension(pub trait NormalizeExt<'tcx>)]26impl<'tcx> At<'_, 'tcx> {
27/// Normalize a value using the `AssocTypeNormalizer`.
28 ///
29 /// This normalization should be used when the type contains inference variables or the
30 /// projection may be fallible.
31fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
32if self.infcx.next_trait_solver() {
33InferOk { value, obligations: PredicateObligations::new() }
34 } else {
35let mut selcx = SelectionContext::new(self.infcx);
36let Normalized { value, obligations } =
37normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
38InferOk { value, obligations }
39 }
40 }
4142/// Deeply normalizes `value`, replacing all aliases which can by normalized in
43 /// the current environment. In the new solver this errors in case normalization
44 /// fails or is ambiguous.
45 ///
46 /// In the old solver this simply uses `normalizes` and adds the nested obligations
47 /// to the `fulfill_cx`. This is necessary as we otherwise end up recomputing the
48 /// same goals in both a temporary and the shared context which negatively impacts
49 /// performance as these don't share caching.
50 ///
51 /// FIXME(-Znext-solver=no): For performance reasons, we currently reuse an existing
52 /// fulfillment context in the old solver. Once we have removed the old solver, we
53 /// can remove the `fulfill_cx` parameter on this function.
54fn deeply_normalize<T, E>(
55self,
56 value: T,
57 fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
58 ) -> Result<T, Vec<E>>
59where
60T: TypeFoldable<TyCtxt<'tcx>>,
61 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
62 {
63if self.infcx.next_trait_solver() {
64crate::solve::deeply_normalize(self, value)
65 } else {
66if fulfill_cx.has_pending_obligations() {
67let pending_obligations = fulfill_cx.pending_obligations();
68span_bug!(
69pending_obligations[0].cause.span,
70"deeply_normalize should not be called with pending obligations: \
71 {pending_obligations:#?}"
72);
73 }
74let value = self75 .normalize(value)
76 .into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
77let errors = fulfill_cx.evaluate_obligations_error_on_ambiguity(self.infcx);
78let value = self.infcx.resolve_vars_if_possible(value);
79if errors.is_empty() {
80Ok(value)
81 } else {
82// Drop pending obligations, since deep normalization may happen
83 // in a loop and we don't want to trigger the assertion on the next
84 // iteration due to pending ambiguous obligations we've left over.
85let _ = fulfill_cx.collect_remaining_errors(self.infcx);
86Err(errors)
87 }
88 }
89 }
90}
9192/// As `normalize`, but with a custom depth.
93pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>(
94 selcx: &'a mut SelectionContext<'b, 'tcx>,
95 param_env: ty::ParamEnv<'tcx>,
96 cause: ObligationCause<'tcx>,
97 depth: usize,
98 value: T,
99) -> Normalized<'tcx, T>
100where
101T: TypeFoldable<TyCtxt<'tcx>>,
102{
103let mut obligations = PredicateObligations::new();
104let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations);
105Normalized { value, obligations }
106}
107108#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("normalize_with_depth_to",
"rustc_trait_selection::traits::normalize",
::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/normalize.rs"),
::tracing_core::__macro_support::Option::Some(108u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::normalize"),
::tracing_core::field::FieldSet::new(&["depth", "value"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::INFO <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&depth as
&dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&value)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: T = loop {};
return __tracing_attr_fake_return;
}
{
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/normalize.rs:120",
"rustc_trait_selection::traits::normalize",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/normalize.rs"),
::tracing_core::__macro_support::Option::Some(120u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::normalize"),
::tracing_core::field::FieldSet::new(&["obligations.len"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&obligations.len()
as &dyn Value))])
});
} else { ; }
};
let mut normalizer =
AssocTypeNormalizer::new(selcx, param_env, cause, depth,
obligations);
let result =
ensure_sufficient_stack(||
AssocTypeNormalizer::fold(&mut normalizer, value));
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/normalize.rs:123",
"rustc_trait_selection::traits::normalize",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/normalize.rs"),
::tracing_core::__macro_support::Option::Some(123u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::normalize"),
::tracing_core::field::FieldSet::new(&["result",
"obligations.len"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&result) as
&dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&normalizer.obligations.len()
as &dyn Value))])
});
} else { ; }
};
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/normalize.rs:124",
"rustc_trait_selection::traits::normalize",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/normalize.rs"),
::tracing_core::__macro_support::Option::Some(124u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::normalize"),
::tracing_core::field::FieldSet::new(&["normalizer.obligations"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&normalizer.obligations)
as &dyn Value))])
});
} else { ; }
};
result
}
}
}#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]109pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
110 selcx: &'a mut SelectionContext<'b, 'tcx>,
111 param_env: ty::ParamEnv<'tcx>,
112 cause: ObligationCause<'tcx>,
113 depth: usize,
114 value: T,
115 obligations: &mut PredicateObligations<'tcx>,
116) -> T
117where
118T: TypeFoldable<TyCtxt<'tcx>>,
119{
120debug!(obligations.len = obligations.len());
121let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
122let result = ensure_sufficient_stack(|| AssocTypeNormalizer::fold(&mut normalizer, value));
123debug!(?result, obligations.len = normalizer.obligations.len());
124debug!(?normalizer.obligations,);
125 result
126}
127128pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
129 infcx: &InferCtxt<'tcx>,
130 value: &T,
131) -> bool {
132let mut flags = ty::TypeFlags::HAS_ALIAS;
133134// Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
135 // so we can ignore those.
136match infcx.typing_mode() {
137// FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
138TypingMode::Coherence139 | TypingMode::Analysis { .. }
140 | TypingMode::Borrowck { .. }
141 | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
142TypingMode::PostAnalysis => {}
143 }
144145value.has_type_flags(flags)
146}
147148struct AssocTypeNormalizer<'a, 'b, 'tcx> {
149 selcx: &'a mut SelectionContext<'b, 'tcx>,
150 param_env: ty::ParamEnv<'tcx>,
151 cause: ObligationCause<'tcx>,
152 obligations: &'a mut PredicateObligations<'tcx>,
153 depth: usize,
154 universes: Vec<Option<ty::UniverseIndex>>,
155}
156157impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
158fn new(
159 selcx: &'a mut SelectionContext<'b, 'tcx>,
160 param_env: ty::ParamEnv<'tcx>,
161 cause: ObligationCause<'tcx>,
162 depth: usize,
163 obligations: &'a mut PredicateObligations<'tcx>,
164 ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
165if true {
if !!selcx.infcx.next_trait_solver() {
::core::panicking::panic("assertion failed: !selcx.infcx.next_trait_solver()")
};
};debug_assert!(!selcx.infcx.next_trait_solver());
166AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: ::alloc::vec::Vec::new()vec![] }
167 }
168169fn fold<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
170let value = self.selcx.infcx.resolve_vars_if_possible(value);
171{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/normalize.rs:171",
"rustc_trait_selection::traits::normalize",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/normalize.rs"),
::tracing_core::__macro_support::Option::Some(171u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::normalize"),
::tracing_core::field::FieldSet::new(&["value"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&value) as
&dyn Value))])
});
} else { ; }
};debug!(?value);
172173if !!value.has_escaping_bound_vars() {
{
::core::panicking::panic_fmt(format_args!("Normalizing {0:?} without wrapping in a `Binder`",
value));
}
};assert!(
174 !value.has_escaping_bound_vars(),
175"Normalizing {value:?} without wrapping in a `Binder`"
176);
177178if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) }
179 }
180181// FIXME(mgca): While this supports constants, it is only used for types by default right now
182x;#[instrument(level = "debug", skip(self), ret)]183fn normalize_trait_projection(&mut self, proj: AliasTerm<'tcx>) -> Term<'tcx> {
184if !proj.has_escaping_bound_vars() {
185// When we don't have escaping bound vars we can normalize ambig aliases
186 // to inference variables (done in `normalize_projection_ty`). This would
187 // be wrong if there were escaping bound vars as even if we instantiated
188 // the bound vars with placeholders, we wouldn't be able to map them back
189 // after normalization succeeded.
190 //
191 // Also, as an optimization: when we don't have escaping bound vars, we don't
192 // need to replace them with placeholders (see branch below).
193let proj = proj.fold_with(self);
194 project::normalize_projection_term(
195self.selcx,
196self.param_env,
197 proj,
198self.cause.clone(),
199self.depth,
200self.obligations,
201 )
202 } else {
203// If there are escaping bound vars, we temporarily replace the
204 // bound vars with placeholders. Note though, that in the case
205 // that we still can't project for whatever reason (e.g. self
206 // type isn't known enough), we *can't* register an obligation
207 // and return an inference variable (since then that obligation
208 // would have bound vars and that's a can of worms). Instead,
209 // we just give up and fall back to pretending like we never tried!
210 //
211 // Note: this isn't necessarily the final approach here; we may
212 // want to figure out how to register obligations with escaping vars
213 // or handle this some other way.
214let infcx = self.selcx.infcx;
215let (proj, mapped_regions, mapped_types, mapped_consts) =
216 BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, proj);
217let proj = proj.fold_with(self);
218let normalized_term = project::opt_normalize_projection_term(
219self.selcx,
220self.param_env,
221 proj,
222self.cause.clone(),
223self.depth,
224self.obligations,
225 )
226 .ok()
227 .flatten()
228 .unwrap_or_else(|| proj.to_term(infcx.tcx));
229230 PlaceholderReplacer::replace_placeholders(
231 infcx,
232 mapped_regions,
233 mapped_types,
234 mapped_consts,
235&self.universes,
236 normalized_term,
237 )
238 }
239 }
240241// FIXME(mgca): While this supports constants, it is only used for types by default right now
242x;#[instrument(level = "debug", skip(self), ret)]243fn normalize_inherent_projection(&mut self, inherent: AliasTerm<'tcx>) -> Term<'tcx> {
244if !inherent.has_escaping_bound_vars() {
245// When we don't have escaping bound vars we can normalize ambig aliases
246 // to inference variables (done in `normalize_projection_ty`). This would
247 // be wrong if there were escaping bound vars as even if we instantiated
248 // the bound vars with placeholders, we wouldn't be able to map them back
249 // after normalization succeeded.
250 //
251 // Also, as an optimization: when we don't have escaping bound vars, we don't
252 // need to replace them with placeholders (see branch below).
253254let inherent = inherent.fold_with(self);
255 project::normalize_inherent_projection(
256self.selcx,
257self.param_env,
258 inherent,
259self.cause.clone(),
260self.depth,
261self.obligations,
262 )
263 } else {
264let infcx = self.selcx.infcx;
265let (inherent, mapped_regions, mapped_types, mapped_consts) =
266 BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, inherent);
267let inherent = inherent.fold_with(self);
268let inherent = project::normalize_inherent_projection(
269self.selcx,
270self.param_env,
271 inherent,
272self.cause.clone(),
273self.depth,
274self.obligations,
275 );
276277 PlaceholderReplacer::replace_placeholders(
278 infcx,
279 mapped_regions,
280 mapped_types,
281 mapped_consts,
282&self.universes,
283 inherent,
284 )
285 }
286 }
287288// FIXME(mgca): While this supports constants, it is only used for types by default right now
289x;#[instrument(level = "debug", skip(self), ret)]290fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> {
291let recursion_limit = self.cx().recursion_limit();
292if !recursion_limit.value_within_limit(self.depth) {
293self.selcx.infcx.err_ctxt().report_overflow_error(
294 OverflowCause::DeeplyNormalize(free.into()),
295self.cause.span,
296false,
297 |diag| {
298 diag.note(msg!("in case this is a recursive type alias, consider using a struct, enum, or union instead"));
299 },
300 );
301 }
302303// We don't replace bound vars in the generic arguments of the free alias with
304 // placeholders. This doesn't cause any issues as instantiating parameters with
305 // bound variables is special-cased to rewrite the debruijn index to be higher
306 // whenever we fold through a binder.
307 //
308 // However, we do replace any escaping bound vars in the resulting goals with
309 // placeholders as the trait solver does not expect to encounter escaping bound
310 // vars in obligations.
311 //
312 // FIXME(lazy_type_alias): Check how much this actually matters for perf before
313 // stabilization. This is a bit weird and generally not how we handle binders in
314 // the compiler so ideally we'd do the same boundvar->placeholder->boundvar dance
315 // that other kinds of normalization do.
316let infcx = self.selcx.infcx;
317self.obligations.extend(
318 infcx.tcx.predicates_of(free.def_id).instantiate_own(infcx.tcx, free.args).map(
319 |(mut predicate, span)| {
320if free.has_escaping_bound_vars() {
321 (predicate, ..) = BoundVarReplacer::replace_bound_vars(
322 infcx,
323&mut self.universes,
324 predicate,
325 );
326 }
327let mut cause = self.cause.clone();
328 cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, free.def_id));
329 Obligation::new(infcx.tcx, cause, self.param_env, predicate)
330 },
331 ),
332 );
333self.depth += 1;
334let res = if free.kind(infcx.tcx).is_type() {
335 infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into()
336 } else {
337 infcx
338 .tcx
339 .const_of_item(free.def_id)
340 .instantiate(infcx.tcx, free.args)
341 .fold_with(self)
342 .into()
343 };
344self.depth -= 1;
345 res
346 }
347}
348349impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx> {
350fn cx(&self) -> TyCtxt<'tcx> {
351self.selcx.tcx()
352 }
353354fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
355&mut self,
356 t: ty::Binder<'tcx, T>,
357 ) -> ty::Binder<'tcx, T> {
358self.universes.push(None);
359let t = t.super_fold_with(self);
360self.universes.pop();
361t362 }
363364fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
365if !needs_normalization(self.selcx.infcx, &ty) {
366return ty;
367 }
368369let (kind, data) = match *ty.kind() {
370 ty::Alias(kind, data) => (kind, data),
371_ => return ty.super_fold_with(self),
372 };
373374// We try to be a little clever here as a performance optimization in
375 // cases where there are nested projections under binders.
376 // For example:
377 // ```
378 // for<'a> fn(<T as Foo>::One<'a, Box<dyn Bar<'a, Item=<T as Foo>::Two<'a>>>>)
379 // ```
380 // We normalize the args on the projection before the projecting, but
381 // if we're naive, we'll
382 // replace bound vars on inner, project inner, replace placeholders on inner,
383 // replace bound vars on outer, project outer, replace placeholders on outer
384 //
385 // However, if we're a bit more clever, we can replace the bound vars
386 // on the entire type before normalizing nested projections, meaning we
387 // replace bound vars on outer, project inner,
388 // project outer, replace placeholders on outer
389 //
390 // This is possible because the inner `'a` will already be a placeholder
391 // when we need to normalize the inner projection
392 //
393 // On the other hand, this does add a bit of complexity, since we only
394 // replace bound vars if the current type is a `Projection` and we need
395 // to make sure we don't forget to fold the args regardless.
396397match kind {
398 ty::Opaque => {
399// Only normalize `impl Trait` outside of type inference, usually in codegen.
400match self.selcx.infcx.typing_mode() {
401// FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
402TypingMode::Coherence403 | TypingMode::Analysis { .. }
404 | TypingMode::Borrowck { .. }
405 | TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self),
406TypingMode::PostAnalysis => {
407let recursion_limit = self.cx().recursion_limit();
408if !recursion_limit.value_within_limit(self.depth) {
409self.selcx.infcx.err_ctxt().report_overflow_error(
410 OverflowCause::DeeplyNormalize(data.into()),
411self.cause.span,
412true,
413 |_| {},
414 );
415 }
416417let args = data.args.fold_with(self);
418let generic_ty = self.cx().type_of(data.def_id);
419let concrete_ty = generic_ty.instantiate(self.cx(), args);
420self.depth += 1;
421let folded_ty = self.fold_ty(concrete_ty);
422self.depth -= 1;
423folded_ty424 }
425 }
426 }
427428 ty::Projection => self.normalize_trait_projection(data.into()).expect_type(),
429 ty::Inherent => self.normalize_inherent_projection(data.into()).expect_type(),
430 ty::Free => self.normalize_free_alias(data.into()).expect_type(),
431 }
432 }
433434#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("fold_const",
"rustc_trait_selection::traits::normalize",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/normalize.rs"),
::tracing_core::__macro_support::Option::Some(434u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::normalize"),
::tracing_core::field::FieldSet::new(&["ct"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ct)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: ty::Const<'tcx> = loop {};
return __tracing_attr_fake_return;
}
{
let tcx = self.selcx.tcx();
if tcx.features().generic_const_exprs() &&
!#[allow(non_exhaustive_omitted_patterns)] match ct.kind() {
ty::ConstKind::Unevaluated(uv) if tcx.is_type_const(uv.def)
=> true,
_ => false,
} || !needs_normalization(self.selcx.infcx, &ct) {
return ct;
}
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()).expect_const(),
DefKind::Impl { of_trait: false } => {
self.normalize_inherent_projection(uv.into()).expect_const()
}
kind => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("unexpected `DefKind` for const alias\' resolution\'s parent def: {0:?}",
kind)));
}
},
DefKind::Const =>
self.normalize_free_alias(uv.into()).expect_const(),
DefKind::AnonConst => {
let ct = ct.super_fold_with(self);
super::with_replaced_escaping_bound_vars(self.selcx.infcx,
&mut self.universes, ct,
|ct|
super::evaluate_const(self.selcx.infcx, ct, self.param_env))
}
kind => {
{
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("unexpected `DefKind` for const alias to resolve to: {0:?}",
kind)));
}
}
};
ct.super_fold_with(self)
}
}
}#[instrument(skip(self), level = "debug")]435fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
436let tcx = self.selcx.tcx();
437438if tcx.features().generic_const_exprs()
439// Normalize type_const items even with feature `generic_const_exprs`.
440&& !matches!(ct.kind(), ty::ConstKind::Unevaluated(uv) if tcx.is_type_const(uv.def))
441 || !needs_normalization(self.selcx.infcx, &ct)
442 {
443return ct;
444 }
445446let uv = match ct.kind() {
447 ty::ConstKind::Unevaluated(uv) => uv,
448_ => return ct.super_fold_with(self),
449 };
450451// Note that the AssocConst and Const cases are unreachable on stable,
452 // unless a `min_generic_const_args` feature gate error has already
453 // been emitted earlier in compilation.
454 //
455 // That's because we can only end up with an Unevaluated ty::Const for a const item
456 // if it was marked with `type const`. Using this attribute without the mgca
457 // feature gate causes a parse error.
458let ct = match tcx.def_kind(uv.def) {
459 DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) {
460 DefKind::Trait => self.normalize_trait_projection(uv.into()).expect_const(),
461 DefKind::Impl { of_trait: false } => {
462self.normalize_inherent_projection(uv.into()).expect_const()
463 }
464 kind => unreachable!(
465"unexpected `DefKind` for const alias' resolution's parent def: {:?}",
466 kind
467 ),
468 },
469 DefKind::Const => self.normalize_free_alias(uv.into()).expect_const(),
470 DefKind::AnonConst => {
471let ct = ct.super_fold_with(self);
472super::with_replaced_escaping_bound_vars(
473self.selcx.infcx,
474&mut self.universes,
475 ct,
476 |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env),
477 )
478 }
479 kind => {
480unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind)
481 }
482 };
483484// We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
485 // unnormalized after const evaluation returns.
486ct.super_fold_with(self)
487 }
488489#[inline]
490fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
491if p.allow_normalization() && needs_normalization(self.selcx.infcx, &p) {
492p.super_fold_with(self)
493 } else {
494p495 }
496 }
497}