Skip to main content

rustc_next_trait_solver/
normalize.rs

1use std::fmt::Debug;
2
3use rustc_type_ir::inherent::*;
4use rustc_type_ir::{
5    self as ty, AliasTerm, Binder, FallibleTypeFolder, InferCtxtLike, Interner, TypeFoldable,
6    TypeSuperFoldable, TypeVisitableExt, UniverseIndex, eager_resolve_vars,
7};
8use tracing::instrument;
9
10use crate::placeholder::{BoundVarReplacer, PlaceholderReplacer};
11
12/// This folder normalizes value and collects ambiguous goals.
13///
14/// Note that for ambiguous alias which contains escaping bound vars,
15/// we just return the original alias and don't collect the ambiguous goal.
16pub struct NormalizationFolder<'a, Infcx, I, F>
17where
18    Infcx: InferCtxtLike<Interner = I>,
19    I: Interner,
20{
21    infcx: &'a Infcx,
22    universes: Vec<Option<UniverseIndex>>,
23    normalize: F,
24}
25
26#[derive(#[automatically_derived]
impl ::core::marker::StructuralPartialEq for HasEscapingBoundVars { }
#[automatically_derived]
impl ::core::cmp::PartialEq for HasEscapingBoundVars {
    #[inline]
    fn eq(&self, other: &HasEscapingBoundVars) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for HasEscapingBoundVars {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq)]
27enum HasEscapingBoundVars {
28    Yes,
29    No,
30}
31
32#[derive(#[automatically_derived]
impl ::core::marker::StructuralPartialEq for NormalizationWasAmbiguous { }
#[automatically_derived]
impl ::core::cmp::PartialEq for NormalizationWasAmbiguous {
    #[inline]
    fn eq(&self, other: &NormalizationWasAmbiguous) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for NormalizationWasAmbiguous {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq)]
