Skip to main content

rustc_trait_selection/traits/query/
normalize.rs

1//! Code for the 'normalization' query. This consists of a wrapper
2//! which folds deeply, invoking the underlying
3//! `normalize_canonicalized_projection` query when it encounters projections.
4
5use rustc_data_structures::sso::SsoHashMap;
6use rustc_infer::traits::PredicateObligations;
7use rustc_macros::extension;
8pub use rustc_middle::traits::query::NormalizationResult;
9use rustc_middle::ty::{
10    self, FallibleTypeFolder, Flags, PredicateProxy, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
11    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Unnormalized,
12};
13use rustc_span::DUMMY_SP;
14use tracing::{debug, info, instrument};
15
16use super::NoSolution;
17use crate::error_reporting::InferCtxtErrorExt;
18use crate::error_reporting::traits::OverflowCause;
19use crate::infer::at::At;
20use crate::infer::canonical::OriginalQueryValues;
21use crate::infer::{InferCtxt, InferOk};
22use crate::traits::normalize::needs_normalization;
23use crate::traits::{
24    BoundVarReplacer, FulfillmentError, FulfillmentErrorCode, Normalized, ObligationCause,
25    PlaceholderReplacer,
26};
27
28pub trait QueryNormalizeExt<'tcx> {
    #[doc = " Normalize `value` in the context of the inference context,"]
    #[doc = " yielding a resulting type, or an error if `value` cannot be"]
    #[doc =
    " normalized. If you don\'t care about regions, you should prefer"]
    #[doc = " `normalize_erasing_regions`, which is more efficient."]
    #[doc = ""]
    #[doc = " If the normalization succeeds, returns back the normalized"]
    #[doc = " value along with various outlives relations (in the form of"]
    #[doc = " obligations that must be discharged)."]
    #[doc = ""]
    #[doc =
    " This normalization should *only* be used when the projection is well-formed and"]
    #[doc =
    " does not have possible ambiguity (contains inference variables)."]
    #[doc = ""]
    #[doc =
    " After codegen, when lifetimes do not matter, it is preferable to instead"]
    #[doc =
    " use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure."]
    #[doc = ""]
    #[doc =
    " N.B. Once the new solver is stabilized this method of normalization will"]
    #[doc =
    " likely be removed as trait solver operations are already cached by the query"]
    #[doc = " system making this redundant."]
    fn query_normalize<T>(self, value: T)
    -> Result<Normalized<'tcx, T>, NoSolution>
    where
    T: TypeFoldable<TyCtxt<'tcx>>;
}
impl<'a, 'tcx> QueryNormalizeExt<'tcx> for At<'a, 'tcx> {
    #[doc = " Normalize `value` in the context of the inference context,"]
    #[doc = " yielding a resulting type, or an error if `value` cannot be"]
    #[doc =
    " normalized. If you don\'t care about regions, you should prefer"]
    #[doc = " `normalize_erasing_regions`, which is more efficient."]
    #[doc = ""]
    #[doc = " If the normalization succeeds, returns back the normalized"]
    #[doc = " value along with various outlives relations (in the form of"]
    #[doc = " obligations that must be discharged)."]
    #[doc = ""]
    #[doc =
    " This normalization should *only* be used when the projection is well-formed and"]
    #[doc =
    " does not have possible ambiguity (contains inference variables)."]
    #[doc = ""]
    #[doc =
    " After codegen, when lifetimes do not matter, it is preferable to instead"]
    #[doc =
    " use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure."]
    #[doc = ""]
    #[doc =
    " N.B. Once the new solver is stabilized this method of normalization will"]
    #[doc =
    " likely be removed as trait solver operations are already cached by the query"]
    #[doc = " system making this redundant."]
    fn query_normalize<T>(self, value: T)
        -> Result<Normalized<'tcx, T>, NoSolution> where
        T: TypeFoldable<TyCtxt<'tcx>> {
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("event /rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs:52",
                                "rustc_trait_selection::traits::query::normalize",
                                ::tracing::Level::DEBUG,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs"),
                                ::tracing_core::__macro_support::Option::Some(52u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::normalize"),
                                ::tracing_core::field::FieldSet::new(&["message"],
                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::EVENT)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let enabled =
                ::tracing::Level::DEBUG <=
                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                        ::tracing::Level::DEBUG <=
                            ::tracing::level_filters::LevelFilter::current() &&
                    {
                        let interest = __CALLSITE.interest();
                        !interest.is_never() &&
                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                interest)
                    };
            if enabled {
                (|value_set: ::tracing::field::ValueSet|
                            {
                                let meta = __CALLSITE.metadata();
                                ::tracing::Event::dispatch(meta, &value_set);
                                ;
                            })({
                        #[allow(unused_imports)]
                        use ::tracing::field::{debug, display, Value};
                        __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("normalize::<{0}>(value={1:?}, param_env={2:?}, cause={3:?})",
                                                            std::any::type_name::<T>(), value, self.param_env,
                                                            self.cause) as &dyn ::tracing::field::Value))])
                    });
            } else { ; }
        };
        let universes =
            if value.has_escaping_bound_vars() {
                let mut max_visitor =
                    MaxEscapingBoundVarVisitor {
                        outer_index: ty::INNERMOST,
                        escaping: 0,
                    };
                value.visit_with(&mut max_visitor);
                ::alloc::vec::from_elem(None, max_visitor.escaping)
            } else { ::alloc::vec::Vec::new() };
        if self.infcx.next_trait_solver() {
            match crate::solve::deeply_normalize_with_skipped_universes::<_,
                        FulfillmentError<'tcx>>(self, Unnormalized::new_wip(value),
                    universes) {
                Ok(value) => {
                    return Ok(Normalized {
                                value,
                                obligations: PredicateObligations::new(),
                            });
                }
                Err(errors) => {
                    if let Some((overflowed_obligation, suggest_higher_limit)) =
                            errors.into_iter().find_map(|e|
                                    match e.code {
                                        FulfillmentErrorCode::Ambiguity {
                                            overflow: Some(suggest_higher_limit) } =>
                                            Some((e.root_obligation, suggest_higher_limit)),
                                        _ => None,
                                    }) {
                        self.infcx.err_ctxt().report_overflow_obligation(&overflowed_obligation,
                            suggest_higher_limit);
                    } else { return Err(NoSolution); }
                }
            }
        }
        if !needs_normalization(self.infcx, &value) {
            return Ok(Normalized {
                        value,
                        obligations: PredicateObligations::new(),
                    });
        }
        let mut normalizer =
            QueryNormalizer {
                infcx: self.infcx,
                cause: self.cause,
                param_env: self.param_env,
                obligations: PredicateObligations::new(),
                cache: SsoHashMap::new(),
                anon_depth: 0,
                universes,
            };
        let result = value.try_fold_with(&mut normalizer);
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("event /rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs:125",
                                "rustc_trait_selection::traits::query::normalize",
                                ::tracing::Level::INFO,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs"),
                                ::tracing_core::__macro_support::Option::Some(125u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::normalize"),
                                ::tracing_core::field::FieldSet::new(&["message"],
                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::EVENT)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let enabled =
                ::tracing::Level::INFO <=
                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                        ::tracing::Level::INFO <=
                            ::tracing::level_filters::LevelFilter::current() &&
                    {
                        let interest = __CALLSITE.interest();
                        !interest.is_never() &&
                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                interest)
                    };
            if enabled {
                (|value_set: ::tracing::field::ValueSet|
                            {
                                let meta = __CALLSITE.metadata();
                                ::tracing::Event::dispatch(meta, &value_set);
                                ;
                            })({
                        #[allow(unused_imports)]
                        use ::tracing::field::{debug, display, Value};
                        __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("normalize::<{0}>: result={1:?} with {2} obligations",
                                                            std::any::type_name::<T>(), result,
                                                            normalizer.obligations.len()) as
                                                    &dyn ::tracing::field::Value))])
                    });
            } else { ; }
        };
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("event /rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs:131",
                                "rustc_trait_selection::traits::query::normalize",
                                ::tracing::Level::DEBUG,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs"),
                                ::tracing_core::__macro_support::Option::Some(131u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::normalize"),
                                ::tracing_core::field::FieldSet::new(&["message"],
                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::EVENT)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let enabled =
                ::tracing::Level::DEBUG <=
                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                        ::tracing::Level::DEBUG <=
                            ::tracing::level_filters::LevelFilter::current() &&
                    {
                        let interest = __CALLSITE.interest();
                        !interest.is_never() &&
                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                interest)
                    };
            if enabled {
                (|value_set: ::tracing::field::ValueSet|
                            {
                                let meta = __CALLSITE.metadata();
                                ::tracing::Event::dispatch(meta, &value_set);
                                ;
                            })({
                        #[allow(unused_imports)]
                        use ::tracing::field::{debug, display, Value};
                        __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("normalize::<{0}>: obligations={1:?}",
                                                            std::any::type_name::<T>(), normalizer.obligations) as
                                                    &dyn ::tracing::field::Value))])
                    });
            } else { ; }
        };
        result.map(|value|
                Normalized { value, obligations: normalizer.obligations })
    }
}#[extension(pub trait QueryNormalizeExt<'tcx>)]
29impl<'a, 'tcx> At<'a, 'tcx> {
30    /// Normalize `value` in the context of the inference context,
31    /// yielding a resulting type, or an error if `value` cannot be
32    /// normalized. If you don't care about regions, you should prefer
33    /// `normalize_erasing_regions`, which is more efficient.
34    ///
35    /// If the normalization succeeds, returns back the normalized
36    /// value along with various outlives relations (in the form of
37    /// obligations that must be discharged).
38    ///
39    /// This normalization should *only* be used when the projection is well-formed and
40    /// does not have possible ambiguity (contains inference variables).
41    ///
42    /// After codegen, when lifetimes do not matter, it is preferable to instead
43    /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure.
44    ///
45    /// N.B. Once the new solver is stabilized this method of normalization will
46    /// likely be removed as trait solver operations are already cached by the query
47    /// system making this redundant.
48    fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
49    where
50        T: TypeFoldable<TyCtxt<'tcx>>,
51    {
52        debug!(
53            "normalize::<{}>(value={:?}, param_env={:?}, cause={:?})",
54            std::any::type_name::<T>(),
55            value,
56            self.param_env,
57            self.cause,
58        );
59
60        // This is actually a consequence by the way `normalize_erasing_regions` works currently.
61        // Because it needs to call the `normalize_generic_arg_after_erasing_regions`, it folds
62        // through tys and consts in a `TypeFoldable`. Importantly, it skips binders, leaving us
63        // with trying to normalize with escaping bound vars.
64        //
65        // Here, we just add the universes that we *would* have created had we passed through the binders.
66        //
67        // We *could* replace escaping bound vars eagerly here, but it doesn't seem really necessary.
68        // The rest of the code is already set up to be lazy about replacing bound vars,
69        // and only when we actually have to normalize.
70        let universes = if value.has_escaping_bound_vars() {
71            let mut max_visitor =
72                MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 };
73            value.visit_with(&mut max_visitor);
74            vec![None; max_visitor.escaping]
75        } else {
76            vec![]
77        };
78
79        if self.infcx.next_trait_solver() {
80            match crate::solve::deeply_normalize_with_skipped_universes::<_, FulfillmentError<'tcx>>(
81                self,
82                Unnormalized::new_wip(value),
83                universes,
84            ) {
85                Ok(value) => {
86                    return Ok(Normalized { value, obligations: PredicateObligations::new() });
87                }
88                Err(errors) => {
89                    // We're imitating the old solver's behavior of eagerly reporting overflow
90                    // errors here. Otherwise we might silently ignore such errors. See #161542.
91                    if let Some((overflowed_obligation, suggest_higher_limit)) =
92                        errors.into_iter().find_map(|e| match e.code {
93                            FulfillmentErrorCode::Ambiguity {
94                                overflow: Some(suggest_higher_limit),
95                            } => Some((e.root_obligation, suggest_higher_limit)),
96                            _ => None,
97                        })
98                    {
99                        self.infcx.err_ctxt().report_overflow_obligation(
100                            &overflowed_obligation,
101                            suggest_higher_limit,
102                        );
103                    } else {
104                        return Err(NoSolution);
105                    }
106                }
107            }
108        }
109
110        if !needs_normalization(self.infcx, &value) {
111            return Ok(Normalized { value, obligations: PredicateObligations::new() });
112        }
113
114        let mut normalizer = QueryNormalizer {
115            infcx: self.infcx,
116            cause: self.cause,
117            param_env: self.param_env,
118            obligations: PredicateObligations::new(),
119            cache: SsoHashMap::new(),
120            anon_depth: 0,
121            universes,
122        };
123
124        let result = value.try_fold_with(&mut normalizer);
125        info!(
126            "normalize::<{}>: result={:?} with {} obligations",
127            std::any::type_name::<T>(),
128            result,
129            normalizer.obligations.len(),
130        );
131        debug!(
132            "normalize::<{}>: obligations={:?}",
133            std::any::type_name::<T>(),
134            normalizer.obligations,
135        );
136        result.map(|value| Normalized { value, obligations: normalizer.obligations })
137    }
138}
139
140// Visitor to find the maximum escaping bound var
141struct MaxEscapingBoundVarVisitor {
142    // The index which would count as escaping
143    outer_index: ty::DebruijnIndex,
144    escaping: usize,
145}
146
147impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor {
148    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
149        self.outer_index.shift_in(1);
150        t.super_visit_with(self);
151        self.outer_index.shift_out(1);
152    }
153
154    #[inline]
155    fn visit_ty(&mut self, t: Ty<'tcx>) {
156        if t.outer_exclusive_binder() > self.outer_index {
157            self.escaping = self
158                .escaping
159                .max(t.outer_exclusive_binder().as_usize() - self.outer_index.as_usize());
160        }
161    }
162
163    #[inline]
164    fn visit_region(&mut self, r: ty::Region<'tcx>) {
165        match r.kind() {
166            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
167                if debruijn > self.outer_index =>
168            {
169                self.escaping =
170                    self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
171            }
172            _ => {}
173        }
174    }
175
176    fn visit_const(&mut self, ct: ty::Const<'tcx>) {
177        if ct.outer_exclusive_binder() > self.outer_index {
178            self.escaping = self
179                .escaping
180                .max(ct.outer_exclusive_binder().as_usize() - self.outer_index.as_usize());
181        }
182    }
183}
184
185struct QueryNormalizer<'a, 'tcx> {
186    infcx: &'a InferCtxt<'tcx>,
187    cause: &'a ObligationCause<'tcx>,
188    param_env: ty::ParamEnv<'tcx>,
189    obligations: PredicateObligations<'tcx>,
190    cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
191    anon_depth: usize,
192    universes: Vec<Option<ty::UniverseIndex>>,
193}
194
195impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
196    type Error = NoSolution;
197
198    fn cx(&self) -> TyCtxt<'tcx> {
199        self.infcx.tcx
200    }
201
202    fn try_fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
203        &mut self,
204        t: ty::Binder<'tcx, T>,
205    ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
206        self.universes.push(None);
207        let t = t.try_super_fold_with(self);
208        self.universes.pop();
209        t
210    }
211
212    {}
#[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("try_fold_ty",
                                    "rustc_trait_selection::traits::query::normalize",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs"),
                                    ::tracing_core::__macro_support::Option::Some(212u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::normalize"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("ty")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("ty");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: Result<Ty<'tcx>, Self::Error> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            if !needs_normalization(self.infcx, &ty) { return Ok(ty); }
            if let Some(ty) = self.cache.get(&ty) { return Ok(*ty); }
            let &ty::Alias(_, data) =
                ty.kind() else {
                    let res = ty.try_super_fold_with(self)?;
                    self.cache.insert(ty, res);
                    return Ok(res);
                };
            let res =
                match data.kind {
                    ty::Opaque { def_id } => {
                        match self.infcx.typing_mode_raw().assert_not_erased() {
                            TypingMode::Coherence | TypingMode::Typeck { .. } |
                                TypingMode::PostTypeckUntilBorrowck { .. } |
                                TypingMode::PostBorrowck { .. } =>
                                ty.try_super_fold_with(self)?,
                            TypingMode::Reflection | TypingMode::PostAnalysis |
                                TypingMode::Codegen => {
                                let args = data.args.try_fold_with(self)?;
                                let recursion_limit = self.cx().recursion_limit();
                                if !recursion_limit.value_within_limit(self.anon_depth) {
                                    let guar =
                                        self.infcx.err_ctxt().build_overflow_error(OverflowCause::DeeplyNormalize(data.into()),
                                                self.cause.span, true).delay_as_bug();
                                    return Ok(Ty::new_error(self.cx(), guar));
                                }
                                let generic_ty = self.cx().type_of(def_id);
                                let mut concrete_ty =
                                    generic_ty.instantiate(self.cx(), args).skip_norm_wip();
                                self.anon_depth += 1;
                                if concrete_ty == ty {
                                    concrete_ty =
                                        Ty::new_error_with_message(self.cx(), DUMMY_SP,
                                            "recursive opaque type");
                                }
                                let folded_ty = self.try_fold_ty(concrete_ty);
                                self.anon_depth -= 1;
                                folded_ty?
                            }
                        }
                    }
                    kind @
                        (ty::Projection { .. } | ty::Inherent { .. } | ty::Free { ..
                        }) =>
                        self.try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(),
                                        kind.into(), data.args))?.expect_type(),
                };
            self.cache.insert(ty, res);
            Ok(res)
        }
    }
}#[instrument(level = "debug", skip(self))]
213    fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
214        if !needs_normalization(self.infcx, &ty) {
215            return Ok(ty);
216        }
217
218        if let Some(ty) = self.cache.get(&ty) {
219            return Ok(*ty);
220        }
221
222        let &ty::Alias(_, data) = ty.kind() else {
223            let res = ty.try_super_fold_with(self)?;
224            self.cache.insert(ty, res);
225            return Ok(res);
226        };
227
228        // See note in `rustc_trait_selection::traits::project` about why we
229        // wait to fold the args.
230        let res = match data.kind {
231            ty::Opaque { def_id } => {
232                // Only normalize `impl Trait` outside of type inference, usually in codegen.
233                match self.infcx.typing_mode_raw().assert_not_erased() {
234                    TypingMode::Coherence
235                    | TypingMode::Typeck { .. }
236                    | TypingMode::PostTypeckUntilBorrowck { .. }
237                    | TypingMode::PostBorrowck { .. } => ty.try_super_fold_with(self)?,
238
239                    TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => {
240                        let args = data.args.try_fold_with(self)?;
241                        let recursion_limit = self.cx().recursion_limit();
242
243                        if !recursion_limit.value_within_limit(self.anon_depth) {
244                            let guar = self
245                                .infcx
246                                .err_ctxt()
247                                .build_overflow_error(
248                                    OverflowCause::DeeplyNormalize(data.into()),
249                                    self.cause.span,
250                                    true,
251                                )
252                                .delay_as_bug();
253                            return Ok(Ty::new_error(self.cx(), guar));
254                        }
255
256                        let generic_ty = self.cx().type_of(def_id);
257                        let mut concrete_ty =
258                            generic_ty.instantiate(self.cx(), args).skip_norm_wip();
259                        self.anon_depth += 1;
260                        if concrete_ty == ty {
261                            concrete_ty = Ty::new_error_with_message(
262                                self.cx(),
263                                DUMMY_SP,
264                                "recursive opaque type",
265                            );
266                        }
267                        let folded_ty = self.try_fold_ty(concrete_ty);
268                        self.anon_depth -= 1;
269                        folded_ty?
270                    }
271                }
272            }
273
274            kind @ (ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. }) => self
275                .try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), kind.into(), data.args))?
276                .expect_type(),
277        };
278
279        self.cache.insert(ty, res);
280        Ok(res)
281    }
282
283    fn try_fold_const(
284        &mut self,
285        constant: ty::Const<'tcx>,
286    ) -> Result<ty::Const<'tcx>, Self::Error> {
287        if !needs_normalization(self.infcx, &constant) {
288            return Ok(constant);
289        }
290
291        let alias_const = match constant.kind() {
292            ty::ConstKind::Alias(_, alias_const) => alias_const,
293            _ => return constant.try_super_fold_with(self),
294        };
295
296        let constant = match alias_const.kind {
297            ty::AliasConstKind::Anon { .. } => crate::traits::with_replaced_escaping_bound_vars(
298                self.infcx,
299                &mut self.universes,
300                constant,
301                |constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env),
302            ),
303            _ => self.try_fold_free_or_assoc(alias_const.into())?.expect_const(),
304        };
305        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs:305",
                        "rustc_trait_selection::traits::query::normalize",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs"),
                        ::tracing_core::__macro_support::Option::Some(305u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::normalize"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("constant")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("constant");
                                            NAME.as_str()
                                        },
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("self.param_env")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("self.param_env");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&constant)
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.param_env)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?constant, ?self.param_env);
306        constant.try_super_fold_with(self)
307    }
308
309    #[inline]
310    fn try_fold_predicate<P: PredicateProxy<TyCtxt<'tcx>>>(
311        &mut self,
312        p: P,
313    ) -> Result<P, Self::Error> {
314        if p.allow_normalization() && needs_normalization(self.infcx, &p) {
315            p.try_super_fold_with(self)
316        } else {
317            Ok(p)
318        }
319    }
320}
321
322impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> {
323    fn try_fold_free_or_assoc(
324        &mut self,
325        term: ty::AliasTerm<'tcx>,
326    ) -> Result<ty::Term<'tcx>, NoSolution> {
327        let infcx = self.infcx;
328        let tcx = infcx.tcx;
329        // Just an optimization: When we don't have escaping bound vars,
330        // we don't need to replace them with placeholders.
331        let (term, maps) = if term.has_escaping_bound_vars() {
332            let (term, mapped_regions, mapped_types, mapped_consts) =
333                BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, term);
334            (term, Some((mapped_regions, mapped_types, mapped_consts)))
335        } else {
336            (term, None)
337        };
338        let term = term.try_fold_with(self)?;
339
340        let mut orig_values = OriginalQueryValues::default();
341        let c_term = infcx.canonicalize_query(self.param_env.and(term), &mut orig_values);
342        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs:342",
                        "rustc_trait_selection::traits::query::normalize",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs"),
                        ::tracing_core::__macro_support::Option::Some(342u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::normalize"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("QueryNormalizer: c_term = {0:#?}",
                                                    c_term) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("QueryNormalizer: c_term = {:#?}", c_term);
343        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs:343",
                        "rustc_trait_selection::traits::query::normalize",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs"),
                        ::tracing_core::__macro_support::Option::Some(343u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::normalize"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("QueryNormalizer: orig_values = {0:#?}",
                                                    orig_values) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
344        let result = match term.kind {
345            ty::AliasTermKind::ProjectionTy { .. } | ty::AliasTermKind::ProjectionConst { .. } => {
346                tcx.normalize_canonicalized_projection(c_term)
347            }
348            ty::AliasTermKind::FreeTy { .. } | ty::AliasTermKind::FreeConst { .. } => {
349                tcx.normalize_canonicalized_free_alias(c_term)
350            }
351            ty::AliasTermKind::InherentTy { .. }
352            | ty::AliasTermKind::InherentConstSelf { .. }
353            | ty::AliasTermKind::InherentConstImpl { .. } => {
354                tcx.normalize_canonicalized_inherent_projection(c_term)
355            }
356            kind @ (ty::AliasTermKind::OpaqueTy { .. } | ty::AliasTermKind::AnonConst { .. }) => {
357                {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("did not expect {0:?} due to match arm above",
                kind)));
}unreachable!("did not expect {kind:?} due to match arm above")
358            }
359        }?;
360        // We don't expect ambiguity.
361        if !result.value.is_proven() {
362            // Rustdoc normalizes possibly not well-formed types, so only
363            // treat this as a bug if we're not in rustdoc.
364            if !tcx.sess.opts.actually_rustdoc {
365                tcx.dcx().delayed_bug(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("unexpected ambiguity: {0:?} {1:?}",
                c_term, result))
    })format!("unexpected ambiguity: {c_term:?} {result:?}"));
