1//! Deeply normalize types using the old trait solver.
23use rustc_data_structures::stack::ensure_sufficient_stack;
4use rustc_errors::msg;
5use rustc_infer::infer::at::At;
6use rustc_infer::infer::{InferCtxt, InferOk};
7use rustc_infer::traits::{
8FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
9};
10use rustc_macros::extension;
11use rustc_middle::span_bug;
12use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
13use rustc_middle::ty::{
14self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
15TypeVisitableExt, TypingMode, Unnormalized,
16};
17use tracing::{debug, instrument};
1819use super::{BoundVarReplacer, PlaceholderReplacer, SelectionContext, project};
20use crate::error_reporting::InferCtxtErrorExt;
21use crate::error_reporting::traits::OverflowCause;
22use crate::solve::NextSolverError;
2324impl<'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: Unnormalized<'tcx, T>) -> InferOk<'tcx, T> {
if self.infcx.next_trait_solver() {
let Normalized { value, obligations } =
crate::solve::normalize(*self, value);
InferOk { value, obligations }
} 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: Unnormalized<'tcx, 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>)]25impl<'tcx> At<'_, 'tcx> {
26/// Normalize a value using the `AssocTypeNormalizer`.
27 ///
28 /// This normalization should be used when the type contains inference variables or the
29 /// projection may be fallible.
30fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
31&self,
32 value: Unnormalized<'tcx, T>,
33 ) -> InferOk<'tcx, T> {
34if self.infcx.next_trait_solver() {
35let Normalized { value, obligations } = crate::solve::normalize(*self, value);
36InferOk { value, obligations }
37 } else {
38let mut selcx = SelectionContext::new(self.infcx);
39let Normalized { value, obligations } =
40normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
41InferOk { value, obligations }
42 }
43 }
4445/// Deeply normalizes `value`, replacing all aliases which can by normalized in
46 /// the current environment. In the new solver this errors in case normalization
47 /// fails or is ambiguous.
48 ///
49 /// In the old solver this simply uses `normalizes` and adds the nested obligations
50 /// to the `fulfill_cx`. This is necessary as we otherwise end up recomputing the
51 /// same goals in both a temporary and the shared context which negatively impacts
52 /// performance as these don't share caching.
53 ///
54 /// FIXME(-Znext-solver=no): For performance reasons, we currently reuse an existing
55 /// fulfillment context in the old solver. Once we have removed the old solver, we
56 /// can remove the `fulfill_cx` parameter on this function.
57fn deeply_normalize<T, E>(
58self,
59 value: Unnormalized<'tcx, T>,
60 fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
61 ) -> Result<T, Vec<E>>
62where
63T: TypeFoldable<TyCtxt<'tcx>>,
64 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
65 {
66if self.infcx.next_trait_solver() {
67crate::solve::deeply_normalize(self, value)
68 } else {
69if fulfill_cx.has_pending_obligations() {
70let pending_obligations = fulfill_cx.pending_obligations();
71span_bug!(
72 pending_obligations[0].cause.span,
73"deeply_normalize should not be called with pending obligations: \
74 {pending_obligations:#?}"
75);
76 }
77let value = self78 .normalize(value)
79 .into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
80let errors = fulfill_cx.evaluate_obligations_error_on_ambiguity(self.infcx);
81let value = self.infcx.resolve_vars_if_possible(value);
82if errors.is_empty() {
83Ok(value)
84 } else {
85// Drop pending obligations, since deep normalization may happen
86 // in a loop and we don't want to trigger the assertion on the next
87 // iteration due to pending ambiguous obligations we've left over.
88let _ = fulfill_cx.collect_remaining_errors(self.infcx);
89Err(errors)
90 }
91 }
92 }
93}
9495/// As `normalize`, but with a custom depth.
96pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>(
97 selcx: &'a mut SelectionContext<'b, 'tcx>,
98 param_env: ty::ParamEnv<'tcx>,
99 cause: ObligationCause<'tcx>,
100 depth: usize,
101 value: Unnormalized<'tcx, T>,
102) -> Normalized<'tcx, T>
103where
104T: TypeFoldable<TyCtxt<'tcx>>,
105{
106let mut obligations = PredicateObligations::new();
107let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations);
108Normalized { value, obligations }
109}
110111#[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(111u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::normalize"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("depth")
}> =
::tracing::__macro_support::FieldName::new("depth");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("value")
}> =
::tracing::__macro_support::FieldName::new("value");
NAME.as_str()
}], ::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};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&depth
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&value)
as &dyn ::tracing::field::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: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(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("obligations.len")
}> =
::tracing::__macro_support::FieldName::new("obligations.len");
NAME.as_str()
}], ::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&obligations.len()
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
let mut normalizer =
AssocTypeNormalizer::new(selcx, param_env, cause, depth,
obligations);
let result =
ensure_sufficient_stack(||
{
AssocTypeNormalizer::fold(&mut normalizer,
value.skip_normalization())
});
{
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:128",
"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(128u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::normalize"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("result")
}> =
::tracing::__macro_support::FieldName::new("result");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("obligations.len")
}> =
::tracing::__macro_support::FieldName::new("obligations.len");
NAME.as_str()
}], ::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&result)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&normalizer.obligations.len()
as &dyn ::tracing::field::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:129",
"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(129u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::normalize"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("normalizer.obligations")
}> =
::tracing::__macro_support::FieldName::new("normalizer.obligations");
NAME.as_str()
}], ::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&normalizer.obligations)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
result
}
}
}#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]112pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
113 selcx: &'a mut SelectionContext<'b, 'tcx>,
114 param_env: ty::ParamEnv<'tcx>,
115 cause: ObligationCause<'tcx>,
116 depth: usize,
117 value: Unnormalized<'tcx, T>,
118 obligations: &mut PredicateObligations<'tcx>,
119) -> T
120where
121T: TypeFoldable<TyCtxt<'tcx>>,
122{
123debug!(obligations.len = obligations.len());
124let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
125let result = ensure_sufficient_stack(|| {
126 AssocTypeNormalizer::fold(&mut normalizer, value.skip_normalization())
127 });
128debug!(?result, obligations.len = normalizer.obligations.len());
129debug!(?normalizer.obligations,);
130 result
131}
132133pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
134 infcx: &InferCtxt<'tcx>,
135 value: &T,
136) -> bool {
137let mut flags = ty::TypeFlags::HAS_ALIAS;
138139// Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
140 // so we can ignore those.
141match infcx.typing_mode_raw().assert_not_erased() {
142// FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
143TypingMode::Coherence144 | TypingMode::Typeck { .. }
145 | TypingMode::PostTypeckUntilBorrowck { .. }
146 | TypingMode::PostBorrowck { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
147TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => {}
148 }
149150value.has_type_flags(flags)
151}
152153struct AssocTypeNormalizer<'a, 'b, 'tcx> {
154 selcx: &'a mut SelectionContext<'b, 'tcx>,
155 param_env: ty::ParamEnv<'tcx>,
156 cause: ObligationCause<'tcx>,
157 obligations: &'a mut PredicateObligations<'tcx>,
158 depth: usize,
159 universes: Vec<Option<ty::UniverseIndex>>,
160}
161162impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
163fn new(
164 selcx: &'a mut SelectionContext<'b, 'tcx>,
165 param_env: ty::ParamEnv<'tcx>,
166 cause: ObligationCause<'tcx>,
167 depth: usize,
168 obligations: &'a mut PredicateObligations<'tcx>,
169 ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
170if true {
if !!selcx.infcx.next_trait_solver() {
::core::panicking::panic("assertion failed: !selcx.infcx.next_trait_solver()")
};
};debug_assert!(!selcx.infcx.next_trait_solver());
171AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: ::alloc::vec::Vec::new()vec![] }
172 }
173174fn fold<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
175let value = self.selcx.infcx.resolve_vars_if_possible(value);
176{
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:176",
"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(176u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::normalize"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("value")
}> =
::tracing::__macro_support::FieldName::new("value");
NAME.as_str()
}], ::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&value)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(?value);
177178if !!value.has_escaping_bound_vars() {
{
::core::panicking::panic_fmt(format_args!("Normalizing {0:?} without wrapping in a `Binder`",
value));
}
};assert!(
179 !value.has_escaping_bound_vars(),
180"Normalizing {value:?} without wrapping in a `Binder`"
181);
182183if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) }
184 }
185186// FIXME(mgca): While this supports constants, it is only used for types by default right now
187x;#[instrument(level = "debug", skip(self), ret)]188fn normalize_trait_projection(&mut self, proj: AliasTerm<'tcx>) -> Term<'tcx> {
189if !proj.has_escaping_bound_vars() {
190// When we don't have escaping bound vars we can normalize ambig aliases
191 // to inference variables (done in `normalize_projection_ty`). This would
192 // be wrong if there were escaping bound vars as even if we instantiated
193 // the bound vars with placeholders, we wouldn't be able to map them back
194 // after normalization succeeded.
195 //
196 // Also, as an optimization: when we don't have escaping bound vars, we don't
197 // need to replace them with placeholders (see branch below).
198let proj = proj.fold_with(self);
199 project::normalize_projection_term(
200self.selcx,
201self.param_env,
202 proj,
203self.cause.clone(),
204self.depth,
205self.obligations,
206 )
207 } else {
208// If there are escaping bound vars, we temporarily replace the
209 // bound vars with placeholders. Note though, that in the case
210 // that we still can't project for whatever reason (e.g. self
211 // type isn't known enough), we *can't* register an obligation
212 // and return an inference variable (since then that obligation
213 // would have bound vars and that's a can of worms). Instead,
214 // we just give up and fall back to pretending like we never tried!
215 //
216 // Note: this isn't necessarily the final approach here; we may
217 // want to figure out how to register obligations with escaping vars
218 // or handle this some other way.
219let infcx = self.selcx.infcx;
220let (proj, mapped_regions, mapped_types, mapped_consts) =
221 BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, proj);
222let proj = proj.fold_with(self);
223let normalized_term = project::opt_normalize_projection_term(
224self.selcx,
225self.param_env,
226 proj,
227self.cause.clone(),
228self.depth,
229self.obligations,
230 )
231 .ok()
232 .flatten()
233 .unwrap_or_else(|| proj.to_term(infcx.tcx, ty::IsRigid::No));
234235 PlaceholderReplacer::replace_placeholders(
236 infcx,
237 mapped_regions,
238 mapped_types,
239 mapped_consts,
240&self.universes,
241 normalized_term,
242 )
243 }
244 }
245246// FIXME(mgca): While this supports constants, it is only used for types by default right now
247x;#[instrument(level = "debug", skip(self), ret)]248fn normalize_inherent_projection(&mut self, inherent: AliasTerm<'tcx>) -> Term<'tcx> {
249if !inherent.has_escaping_bound_vars() {
250// When we don't have escaping bound vars we can normalize ambig aliases
251 // to inference variables (done in `normalize_projection_ty`). This would
252 // be wrong if there were escaping bound vars as even if we instantiated
253 // the bound vars with placeholders, we wouldn't be able to map them back
254 // after normalization succeeded.
255 //
256 // Also, as an optimization: when we don't have escaping bound vars, we don't
257 // need to replace them with placeholders (see branch below).
258259let inherent = inherent.fold_with(self);
260 project::normalize_inherent_projection(
261self.selcx,
262self.param_env,
263 inherent,
264self.cause.clone(),
265self.depth,
266self.obligations,
267 )
268 } else {
269let infcx = self.selcx.infcx;
270let (inherent, mapped_regions, mapped_types, mapped_consts) =
271 BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, inherent);
272let inherent = inherent.fold_with(self);
273let inherent = project::normalize_inherent_projection(
274self.selcx,
275self.param_env,
276 inherent,
277self.cause.clone(),
278self.depth,
279self.obligations,
280 );
281282 PlaceholderReplacer::replace_placeholders(
283 infcx,
284 mapped_regions,
285 mapped_types,
286 mapped_consts,
287&self.universes,
288 inherent,
289 )
290 }
291 }
292293// FIXME(mgca): While this supports constants, it is only used for types by default right now
294x;#[instrument(level = "debug", skip(self), ret)]295fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> {
296let recursion_limit = self.cx().recursion_limit();
297if !recursion_limit.value_within_limit(self.depth) {
298self.selcx.infcx.err_ctxt().report_overflow_error(
299 OverflowCause::DeeplyNormalize(free),
300self.cause.span,
301false,
302 |diag| {
303 diag.note(msg!("in case this is a recursive type alias, consider using a struct, enum, or union instead"));
304 },
305 );
306 }
307308let def_id = free.expect_free_def_id();
309310// We don't replace bound vars in the generic arguments of the free alias with
311 // placeholders. This doesn't cause any issues as instantiating parameters with
312 // bound variables is special-cased to rewrite the debruijn index to be higher
313 // whenever we fold through a binder.
314 //
315 // However, we do replace any escaping bound vars in the resulting goals with
316 // placeholders as the trait solver does not expect to encounter escaping bound
317 // vars in obligations.
318 //
319 // FIXME(checked_type_alias): Check how much this actually matters for perf before
320 // stabilization. This is a bit weird and generally not how we handle binders in
321 // the compiler so ideally we'd do the same boundvar->placeholder->boundvar dance
322 // that other kinds of normalization do.
323let infcx = self.selcx.infcx;
324self.obligations.extend(
325 infcx
326 .tcx
327 .clauses_of(def_id)
328 .instantiate_own(infcx.tcx, free.args)
329 .map(|(clause, span)| (clause.skip_norm_wip(), span))
330 .map(|(mut clause, span)| {
331if free.has_escaping_bound_vars() {
332 (clause, ..) = BoundVarReplacer::replace_bound_vars(
333 infcx,
334&mut self.universes,
335 clause,
336 );
337 }
338let mut cause = self.cause.clone();
339 cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, def_id));
340 Obligation::new(infcx.tcx, cause, self.param_env, clause)
341 }),
342 );
343self.depth += 1;
344let res: ty::Term<'tcx> = if free.kind.is_type() {
345 infcx
346 .tcx
347 .type_of(def_id)
348 .instantiate(infcx.tcx, free.args)
349 .skip_norm_wip()
350 .fold_with(self)
351 .into()
352 } else {
353 infcx
354 .tcx
355 .const_of_item(def_id)
356 .instantiate(infcx.tcx, free.args)
357 .skip_norm_wip()
358 .fold_with(self)
359 .into()
360 };
361// When normalizing a free const alias, register a `ConstArgHasType`
362 // obligation to ensure the const value's type matches the declared type.
363if let Some(ct) = res.as_const() {
364let expected_ty =
365 infcx.tcx.type_of(def_id).instantiate(infcx.tcx, free.args).skip_norm_wip();
366self.obligations.push(Obligation::with_depth(
367 infcx.tcx,
368self.cause.clone(),
369self.depth,
370self.param_env,
371 ty::ClauseKind::ConstArgHasType(ct, expected_ty),
372 ));
373 }
374self.depth -= 1;
375 res
376 }
377}
378379impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx> {
380fn cx(&self) -> TyCtxt<'tcx> {
381self.selcx.tcx()
382 }
383384fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
385&mut self,
386 t: ty::Binder<'tcx, T>,
387 ) -> ty::Binder<'tcx, T> {
388self.universes.push(None);
389let t = t.super_fold_with(self);
390self.universes.pop();
391t392 }
393394fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
395// We don't use the rigid marker in old solver.
396if true {
if !!ty.has_rigid_aliases() {
::core::panicking::panic("assertion failed: !ty.has_rigid_aliases()")
};
};debug_assert!(!ty.has_rigid_aliases());
397398if !needs_normalization(self.selcx.infcx, &ty) {
399return ty;
400 }
401402let ty::Alias(_, data) = *ty.kind() else { return ty.super_fold_with(self) };
403404// We try to be a little clever here as a performance optimization in
405 // cases where there are nested projections under binders.
406 // For example:
407 // ```
408 // for<'a> fn(<T as Foo>::One<'a, Box<dyn Bar<'a, Item=<T as Foo>::Two<'a>>>>)
409 // ```
410 // We normalize the args on the projection before the projecting, but
411 // if we're naive, we'll
412 // replace bound vars on inner, project inner, replace placeholders on inner,
413 // replace bound vars on outer, project outer, replace placeholders on outer
414 //
415 // However, if we're a bit more clever, we can replace the bound vars
416 // on the entire type before normalizing nested projections, meaning we
417 // replace bound vars on outer, project inner,
418 // project outer, replace placeholders on outer
419 //
420 // This is possible because the inner `'a` will already be a placeholder
421 // when we need to normalize the inner projection
422 //
423 // On the other hand, this does add a bit of complexity, since we only
424 // replace bound vars if the current type is a `Projection` and we need
425 // to make sure we don't forget to fold the args regardless.
426427match data.kind {
428 ty::Opaque { def_id } => {
429// Only normalize `impl Trait` outside of type inference, usually in codegen.
430match self.selcx.typing_mode() {
431// FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
432TypingMode::Coherence433 | TypingMode::Typeck { .. }
434 | TypingMode::PostTypeckUntilBorrowck { .. }
435 | TypingMode::PostBorrowck { .. } => ty.super_fold_with(self),
436TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => {
437let recursion_limit = self.cx().recursion_limit();
438if !recursion_limit.value_within_limit(self.depth) {
439self.selcx.infcx.err_ctxt().report_overflow_error(
440 OverflowCause::DeeplyNormalize(data.into()),
441self.cause.span,
442true,
443 |_| {},
444 );
445 }
446447let args = data.args.fold_with(self);
448let generic_ty = self.cx().type_of(def_id);
449let concrete_ty = generic_ty.instantiate(self.cx(), args).skip_norm_wip();
450self.depth += 1;
451let folded_ty = self.fold_ty(concrete_ty);
452self.depth -= 1;
453folded_ty454 }
455 }
456 }
457458 ty::Projection { .. } => self.normalize_trait_projection(data.into()).expect_type(),
459 ty::Inherent { .. } => self.normalize_inherent_projection(data.into()).expect_type(),
460 ty::Free { .. } => self.normalize_free_alias(data.into()).expect_type(),
461 }
462 }
463464#[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(464u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::normalize"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("ct")
}> =
::tracing::__macro_support::FieldName::new("ct");
NAME.as_str()
}], ::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};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ct)
as &dyn ::tracing::field::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;
}
{
if true {
if !!ct.has_rigid_aliases() {
::core::panicking::panic("assertion failed: !ct.has_rigid_aliases()")
};
};
let tcx = self.selcx.tcx();
if tcx.features().generic_const_exprs() &&
!#[allow(non_exhaustive_omitted_patterns)] match ct.kind() {
ty::ConstKind::Alias(_, alias_const) if
alias_const.kind.is_type_const(tcx) => true,
_ => false,
} || !needs_normalization(self.selcx.infcx, &ct) {
return ct;
}
let alias_const =
match ct.kind() {
ty::ConstKind::Alias(_, alias_const) => alias_const,
_ => return ct.super_fold_with(self),
};
let ct =
match alias_const.kind {
ty::AliasConstKind::Projection { .. } => {
self.normalize_trait_projection(alias_const.into()).expect_const()
}
ty::AliasConstKind::Inherent { .. } => {
self.normalize_inherent_projection(alias_const.into()).expect_const()
}
ty::AliasConstKind::Free { .. } => {
self.normalize_free_alias(alias_const.into()).expect_const()
}
ty::AliasConstKind::Anon { .. } => {
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))
}
};
ct.super_fold_with(self)
}
}
}#[instrument(skip(self), level = "debug")]465fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
466// We don't use the rigid marker in old solver.
467debug_assert!(!ct.has_rigid_aliases());
468469let tcx = self.selcx.tcx();
470471if tcx.features().generic_const_exprs()
472// Normalize type_const items even with feature `generic_const_exprs`.
473&& !matches!(ct.kind(), ty::ConstKind::Alias(_, alias_const) if alias_const.kind.is_type_const(tcx))
474 || !needs_normalization(self.selcx.infcx, &ct)
475 {
476return ct;
477 }
478479let alias_const = match ct.kind() {
480 ty::ConstKind::Alias(_, alias_const) => alias_const,
481_ => return ct.super_fold_with(self),
482 };
483484// Note that the Projection/Inherent/Free cases are unreachable on stable,
485 // unless a `min_generic_const_args` feature gate error has already
486 // been emitted earlier in compilation.
487 //
488 // That's because we can only end up with an Alias ty::Const for a const item
489 // if it was marked with `type const`. Using this attribute without the mgca
490 // feature gate causes a parse error.
491let ct = match alias_const.kind {
492 ty::AliasConstKind::Projection { .. } => {
493self.normalize_trait_projection(alias_const.into()).expect_const()
494 }
495 ty::AliasConstKind::Inherent { .. } => {
496self.normalize_inherent_projection(alias_const.into()).expect_const()
497 }
498 ty::AliasConstKind::Free { .. } => {
499self.normalize_free_alias(alias_const.into()).expect_const()
500 }
501 ty::AliasConstKind::Anon { .. } => {
502let ct = ct.super_fold_with(self);
503super::with_replaced_escaping_bound_vars(
504self.selcx.infcx,
505&mut self.universes,
506 ct,
507 |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env),
508 )
509 }
510 };
511512// We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
513 // unnormalized after const evaluation returns.
514ct.super_fold_with(self)
515 }
516517#[inline]
518fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
519if p.allow_normalization() && needs_normalization(self.selcx.infcx, &p) {
520p.super_fold_with(self)
521 } else {
522p523 }
524 }
525}