33pub enum NormalizationWasAmbiguous {
34    Yes,
35    No,
36}
37
38impl<'a, Infcx, I, F, E> NormalizationFolder<'a, Infcx, I, F>
39where
40    Infcx: InferCtxtLike<Interner = I>,
41    I: Interner,
42    F: FnMut(AliasTerm<I>) -> Result<(I::Term, NormalizationWasAmbiguous), E>,
43{
44    pub fn new(infcx: &'a Infcx, universes: Vec<Option<UniverseIndex>>, normalize: F) -> Self {
45        Self { infcx, universes, normalize }
46    }
47
48    fn normalize_alias_term(
49        &mut self,
50        alias_term: AliasTerm<I>,
51        has_escaping: HasEscapingBoundVars,
52    ) -> Result<Option<I::Term>, E> {
53        let (normalized, normalization_was_ambiguous) = (self.normalize)(alias_term)?;
54
55        // Return ambiguous higher ranked alias as is, if
56        //   - it contains escaping vars, and
57        //   - the normalized term contains infer vars which may mention
58        //     temporary placeholders after we've already mapped them back
59        //     to bound vars.
60        //
61        // We can normalize the ambiguous alias again after the binder is instantiated.
62        if normalization_was_ambiguous == NormalizationWasAmbiguous::Yes
63            && has_escaping == HasEscapingBoundVars::Yes
64        {
65            let max_universe = ty::max_universe_of_infer_vars(self.infcx, normalized);
66            if max_universe.can_name(self.universes.first().unwrap().unwrap()) {
67                return Ok(None);
68            }
69        }
70
71        Ok(Some(normalized))
72    }
73}
74
75impl<'a, Infcx, I, F, E> FallibleTypeFolder<I> for NormalizationFolder<'a, Infcx, I, F>
76where
77    Infcx: InferCtxtLike<Interner = I>,
78    I: Interner,
79    F: FnMut(AliasTerm<I>) -> Result<(I::Term, NormalizationWasAmbiguous), E>,
80    E: Debug,
81{
82    type Error = E;
83
84    fn cx(&self) -> I {
85        self.infcx.cx()
86    }
87
88    fn try_fold_binder<T: TypeFoldable<I>>(
89        &mut self,
90        t: Binder<I, T>,
91    ) -> Result<Binder<I, T>, Self::Error> {
92        self.universes.push(None);
93        let t = t.try_super_fold_with(self)?;
94        self.universes.pop();
95        Ok(t)
96    }
97
98    {}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::TRACE <=
                ::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_next_trait_solver::normalize",
                                ::tracing::Level::TRACE,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_next_trait_solver/src/normalize.rs"),
                                ::tracing_core::__macro_support::Option::Some(98u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_next_trait_solver::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::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::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();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[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<I::Ty, Self::Error> =
                            loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        let infcx = self.infcx;
                        let original = ty;
                        if !self.cx().renormalize_rigid_aliases() &&
                                !ty.has_non_rigid_aliases() {
                            return Ok(ty);
                        }
                        let ty = ty.try_super_fold_with(self)?;
                        let ty::Alias(orig_is_rigid, alias_ty) =
                            ty.kind() else { return Ok(ty) };
                        if !self.cx().renormalize_rigid_aliases() &&
                                orig_is_rigid == ty::IsRigid::Yes {
                            return Ok(ty);
                        }
                        let normalized =
                            if ty.has_escaping_bound_vars() {
                                let (alias_ty, mapped_regions, mapped_types,
                                        mapped_consts) =
                                    BoundVarReplacer::replace_bound_vars(infcx,
                                        &mut self.universes, alias_ty);
                                let Some(result) =
                                    self.normalize_alias_term(alias_ty.into(),
                                            HasEscapingBoundVars::Yes)? else { return Ok(ty); };
                                PlaceholderReplacer::replace_placeholders(infcx,
                                    mapped_regions, mapped_types, mapped_consts,
                                    &self.universes, result.expect_ty())
                            } else {
                                self.normalize_alias_term(alias_ty.into(),
                                                HasEscapingBoundVars::No)?.map(|term|
                                            term.expect_ty()).unwrap_or(ty)
                            };
                        if self.cx().renormalize_rigid_aliases() &&
                                orig_is_rigid == ty::IsRigid::Yes {
                            let original = eager_resolve_vars(infcx, original);
                            let normalized = eager_resolve_vars(infcx, normalized);
                            {
                                match (&original, &normalized) {
                                    (left_val, right_val) => {
                                        if !(*left_val == *right_val) {
                                            let kind = ::core::panicking::AssertKind::Eq;
                                            ::core::panicking::assert_failed(kind, &*left_val,
                                                &*right_val,
                                                ::core::option::Option::Some(format_args!("rigid alias is further normalized")));
                                        }
                                    }
                                }
                            };
                        }
                        Ok(normalized)
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_next_trait_solver/src/normalize.rs:98",
                        "rustc_next_trait_solver::normalize",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_next_trait_solver/src/normalize.rs"),
                        ::tracing_core::__macro_support::Option::Some(98u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_next_trait_solver::normalize"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::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(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[instrument(level = "trace", skip(self), ret)]
99    fn try_fold_ty(&mut self, ty: I::Ty) -> Result<I::Ty, Self::Error> {
100        let infcx = self.infcx;
101        let original = ty;
102
103        if !self.cx().renormalize_rigid_aliases() && !ty.has_non_rigid_aliases() {
104            return Ok(ty);
105        }
106
107        // With eager normalization, we should normalize the args of alias before
108        // normalizing the alias itself.
109        let ty = ty.try_super_fold_with(self)?;
110        let ty::Alias(orig_is_rigid, alias_ty) = ty.kind() else { return Ok(ty) };
111        // We support ambiguous aliases inside rigid alias. So we still recognize
112        // the rigidness of the outer alias.
113        if !self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes {
114            return Ok(ty);
115        }
116
117        let normalized = if ty.has_escaping_bound_vars() {
118            let (alias_ty, mapped_regions, mapped_types, mapped_consts) =
119                BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, alias_ty);
120            let Some(result) =
121                self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::Yes)?
122            else {
123                return Ok(ty);
124            };
125
126            PlaceholderReplacer::replace_placeholders(
127                infcx,
128                mapped_regions,
129                mapped_types,
130                mapped_consts,
131                &self.universes,
132                result.expect_ty(),
133            )
134        } else {
135            self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::No)?
136                .map(|term| term.expect_ty())
137                .unwrap_or(ty)
138        };
139
140        if self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes {
141            // find out missing typing env change.
142            let original = eager_resolve_vars(infcx, original);
143            let normalized = eager_resolve_vars(infcx, normalized);
144            assert_eq!(original, normalized, "rigid alias is further normalized");
145        }
146        Ok(normalized)
147    }
148
149    {}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::TRACE <=
                ::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_const",
                                "rustc_next_trait_solver::normalize",
                                ::tracing::Level::TRACE,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_next_trait_solver/src/normalize.rs"),
                                ::tracing_core::__macro_support::Option::Some(149u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_next_trait_solver::normalize"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("ct")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("ct");
                                                    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::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::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(&ct)
                                                        as &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[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<I::Const, Self::Error> = loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        let infcx = self.infcx;
                        let original = ct;
                        if !self.cx().renormalize_rigid_aliases() &&
                                !ct.has_non_rigid_aliases() {
                            return Ok(ct);
                        }
                        let ct = ct.try_super_fold_with(self)?;
                        let ty::ConstKind::Alias(orig_is_rigid, alias_const) =
                            ct.kind() else { return Ok(ct) };
                        if !self.cx().renormalize_rigid_aliases() &&
                                orig_is_rigid == ty::IsRigid::Yes {
                            return Ok(ct);
                        }
                        let normalized =
                            if ct.has_escaping_bound_vars() {
                                let (alias_const, mapped_regions, mapped_types,
                                        mapped_consts) =
                                    BoundVarReplacer::replace_bound_vars(infcx,
                                        &mut self.universes, alias_const);
                                let Some(result) =
                                    self.normalize_alias_term(alias_const.into(),
                                            HasEscapingBoundVars::Yes)? else { return Ok(ct); };
                                PlaceholderReplacer::replace_placeholders(infcx,
                                    mapped_regions, mapped_types, mapped_consts,
                                    &self.universes, result.expect_const())
                            } else {
                                self.normalize_alias_term(alias_const.into(),
                                                HasEscapingBoundVars::No)?.map(|term|
                                            term.expect_const()).unwrap_or(ct)
                            };
                        if self.cx().renormalize_rigid_aliases() &&
                                orig_is_rigid == ty::IsRigid::Yes {
                            let original = eager_resolve_vars(infcx, original);
                            let normalized = eager_resolve_vars(infcx, normalized);
                            {
                                match (&original, &normalized) {
                                    (left_val, right_val) => {
                                        if !(*left_val == *right_val) {
                                            let kind = ::core::panicking::AssertKind::Eq;
                                            ::core::panicking::assert_failed(kind, &*left_val,
                                                &*right_val,
                                                ::core::option::Option::Some(format_args!("rigid alias is further normalized")));
                                        }
                                    }
                                }
                            };
                        }
                        Ok(normalized)
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_next_trait_solver/src/normalize.rs:149",
                        "rustc_next_trait_solver::normalize",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_next_trait_solver/src/normalize.rs"),
                        ::tracing_core::__macro_support::Option::Some(149u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_next_trait_solver::normalize"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::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(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[instrument(level = "trace", skip(self), ret)]
150    fn try_fold_const(&mut self, ct: I::Const) -> Result<I::Const, Self::Error> {
151        let infcx = self.infcx;
152        let original = ct;
153
154        if !self.cx().renormalize_rigid_aliases() && !ct.has_non_rigid_aliases() {
155            return Ok(ct);
156        }
157
158        // With eager normalization, we should normalize the args of alias before
159        // normalizing the alias itself.
160        let ct = ct.try_super_fold_with(self)?;
161        let ty::ConstKind::Alias(orig_is_rigid, alias_const) = ct.kind() else { return Ok(ct) };
162        // We support ambiguous aliases inside rigid alias. So we still recognize
163        // the rigidness of the outer alias.
164        if !self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes {
165            return Ok(ct);
166        }
167
168        let normalized = if ct.has_escaping_bound_vars() {
169            let (alias_const, mapped_regions, mapped_types, mapped_consts) =
170                BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, alias_const);
171            let Some(result) =
172                self.normalize_alias_term(alias_const.into(), HasEscapingBoundVars::Yes)?
173            else {
174                return Ok(ct);
175            };
176            PlaceholderReplacer::replace_placeholders(
177                infcx,
178                mapped_regions,
179                mapped_types,
180                mapped_consts,
181                &self.universes,
182                result.expect_const(),
183            )
184        } else {
185            self.normalize_alias_term(alias_const.into(), HasEscapingBoundVars::No)?
186                .map(|term| term.expect_const())
187                .unwrap_or(ct)
188        };
189
190        if self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes {
191            // find out missing typing env change.
192            let original = eager_resolve_vars(infcx, original);
193            let normalized = eager_resolve_vars(infcx, normalized);
194            assert_eq!(original, normalized, "rigid alias is further normalized");
195        }
196
197        Ok(normalized)
198    }
199
200    fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error> {
201        if p.allow_normalization() { p.try_super_fold_with(self) } else { Ok(p) }
202    }
203}