Skip to main content

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_errors::msg;
5use rustc_hir::def::DefKind;
6use rustc_infer::infer::at::At;
7use rustc_infer::infer::{InferCtxt, InferOk};
8use rustc_infer::traits::{
9    FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
10};
11use rustc_macros::extension;
12use rustc_middle::span_bug;
13use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
14use rustc_middle::ty::{
15    self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
16    TypeVisitableExt, TypingMode,
17};
18use tracing::{debug, instrument};
19
20use super::{BoundVarReplacer, PlaceholderReplacer, SelectionContext, project};
21use crate::error_reporting::InferCtxtErrorExt;
22use crate::error_reporting::traits::OverflowCause;
23use crate::solve::NextSolverError;
24
25impl<'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.
31    fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
32        if self.infcx.next_trait_solver() {
33            InferOk { value, obligations: PredicateObligations::new() }
34        } else {
35            let mut selcx = SelectionContext::new(self.infcx);
36            let Normalized { value, obligations } =
37                normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
38            InferOk { value, obligations }
39        }
40    }
41
42    /// 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.
54    fn deeply_normalize<T, E>(
55        self,
56        value: T,
57        fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
58    ) -> Result<T, Vec<E>>
59    where
60        T: TypeFoldable<TyCtxt<'tcx>>,
61        E: FromSolverError<'tcx, NextSolverError<'tcx>>,
62    {
63        if self.infcx.next_trait_solver() {
64            crate::solve::deeply_normalize(self, value)
65        } else {
66            if fulfill_cx.has_pending_obligations() {
67                let pending_obligations = fulfill_cx.pending_obligations();
68                span_bug!(
69                    pending_obligations[0].cause.span,
70                    "deeply_normalize should not be called with pending obligations: \
71                    {pending_obligations:#?}"
72                );
73            }
74            let value = self
75                .normalize(value)
76                .into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
77            let errors = fulfill_cx.evaluate_obligations_error_on_ambiguity(self.infcx);
78            let value = self.infcx.resolve_vars_if_possible(value);
79            if errors.is_empty() {
80                Ok(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.
85                let _ = fulfill_cx.collect_remaining_errors(self.infcx);
86                Err(errors)
87            }
88        }
89    }
90}
91
92/// 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
101    T: TypeFoldable<TyCtxt<'tcx>>,
102{
103    let mut obligations = PredicateObligations::new();
104    let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations);
105    Normalized { value, obligations }
106}
107
108#[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
118    T: TypeFoldable<TyCtxt<'tcx>>,
119{
120    debug!(obligations.len = obligations.len());
121    let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
122    let result = ensure_sufficient_stack(|| AssocTypeNormalizer::fold(&mut normalizer, value));
123    debug!(?result, obligations.len = normalizer.obligations.len());
124    debug!(?normalizer.obligations,);
125    result
126}
127
128pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
129    infcx: &InferCtxt<'tcx>,
130    value: &T,
131) -> bool {
132    let mut flags = ty::TypeFlags::HAS_ALIAS;
133
134    // Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
135    // so we can ignore those.
136    match infcx.typing_mode() {
137        // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
138        TypingMode::Coherence
139        | TypingMode::Analysis { .. }
140        | TypingMode::Borrowck { .. }
141        | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
142        TypingMode::PostAnalysis => {}
143    }
144
145    value.has_type_flags(flags)
146}
147
148struct 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}
156
157impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
158    fn 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> {
165        if true {
    if !!selcx.infcx.next_trait_solver() {
        ::core::panicking::panic("assertion failed: !selcx.infcx.next_trait_solver()")
    };
};debug_assert!(!selcx.infcx.next_trait_solver());
166        AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: ::alloc::vec::Vec::new()vec![] }
167    }
168
169    fn fold<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
170        let 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);
172
173        if !!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        );
177
178        if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) }
179    }
180
181    // FIXME(mgca): While this supports constants, it is only used for types by default right now
182    x;#[instrument(level = "debug", skip(self), ret)]
183    fn normalize_trait_projection(&mut self, proj: AliasTerm<'tcx>) -> Term<'tcx> {
184        if !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).
193            let proj = proj.fold_with(self);
194            project::normalize_projection_term(
195                self.selcx,
196                self.param_env,
197                proj,
198                self.cause.clone(),
199                self.depth,
200                self.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.
214            let infcx = self.selcx.infcx;
215            let (proj, mapped_regions, mapped_types, mapped_consts) =
216                BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, proj);
217            let proj = proj.fold_with(self);
218            let normalized_term = project::opt_normalize_projection_term(
219                self.selcx,
220                self.param_env,
221                proj,
222                self.cause.clone(),
223                self.depth,
224                self.obligations,
225            )
226            .ok()
227            .flatten()
228            .unwrap_or_else(|| proj.to_term(infcx.tcx));
229
230            PlaceholderReplacer::replace_placeholders(
231                infcx,
232                mapped_regions,
233                mapped_types,
234                mapped_consts,
235                &self.universes,
236                normalized_term,
237            )
238        }
239    }
240
241    // FIXME(mgca): While this supports constants, it is only used for types by default right now
242    x;#[instrument(level = "debug", skip(self), ret)]
243    fn normalize_inherent_projection(&mut self, inherent: AliasTerm<'tcx>) -> Term<'tcx> {
244        if !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).
253
254            let inherent = inherent.fold_with(self);
255            project::normalize_inherent_projection(
256                self.selcx,
257                self.param_env,
258                inherent,
259                self.cause.clone(),
260                self.depth,
261                self.obligations,
262            )
263        } else {
264            let infcx = self.selcx.infcx;
265            let (inherent, mapped_regions, mapped_types, mapped_consts) =
266                BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, inherent);
267            let inherent = inherent.fold_with(self);
268            let inherent = project::normalize_inherent_projection(
269                self.selcx,
270                self.param_env,
271                inherent,
272                self.cause.clone(),
273                self.depth,
274                self.obligations,
275            );
276
277            PlaceholderReplacer::replace_placeholders(
278                infcx,
279                mapped_regions,
280                mapped_types,
281                mapped_consts,
282                &self.universes,
283                inherent,
284            )
285        }
286    }
287
288    // FIXME(mgca): While this supports constants, it is only used for types by default right now
289    x;#[instrument(level = "debug", skip(self), ret)]
290    fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> {
291        let recursion_limit = self.cx().recursion_limit();
292        if !recursion_limit.value_within_limit(self.depth) {
293            self.selcx.infcx.err_ctxt().report_overflow_error(
294                OverflowCause::DeeplyNormalize(free.into()),
295                self.cause.span,
296                false,
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        }
302
303        // 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.
316        let infcx = self.selcx.infcx;
317        self.obligations.extend(
318            infcx.tcx.predicates_of(free.def_id).instantiate_own(infcx.tcx, free.args).map(
319                |(mut predicate, span)| {
320                    if free.has_escaping_bound_vars() {
321                        (predicate, ..) = BoundVarReplacer::replace_bound_vars(
322                            infcx,
323                            &mut self.universes,
324                            predicate,
325                        );
326                    }
327                    let 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        );
333        self.depth += 1;
334        let 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        };
344        self.depth -= 1;
345        res
346    }
347}
348
349impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx> {
350    fn cx(&self) -> TyCtxt<'tcx> {
351        self.selcx.tcx()
352    }
353
354    fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
355        &mut self,
356        t: ty::Binder<'tcx, T>,
357    ) -> ty::Binder<'tcx, T> {
358        self.universes.push(None);
359        let t = t.super_fold_with(self);
360        self.universes.pop();
361        t
362    }
363
364    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
365        if !needs_normalization(self.selcx.infcx, &ty) {
366            return ty;
367        }
368
369        let (kind, data) = match *ty.kind() {
370            ty::Alias(kind, data) => (kind, data),
371            _ => return ty.super_fold_with(self),
372        };
373
374        // 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.
396
397        match kind {
398            ty::Opaque => {
399                // Only normalize `impl Trait` outside of type inference, usually in codegen.
400                match self.selcx.infcx.typing_mode() {
401                    // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
402                    TypingMode::Coherence
403                    | TypingMode::Analysis { .. }
404                    | TypingMode::Borrowck { .. }
405                    | TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self),
406                    TypingMode::PostAnalysis => {
407                        let recursion_limit = self.cx().recursion_limit();
408                        if !recursion_limit.value_within_limit(self.depth) {
409                            self.selcx.infcx.err_ctxt().report_overflow_error(
410                                OverflowCause::DeeplyNormalize(data.into()),
411                                self.cause.span,
412                                true,
413                                |_| {},
414                            );
415                        }
416
417                        let args = data.args.fold_with(self);
418                        let generic_ty = self.cx().type_of(data.def_id);
419                        let concrete_ty = generic_ty.instantiate(self.cx(), args);
420                        self.depth += 1;
421                        let folded_ty = self.fold_ty(concrete_ty);
422                        self.depth -= 1;
423                        folded_ty
424                    }
425                }
426            }
427
428            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    }
433
434    #[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")]
435    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
436        let tcx = self.selcx.tcx();
437
438        if 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        {
443            return ct;
444        }
445
446        let uv = match ct.kind() {
447            ty::ConstKind::Unevaluated(uv) => uv,
448            _ => return ct.super_fold_with(self),
449        };
450
451        // 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.
458        let 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 } => {
462                    self.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 => {
471                let ct = ct.super_fold_with(self);
472                super::with_replaced_escaping_bound_vars(
473                    self.selcx.infcx,
474                    &mut self.universes,
475                    ct,
476                    |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env),
477                )
478            }
479            kind => {
480                unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind)
481            }
482        };
483
484        // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
485        // unnormalized after const evaluation returns.
486        ct.super_fold_with(self)
487    }
488
489    #[inline]
490    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
491        if p.allow_normalization() && needs_normalization(self.selcx.infcx, &p) {
492            p.super_fold_with(self)
493        } else {
494            p
495        }
496    }
497}