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_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    /// Normalize a value using the `AssocTypeNormalizer`.
29    ///
30    /// This normalization should be used when the type contains inference variables or the
31    /// projection may be fallible.
32    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    /// Deeply normalizes `value`, replacing all aliases which can by normalized in
44    /// the current environment. In the new solver this errors in case normalization
45    /// fails or is ambiguous.
46    ///
47    /// In the old solver this simply uses `normalizes` and adds the nested obligations
48    /// to the `fulfill_cx`. This is necessary as we otherwise end up recomputing the
49    /// same goals in both a temporary and the shared context which negatively impacts
50    /// performance as these don't share caching.
51    ///
52    /// FIXME(-Znext-solver): For performance reasons, we currently reuse an existing
53    /// fulfillment context in the old solver. Once we have removed the old solver, we
54    /// can remove the `fulfill_cx` parameter on this function.
55    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
85/// As `normalize`, but with a custom depth.
86pub(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    // Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
128    // so we can ignore those.
129    match infcx.typing_mode() {
130        // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
131        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        // We try to be a little clever here as a performance optimization in
200        // cases where there are nested projections under binders.
201        // For example:
202        // ```
203        // for<'a> fn(<T as Foo>::One<'a, Box<dyn Bar<'a, Item=<T as Foo>::Two<'a>>>>)
204        // ```
205        // We normalize the args on the projection before the projecting, but
206        // if we're naive, we'll
207        //   replace bound vars on inner, project inner, replace placeholders on inner,
208        //   replace bound vars on outer, project outer, replace placeholders on outer
209        //
210        // However, if we're a bit more clever, we can replace the bound vars
211        // on the entire type before normalizing nested projections, meaning we
212        //   replace bound vars on outer, project inner,
213        //   project outer, replace placeholders on outer
214        //
215        // This is possible because the inner `'a` will already be a placeholder
216        // when we need to normalize the inner projection
217        //
218        // On the other hand, this does add a bit of complexity, since we only
219        // replace bound vars if the current type is a `Projection` and we need
220        // to make sure we don't forget to fold the args regardless.
221
222        match kind {
223            ty::Opaque => {
224                // Only normalize `impl Trait` outside of type inference, usually in codegen.
225                match self.selcx.infcx.typing_mode() {
226                    // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
227                    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                // This branch is *mostly* just an optimization: when we don't
254                // have escaping bound vars, we don't need to replace them with
255                // placeholders (see branch below). *Also*, we know that we can
256                // register an obligation to *later* project, since we know
257                // there won't be bound vars there.
258                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                // If there are escaping bound vars, we temporarily replace the
279                // bound vars with placeholders. Note though, that in the case
280                // that we still can't project for whatever reason (e.g. self
281                // type isn't known enough), we *can't* register an obligation
282                // and return an inference variable (since then that obligation
283                // would have bound vars and that's a can of worms). Instead,
284                // we just give up and fall back to pretending like we never tried!
285                //
286                // Note: this isn't necessarily the final approach here; we may
287                // want to figure out how to register obligations with escaping vars
288                // or handle this some other way.
289
290                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                // This branch is *mostly* just an optimization: when we don't
370                // have escaping bound vars, we don't need to replace them with
371                // placeholders (see branch below). *Also*, we know that we can
372                // register an obligation to *later* project, since we know
373                // there won't be bound vars there.
374
375                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}