366            }
367            return Err(NoSolution);
368        }
369        let InferOk { value: result, obligations } = infcx
370            .instantiate_query_response_and_region_obligations(
371                self.cause,
372                self.param_env,
373                &orig_values,
374                result,
375            )?;
376        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs:376",
                        "rustc_trait_selection::traits::query::normalize",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs"),
                        ::tracing_core::__macro_support::Option::Some(376u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::normalize"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("QueryNormalizer: result = {0:#?}",
                                                    result) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("QueryNormalizer: result = {:#?}", result);
377        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs:377",
                        "rustc_trait_selection::traits::query::normalize",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/4b6d04e706108ccfeafe2547fbe857dfe8972bad/compiler/rustc_trait_selection/src/traits/query/normalize.rs"),
                        ::tracing_core::__macro_support::Option::Some(377u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::normalize"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("QueryNormalizer: obligations = {0:#?}",
                                                    obligations) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("QueryNormalizer: obligations = {:#?}", obligations);
378        self.obligations.extend(obligations);
379        let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
380            PlaceholderReplacer::replace_placeholders(
381                infcx,
382                mapped_regions,
383                mapped_types,
384                mapped_consts,
385                &self.universes,
386                result.normalized_term,
387            )
388        } else {
389            result.normalized_term
390        };
391        // `tcx.normalize_canonicalized_projection` may normalize to a type that
392        // still has alias consts, so keep normalizing here if that's the case.
393        // Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer
394        // of type/const and we need to continue folding it to reveal the TAIT behind it
395        // or further normalize nested alias consts.
396        if res != term.to_term(tcx, ty::IsRigid::No)
397            && (res.has_type_flags(ty::TypeFlags::HAS_CONST_ALIAS)
398                || #[allow(non_exhaustive_omitted_patterns)] match term.kind {
    ty::AliasTermKind::FreeTy { .. } | ty::AliasTermKind::FreeConst { .. } =>
        true,
    _ => false,
}matches!(
399                    term.kind,
400                    ty::AliasTermKind::FreeTy { .. } | ty::AliasTermKind::FreeConst { .. }
401                ))
402        {
403            res.try_fold_with(self)
404        } else {
405            Ok(res)
406        }
407    }
408}