rustc_trait_selection/traits/
normalize.rs

1//! Deeply normalize types using the old trait solver.
2
3use rustc_data_structures::stack::ensure_sufficient_stack;
4use rustc_hir::def::DefKind;
5use rustc_infer::infer::at::At;
6use rustc_infer::infer::{InferCtxt, InferOk};
7use rustc_infer::traits::{
8    FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
9};
10use rustc_macros::extension;
11use rustc_middle::span_bug;
12use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
13use rustc_middle::ty::{
14    self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
15    TypeVisitableExt, TypingMode,
16};
17use tracing::{debug, instrument};
18
19use super::{BoundVarReplacer, PlaceholderReplacer, SelectionContext, project};
20use crate::error_reporting::InferCtxtErrorExt;
21use crate::error_reporting::traits::OverflowCause;
22use crate::solve::NextSolverError;
23
24#[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.
30    fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
31        if self.infcx.next_trait_solver() {
32            InferOk { value, obligations: PredicateObligations::new() }
33        } else {
34            let mut selcx = SelectionContext::new(self.infcx);
35            let Normalized { value, obligations } =
36                normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
37            InferOk { value, obligations }
38        }
39    }
40
41    /// Deeply normalizes `value`, replacing all aliases which can by normalized in
42    /// the current environment. In the new solver this errors in case normalization
43    /// fails or is ambiguous.
44    ///
45    /// In the old solver this simply uses `normalizes` and adds the nested obligations
46    /// to the `fulfill_cx`. This is necessary as we otherwise end up recomputing the
47    /// same goals in both a temporary and the shared context which negatively impacts
48    /// performance as these don't share caching.
49    ///
50    /// FIXME(-Znext-solver): For performance reasons, we currently reuse an existing
51    /// fulfillment context in the old solver. Once we have removed the old solver, we
52    /// can remove the `fulfill_cx` parameter on this function.
53    fn deeply_normalize<T, E>(
54        self,
55        value: T,
56        fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
57    ) -> Result<T, Vec<E>>
58    where
59        T: TypeFoldable<TyCtxt<'tcx>>,
60        E: FromSolverError<'tcx, NextSolverError<'tcx>>,
61    {
62        if self.infcx.next_trait_solver() {
63            crate::solve::deeply_normalize(self, value)
64        } else {
65            if fulfill_cx.has_pending_obligations() {
66                let pending_obligations = fulfill_cx.pending_obligations();
67                span_bug!(
68                    pending_obligations[0].cause.span,
69                    "deeply_normalize should not be called with pending obligations: \
70                    {pending_obligations:#?}"
71                );
72            }
73            let value = self
74                .normalize(value)
75                .into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
76            let errors = fulfill_cx.select_all_or_error(self.infcx);
77            let value = self.infcx.resolve_vars_if_possible(value);
78            if errors.is_empty() {
79                Ok(value)
80            } else {
81                // Drop pending obligations, since deep normalization may happen
82                // in a loop and we don't want to trigger the assertion on the next
83                // iteration due to pending ambiguous obligations we've left over.
84                let _ = fulfill_cx.collect_remaining_errors(self.infcx);
85                Err(errors)
86            }
87        }
88    }
89}
90
91/// As `normalize`, but with a custom depth.
92pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>(
93    selcx: &'a mut SelectionContext<'b, 'tcx>,
94    param_env: ty::ParamEnv<'tcx>,
95    cause: ObligationCause<'tcx>,
96    depth: usize,
97    value: T,
98) -> Normalized<'tcx, T>
99where
100    T: TypeFoldable<TyCtxt<'tcx>>,
101{
102    let mut obligations = PredicateObligations::new();
103    let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations);
104    Normalized { value, obligations }
105}
106
107#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
108pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
109    selcx: &'a mut SelectionContext<'b, 'tcx>,
110    param_env: ty::ParamEnv<'tcx>,
111    cause: ObligationCause<'tcx>,
112    depth: usize,
113    value: T,
114    obligations: &mut PredicateObligations<'tcx>,
115) -> T
116where
117    T: TypeFoldable<TyCtxt<'tcx>>,
118{
119    debug!(obligations.len = obligations.len());
120    let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
121    let result = ensure_sufficient_stack(|| AssocTypeNormalizer::fold(&mut normalizer, value));
122    debug!(?result, obligations.len = normalizer.obligations.len());
123    debug!(?normalizer.obligations,);
124    result
125}
126
127pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
128    infcx: &InferCtxt<'tcx>,
129    value: &T,
130) -> bool {
131    let mut flags = ty::TypeFlags::HAS_ALIAS;
132
133    // Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
134    // so we can ignore those.
135    match infcx.typing_mode() {
136        // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
137        TypingMode::Coherence
138        | TypingMode::Analysis { .. }
139        | TypingMode::Borrowck { .. }
140        | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
141        TypingMode::PostAnalysis => {}
142    }
143
144    value.has_type_flags(flags)
145}
146
147struct AssocTypeNormalizer<'a, 'b, 'tcx> {
148    selcx: &'a mut SelectionContext<'b, 'tcx>,
149    param_env: ty::ParamEnv<'tcx>,
150    cause: ObligationCause<'tcx>,
151    obligations: &'a mut PredicateObligations<'tcx>,
152    depth: usize,
153    universes: Vec<Option<ty::UniverseIndex>>,
154}
155
156impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
157    fn new(
158        selcx: &'a mut SelectionContext<'b, 'tcx>,
159        param_env: ty::ParamEnv<'tcx>,
160        cause: ObligationCause<'tcx>,
161        depth: usize,
162        obligations: &'a mut PredicateObligations<'tcx>,
163    ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
164        debug_assert!(!selcx.infcx.next_trait_solver());
165        AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] }
166    }
167
168    fn fold<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
169        let value = self.selcx.infcx.resolve_vars_if_possible(value);
170        debug!(?value);
171
172        assert!(
173            !value.has_escaping_bound_vars(),
174            "Normalizing {value:?} without wrapping in a `Binder`"
175        );
176
177        if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) }
178    }
179
180    // FIXME(mgca): While this supports constants, it is only used for types by default right now
181    #[instrument(level = "debug", skip(self), ret)]
182    fn normalize_trait_projection(&mut self, proj: AliasTerm<'tcx>) -> Term<'tcx> {
183        if !proj.has_escaping_bound_vars() {
184            // When we don't have escaping bound vars we can normalize ambig aliases
185            // to inference variables (done in `normalize_projection_ty`). This would
186            // be wrong if there were escaping bound vars as even if we instantiated
187            // the bound vars with placeholders, we wouldn't be able to map them back
188            // after normalization succeeded.
189            //
190            // Also, as an optimization: when we don't have escaping bound vars, we don't
191            // need to replace them with placeholders (see branch below).
192            let proj = proj.fold_with(self);
193            project::normalize_projection_term(
194                self.selcx,
195                self.param_env,
196                proj,
197                self.cause.clone(),
198                self.depth,
199                self.obligations,
200            )
201        } else {
202            // If there are escaping bound vars, we temporarily replace the
203            // bound vars with placeholders. Note though, that in the case
204            // that we still can't project for whatever reason (e.g. self
205            // type isn't known enough), we *can't* register an obligation
206            // and return an inference variable (since then that obligation
207            // would have bound vars and that's a can of worms). Instead,
208            // we just give up and fall back to pretending like we never tried!
209            //
210            // Note: this isn't necessarily the final approach here; we may
211            // want to figure out how to register obligations with escaping vars
212            // or handle this some other way.
213            let infcx = self.selcx.infcx;
214            let (proj, mapped_regions, mapped_types, mapped_consts) =
215                BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, proj);
216            let proj = proj.fold_with(self);
217            let normalized_term = project::opt_normalize_projection_term(
218                self.selcx,
219                self.param_env,
220                proj,
221                self.cause.clone(),
222                self.depth,
223                self.obligations,
224            )
225            .ok()
226            .flatten()
227            .unwrap_or(proj.to_term(infcx.tcx));
228
229            PlaceholderReplacer::replace_placeholders(
230                infcx,
231                mapped_regions,
232                mapped_types,
233                mapped_consts,
234                &self.universes,
235                normalized_term,
236            )
237        }
238    }
239
240    // FIXME(mgca): While this supports constants, it is only used for types by default right now
241    #[instrument(level = "debug", skip(self), ret)]
242    fn normalize_inherent_projection(&mut self, inherent: AliasTerm<'tcx>) -> Term<'tcx> {
243        if !inherent.has_escaping_bound_vars() {
244            // When we don't have escaping bound vars we can normalize ambig aliases
245            // to inference variables (done in `normalize_projection_ty`). This would
246            // be wrong if there were escaping bound vars as even if we instantiated
247            // the bound vars with placeholders, we wouldn't be able to map them back
248            // after normalization succeeded.
249            //
250            // Also, as an optimization: when we don't have escaping bound vars, we don't
251            // need to replace them with placeholders (see branch below).
252
253            let inherent = inherent.fold_with(self);
254            project::normalize_inherent_projection(
255                self.selcx,
256                self.param_env,
257                inherent,
258                self.cause.clone(),
259                self.depth,
260                self.obligations,
261            )
262        } else {
263            let infcx = self.selcx.infcx;
264            let (inherent, mapped_regions, mapped_types, mapped_consts) =
265                BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, inherent);
266            let inherent = inherent.fold_with(self);
267            let inherent = project::normalize_inherent_projection(
268                self.selcx,
269                self.param_env,
270                inherent,
271                self.cause.clone(),
272                self.depth,
273                self.obligations,
274            );
275
276            PlaceholderReplacer::replace_placeholders(
277                infcx,
278                mapped_regions,
279                mapped_types,
280                mapped_consts,
281                &self.universes,
282                inherent,
283            )
284        }
285    }
286
287    // FIXME(mgca): While this supports constants, it is only used for types by default right now
288    #[instrument(level = "debug", skip(self), ret)]
289    fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> {
290        let recursion_limit = self.cx().recursion_limit();
291        if !recursion_limit.value_within_limit(self.depth) {
292            self.selcx.infcx.err_ctxt().report_overflow_error(
293                OverflowCause::DeeplyNormalize(free.into()),
294                self.cause.span,
295                false,
296                |diag| {
297                    diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow);
298                },
299            );
300        }
301
302        // We don't replace bound vars in the generic arguments of the free alias with
303        // placeholders. This doesn't cause any issues as instantiating parameters with
304        // bound variables is special-cased to rewrite the debruijn index to be higher
305        // whenever we fold through a binder.
306        //
307        // However, we do replace any escaping bound vars in the resulting goals with
308        // placeholders as the trait solver does not expect to encounter escaping bound
309        // vars in obligations.
310        //
311        // FIXME(lazy_type_alias): Check how much this actually matters for perf before
312        // stabilization. This is a bit weird and generally not how we handle binders in
313        // the compiler so ideally we'd do the same boundvar->placeholder->boundvar dance
314        // that other kinds of normalization do.
315        let infcx = self.selcx.infcx;
316        self.obligations.extend(
317            infcx.tcx.predicates_of(free.def_id).instantiate_own(infcx.tcx, free.args).map(
318                |(mut predicate, span)| {
319                    if free.has_escaping_bound_vars() {
320                        (predicate, ..) = BoundVarReplacer::replace_bound_vars(
321                            infcx,
322                            &mut self.universes,
323                            predicate,
324                        );
325                    }
326                    let mut cause = self.cause.clone();
327                    cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, free.def_id));
328                    Obligation::new(infcx.tcx, cause, self.param_env, predicate)
329                },
330            ),
331        );
332        self.depth += 1;
333        let res = if free.kind(infcx.tcx).is_type() {
334            infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into()
335        } else {
336            // FIXME(mgca): once const items are actual aliases defined as equal to type system consts
337            // this should instead use that rather than evaluating.
338            super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env)
339                .super_fold_with(self)
340                .into()
341        };
342        self.depth -= 1;
343        res
344    }
345}
346
347impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx> {
348    fn cx(&self) -> TyCtxt<'tcx> {
349        self.selcx.tcx()
350    }
351
352    fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
353        &mut self,
354        t: ty::Binder<'tcx, T>,
355    ) -> ty::Binder<'tcx, T> {
356        self.universes.push(None);
357        let t = t.super_fold_with(self);
358        self.universes.pop();
359        t
360    }
361
362    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
363        if !needs_normalization(self.selcx.infcx, &ty) {
364            return ty;
365        }
366
367        let (kind, data) = match *ty.kind() {
368            ty::Alias(kind, data) => (kind, data),
369            _ => return ty.super_fold_with(self),
370        };
371
372        // We try to be a little clever here as a performance optimization in
373        // cases where there are nested projections under binders.
374        // For example:
375        // ```
376        // for<'a> fn(<T as Foo>::One<'a, Box<dyn Bar<'a, Item=<T as Foo>::Two<'a>>>>)
377        // ```
378        // We normalize the args on the projection before the projecting, but
379        // if we're naive, we'll
380        //   replace bound vars on inner, project inner, replace placeholders on inner,
381        //   replace bound vars on outer, project outer, replace placeholders on outer
382        //
383        // However, if we're a bit more clever, we can replace the bound vars
384        // on the entire type before normalizing nested projections, meaning we
385        //   replace bound vars on outer, project inner,
386        //   project outer, replace placeholders on outer
387        //
388        // This is possible because the inner `'a` will already be a placeholder
389        // when we need to normalize the inner projection
390        //
391        // On the other hand, this does add a bit of complexity, since we only
392        // replace bound vars if the current type is a `Projection` and we need
393        // to make sure we don't forget to fold the args regardless.
394
395        match kind {
396            ty::Opaque => {
397                // Only normalize `impl Trait` outside of type inference, usually in codegen.
398                match self.selcx.infcx.typing_mode() {
399                    // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
400                    TypingMode::Coherence
401                    | TypingMode::Analysis { .. }
402                    | TypingMode::Borrowck { .. }
403                    | TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self),
404                    TypingMode::PostAnalysis => {
405                        let recursion_limit = self.cx().recursion_limit();
406                        if !recursion_limit.value_within_limit(self.depth) {
407                            self.selcx.infcx.err_ctxt().report_overflow_error(
408                                OverflowCause::DeeplyNormalize(data.into()),
409                                self.cause.span,
410                                true,
411                                |_| {},
412                            );
413                        }
414
415                        let args = data.args.fold_with(self);
416                        let generic_ty = self.cx().type_of(data.def_id);
417                        let concrete_ty = generic_ty.instantiate(self.cx(), args);
418                        self.depth += 1;
419                        let folded_ty = self.fold_ty(concrete_ty);
420                        self.depth -= 1;
421                        folded_ty
422                    }
423                }
424            }
425
426            ty::Projection => self.normalize_trait_projection(data.into()).expect_type(),
427            ty::Inherent => self.normalize_inherent_projection(data.into()).expect_type(),
428            ty::Free => self.normalize_free_alias(data.into()).expect_type(),
429        }
430    }
431
432    #[instrument(skip(self), level = "debug")]
433    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
434        let tcx = self.selcx.tcx();
435        if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &ct) {
436            return ct;
437        }
438
439        // Doing "proper" normalization of const aliases is inherently cyclic until const items
440        // are real aliases instead of having bodies. We gate proper const alias handling behind
441        // mgca to avoid breaking stable code, though this should become the "main" codepath long
442        // before mgca is stabilized.
443        //
444        // FIXME(BoxyUwU): Enabling this by default is blocked on a refactoring to how const items
445        // are represented.
446        if tcx.features().min_generic_const_args() {
447            let uv = match ct.kind() {
448                ty::ConstKind::Unevaluated(uv) => uv,
449                _ => return ct.super_fold_with(self),
450            };
451
452            let ct = match tcx.def_kind(uv.def) {
453                DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) {
454                    DefKind::Trait => self.normalize_trait_projection(uv.into()),
455                    DefKind::Impl { of_trait: false } => {
456                        self.normalize_inherent_projection(uv.into())
457                    }
458                    kind => unreachable!(
459                        "unexpected `DefKind` for const alias' resolution's parent def: {:?}",
460                        kind
461                    ),
462                },
463                DefKind::Const | DefKind::AnonConst => self.normalize_free_alias(uv.into()),
464                kind => {
465                    unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind)
466                }
467            };
468
469            // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
470            // unnormalized after const evaluation returns.
471            ct.expect_const().super_fold_with(self)
472        } else {
473            let ct = ct.super_fold_with(self);
474            return super::with_replaced_escaping_bound_vars(
475                self.selcx.infcx,
476                &mut self.universes,
477                ct,
478                |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env),
479            )
480            .super_fold_with(self);
481            // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
482            // unnormalized after const evaluation returns.
483        }
484    }
485
486    #[inline]
487    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
488        if p.allow_normalization() && needs_normalization(self.selcx.infcx, &p) {
489            p.super_fold_with(self)
490        } else {
491            p
492        }
493    }
494}