rustc_trait_selection/traits/
normalize.rs
1use rustc_data_structures::stack::ensure_sufficient_stack;
4use rustc_infer::infer::at::At;
5use rustc_infer::infer::{InferCtxt, InferOk};
6use rustc_infer::traits::{
7 FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
8};
9use rustc_macros::extension;
10use rustc_middle::span_bug;
11use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
12use rustc_middle::ty::{
13 self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt,
14 TypingMode,
15};
16use tracing::{debug, instrument};
17
18use super::{
19 BoundVarReplacer, PlaceholderReplacer, SelectionContext, project,
20 with_replaced_escaping_bound_vars,
21};
22use crate::error_reporting::InferCtxtErrorExt;
23use crate::error_reporting::traits::OverflowCause;
24use crate::solve::NextSolverError;
25
26#[extension(pub trait NormalizeExt<'tcx>)]
27impl<'tcx> At<'_, 'tcx> {
28 fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
33 if self.infcx.next_trait_solver() {
34 InferOk { value, obligations: PredicateObligations::new() }
35 } else {
36 let mut selcx = SelectionContext::new(self.infcx);
37 let Normalized { value, obligations } =
38 normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
39 InferOk { value, obligations }
40 }
41 }
42
43 fn deeply_normalize<T, E>(
56 self,
57 value: T,
58 fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
59 ) -> Result<T, Vec<E>>
60 where
61 T: TypeFoldable<TyCtxt<'tcx>>,
62 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
63 {
64 if self.infcx.next_trait_solver() {
65 crate::solve::deeply_normalize(self, value)
66 } else {
67 if fulfill_cx.has_pending_obligations() {
68 let pending_obligations = fulfill_cx.pending_obligations();
69 span_bug!(
70 pending_obligations[0].cause.span,
71 "deeply_normalize should not be called with pending obligations: \
72 {pending_obligations:#?}"
73 );
74 }
75 let value = self
76 .normalize(value)
77 .into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
78 let errors = fulfill_cx.select_all_or_error(self.infcx);
79 let value = self.infcx.resolve_vars_if_possible(value);
80 if errors.is_empty() { Ok(value) } else { Err(errors) }
81 }
82 }
83}
84
85pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>(
87 selcx: &'a mut SelectionContext<'b, 'tcx>,
88 param_env: ty::ParamEnv<'tcx>,
89 cause: ObligationCause<'tcx>,
90 depth: usize,
91 value: T,
92) -> Normalized<'tcx, T>
93where
94 T: TypeFoldable<TyCtxt<'tcx>>,
95{
96 let mut obligations = PredicateObligations::new();
97 let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations);
98 Normalized { value, obligations }
99}
100
101#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
102pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
103 selcx: &'a mut SelectionContext<'b, 'tcx>,
104 param_env: ty::ParamEnv<'tcx>,
105 cause: ObligationCause<'tcx>,
106 depth: usize,
107 value: T,
108 obligations: &mut PredicateObligations<'tcx>,
109) -> T
110where
111 T: TypeFoldable<TyCtxt<'tcx>>,
112{
113 debug!(obligations.len = obligations.len());
114 let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
115 let result = ensure_sufficient_stack(|| AssocTypeNormalizer::fold(&mut normalizer, value));
116 debug!(?result, obligations.len = normalizer.obligations.len());
117 debug!(?normalizer.obligations,);
118 result
119}
120
121pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
122 infcx: &InferCtxt<'tcx>,
123 value: &T,
124) -> bool {
125 let mut flags = ty::TypeFlags::HAS_ALIAS;
126
127 match infcx.typing_mode() {
130 TypingMode::Coherence
132 | TypingMode::Analysis { .. }
133 | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
134 TypingMode::PostAnalysis => {}
135 }
136
137 value.has_type_flags(flags)
138}
139
140struct AssocTypeNormalizer<'a, 'b, 'tcx> {
141 selcx: &'a mut SelectionContext<'b, 'tcx>,
142 param_env: ty::ParamEnv<'tcx>,
143 cause: ObligationCause<'tcx>,
144 obligations: &'a mut PredicateObligations<'tcx>,
145 depth: usize,
146 universes: Vec<Option<ty::UniverseIndex>>,
147}
148
149impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
150 fn new(
151 selcx: &'a mut SelectionContext<'b, 'tcx>,
152 param_env: ty::ParamEnv<'tcx>,
153 cause: ObligationCause<'tcx>,
154 depth: usize,
155 obligations: &'a mut PredicateObligations<'tcx>,
156 ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
157 debug_assert!(!selcx.infcx.next_trait_solver());
158 AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] }
159 }
160
161 fn fold<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
162 let value = self.selcx.infcx.resolve_vars_if_possible(value);
163 debug!(?value);
164
165 assert!(
166 !value.has_escaping_bound_vars(),
167 "Normalizing {value:?} without wrapping in a `Binder`"
168 );
169
170 if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) }
171 }
172}
173
174impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx> {
175 fn cx(&self) -> TyCtxt<'tcx> {
176 self.selcx.tcx()
177 }
178
179 fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
180 &mut self,
181 t: ty::Binder<'tcx, T>,
182 ) -> ty::Binder<'tcx, T> {
183 self.universes.push(None);
184 let t = t.super_fold_with(self);
185 self.universes.pop();
186 t
187 }
188
189 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
190 if !needs_normalization(self.selcx.infcx, &ty) {
191 return ty;
192 }
193
194 let (kind, data) = match *ty.kind() {
195 ty::Alias(kind, data) => (kind, data),
196 _ => return ty.super_fold_with(self),
197 };
198
199 match kind {
223 ty::Opaque => {
224 match self.selcx.infcx.typing_mode() {
226 TypingMode::Coherence
228 | TypingMode::Analysis { .. }
229 | TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self),
230 TypingMode::PostAnalysis => {
231 let recursion_limit = self.cx().recursion_limit();
232 if !recursion_limit.value_within_limit(self.depth) {
233 self.selcx.infcx.err_ctxt().report_overflow_error(
234 OverflowCause::DeeplyNormalize(data.into()),
235 self.cause.span,
236 true,
237 |_| {},
238 );
239 }
240
241 let args = data.args.fold_with(self);
242 let generic_ty = self.cx().type_of(data.def_id);
243 let concrete_ty = generic_ty.instantiate(self.cx(), args);
244 self.depth += 1;
245 let folded_ty = self.fold_ty(concrete_ty);
246 self.depth -= 1;
247 folded_ty
248 }
249 }
250 }
251
252 ty::Projection if !data.has_escaping_bound_vars() => {
253 let data = data.fold_with(self);
259 let normalized_ty = project::normalize_projection_ty(
260 self.selcx,
261 self.param_env,
262 data,
263 self.cause.clone(),
264 self.depth,
265 self.obligations,
266 );
267 debug!(
268 ?self.depth,
269 ?ty,
270 ?normalized_ty,
271 obligations.len = ?self.obligations.len(),
272 "AssocTypeNormalizer: normalized type"
273 );
274 normalized_ty.expect_type()
275 }
276
277 ty::Projection => {
278 let infcx = self.selcx.infcx;
291 let (data, mapped_regions, mapped_types, mapped_consts) =
292 BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
293 let data = data.fold_with(self);
294 let normalized_ty = project::opt_normalize_projection_term(
295 self.selcx,
296 self.param_env,
297 data.into(),
298 self.cause.clone(),
299 self.depth,
300 self.obligations,
301 )
302 .ok()
303 .flatten()
304 .map(|term| term.expect_type())
305 .map(|normalized_ty| {
306 PlaceholderReplacer::replace_placeholders(
307 infcx,
308 mapped_regions,
309 mapped_types,
310 mapped_consts,
311 &self.universes,
312 normalized_ty,
313 )
314 })
315 .unwrap_or_else(|| ty.super_fold_with(self));
316
317 debug!(
318 ?self.depth,
319 ?ty,
320 ?normalized_ty,
321 obligations.len = ?self.obligations.len(),
322 "AssocTypeNormalizer: normalized type"
323 );
324 normalized_ty
325 }
326 ty::Weak => {
327 let recursion_limit = self.cx().recursion_limit();
328 if !recursion_limit.value_within_limit(self.depth) {
329 self.selcx.infcx.err_ctxt().report_overflow_error(
330 OverflowCause::DeeplyNormalize(data.into()),
331 self.cause.span,
332 false,
333 |diag| {
334 diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow);
335 },
336 );
337 }
338
339 let infcx = self.selcx.infcx;
340 self.obligations.extend(
341 infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map(
342 |(mut predicate, span)| {
343 if data.has_escaping_bound_vars() {
344 (predicate, ..) = BoundVarReplacer::replace_bound_vars(
345 infcx,
346 &mut self.universes,
347 predicate,
348 );
349 }
350 let mut cause = self.cause.clone();
351 cause.map_code(|code| {
352 ObligationCauseCode::TypeAlias(code, span, data.def_id)
353 });
354 Obligation::new(infcx.tcx, cause, self.param_env, predicate)
355 },
356 ),
357 );
358 self.depth += 1;
359 let res = infcx
360 .tcx
361 .type_of(data.def_id)
362 .instantiate(infcx.tcx, data.args)
363 .fold_with(self);
364 self.depth -= 1;
365 res
366 }
367
368 ty::Inherent if !data.has_escaping_bound_vars() => {
369 let data = data.fold_with(self);
376
377 project::normalize_inherent_projection(
378 self.selcx,
379 self.param_env,
380 data,
381 self.cause.clone(),
382 self.depth,
383 self.obligations,
384 )
385 }
386
387 ty::Inherent => {
388 let infcx = self.selcx.infcx;
389 let (data, mapped_regions, mapped_types, mapped_consts) =
390 BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
391 let data = data.fold_with(self);
392 let ty = project::normalize_inherent_projection(
393 self.selcx,
394 self.param_env,
395 data,
396 self.cause.clone(),
397 self.depth,
398 self.obligations,
399 );
400
401 PlaceholderReplacer::replace_placeholders(
402 infcx,
403 mapped_regions,
404 mapped_types,
405 mapped_consts,
406 &self.universes,
407 ty,
408 )
409 }
410 }
411 }
412
413 #[instrument(skip(self), level = "debug")]
414 fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
415 let tcx = self.selcx.tcx();
416 if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &constant)
417 {
418 constant
419 } else {
420 let constant = constant.super_fold_with(self);
421 debug!(?constant, ?self.param_env);
422 with_replaced_escaping_bound_vars(
423 self.selcx.infcx,
424 &mut self.universes,
425 constant,
426 |constant| super::evaluate_const(self.selcx.infcx, constant, self.param_env),
427 )
428 .super_fold_with(self)
429 }
430 }
431
432 #[inline]
433 fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
434 if p.allow_normalization() && needs_normalization(self.selcx.infcx, &p) {
435 p.super_fold_with(self)
436 } else {
437 p
438 }
439 }
440}