rustc_infer/infer/relate/
generalize.rs

1use std::mem;
2
3use rustc_data_structures::sso::SsoHashMap;
4use rustc_data_structures::stack::ensure_sufficient_stack;
5use rustc_hir::def_id::DefId;
6use rustc_middle::bug;
7use rustc_middle::ty::error::TypeError;
8use rustc_middle::ty::{
9    self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
10    TypeVisitableExt, TypeVisitor, TypingMode,
11};
12use rustc_span::Span;
13use tracing::{debug, instrument, warn};
14
15use super::{
16    PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
17};
18use crate::infer::type_variable::TypeVariableValue;
19use crate::infer::unify_key::ConstVariableValue;
20use crate::infer::{InferCtxt, RegionVariableOrigin, relate};
21
22#[derive(#[automatically_derived]
impl ::core::marker::Copy for TermVid { }Copy, #[automatically_derived]
impl ::core::clone::Clone for TermVid {
    #[inline]
    fn clone(&self) -> TermVid {
        let _: ::core::clone::AssertParamIsClone<ty::TyVid>;
        let _: ::core::clone::AssertParamIsClone<ty::ConstVid>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::cmp::Eq for TermVid {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<ty::TyVid>;
        let _: ::core::cmp::AssertParamIsEq<ty::ConstVid>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::PartialEq for TermVid {
    #[inline]
    fn eq(&self, other: &TermVid) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (TermVid::Ty(__self_0), TermVid::Ty(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (TermVid::Const(__self_0), TermVid::Const(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::fmt::Debug for TermVid {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            TermVid::Ty(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Ty",
                    &__self_0),
            TermVid::Const(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Const",
                    &__self_0),
        }
    }
}Debug)]
23enum TermVid {
24    Ty(ty::TyVid),
25    Const(ty::ConstVid),
26}
27
28impl From<ty::TyVid> for TermVid {
29    fn from(value: ty::TyVid) -> Self {
30        TermVid::Ty(value)
31    }
32}
33
34impl From<ty::ConstVid> for TermVid {
35    fn from(value: ty::ConstVid) -> Self {
36        TermVid::Const(value)
37    }
38}
39
40impl<'tcx> InferCtxt<'tcx> {
41    /// The idea is that we should ensure that the type variable `target_vid`
42    /// is equal to, a subtype of, or a supertype of `source_ty`.
43    ///
44    /// For this, we will instantiate `target_vid` with a *generalized* version
45    /// of `source_ty`. Generalization introduces other inference variables wherever
46    /// subtyping could occur. This also does the occurs checks, detecting whether
47    /// instantiating `target_vid` would result in a cyclic type. We eagerly error
48    /// in this case.
49    ///
50    /// This is *not* expected to be used anywhere except for an implementation of
51    /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
52    /// other usecases (i.e. setting the value of a type var).
53    #[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("instantiate_ty_var",
                                    "rustc_infer::infer::relate::generalize",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/generalize.rs"),
                                    ::tracing_core::__macro_support::Option::Some(53u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
                                    ::tracing_core::field::FieldSet::new(&["target_is_expected",
                                                    "target_vid", "instantiation_variance", "source_ty"],
                                        ::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(&target_is_expected
                                                            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(&target_vid)
                                                            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(&instantiation_variance)
                                                            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(&source_ty)
                                                            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: RelateResult<'tcx, ()> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if true {
                if !self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()
                    {
                    ::core::panicking::panic("assertion failed: self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()")
                };
            };
            let Generalization { value_may_be_infer: generalized_ty } =
                self.generalize(relation.span(),
                        relation.structurally_relate_aliases(), target_vid,
                        instantiation_variance, source_ty)?;
            if let &ty::Infer(ty::TyVar(generalized_vid)) =
                    generalized_ty.kind() {
                self.inner.borrow_mut().type_variables().equate(target_vid,
                    generalized_vid);
            } else {
                self.inner.borrow_mut().type_variables().instantiate(target_vid,
                    generalized_ty);
            }
            if generalized_ty.is_ty_var() {
                if self.next_trait_solver() {
                    let (lhs, rhs, direction) =
                        match instantiation_variance {
                            ty::Invariant => {
                                (generalized_ty.into(), source_ty.into(),
                                    AliasRelationDirection::Equate)
                            }
                            ty::Covariant => {
                                (generalized_ty.into(), source_ty.into(),
                                    AliasRelationDirection::Subtype)
                            }
                            ty::Contravariant => {
                                (source_ty.into(), generalized_ty.into(),
                                    AliasRelationDirection::Subtype)
                            }
                            ty::Bivariant => {
                                ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
                                        format_args!("bivariant generalization")));
                            }
                        };
                    relation.register_predicates([ty::PredicateKind::AliasRelate(lhs,
                                    rhs, direction)]);
                } else {
                    match source_ty.kind() {
                        &ty::Alias(ty::Projection, data) => {
                            relation.register_predicates([ty::ProjectionPredicate {
                                            projection_term: data.into(),
                                            term: generalized_ty.into(),
                                        }]);
                        }
                        ty::Alias(ty::Inherent | ty::Free | ty::Opaque, _) => {
                            return Err(TypeError::CyclicTy(source_ty));
                        }
                        _ =>
                            ::rustc_middle::util::bug::bug_fmt(format_args!("generalized `{0:?} to infer, not an alias",
                                    source_ty)),
                    }
                }
            } else {
                if target_is_expected {
                    relation.relate(generalized_ty, source_ty)?;
                } 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_infer/src/infer/relate/generalize.rs:155",
                                            "rustc_infer::infer::relate::generalize",
                                            ::tracing::Level::DEBUG,
                                            ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/generalize.rs"),
                                            ::tracing_core::__macro_support::Option::Some(155u32),
                                            ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
                                            ::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};
                                    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(&format_args!("flip relation")
                                                                as &dyn Value))])
                                });
                        } else { ; }
                    };
                    relation.relate(source_ty, generalized_ty)?;
                }
            }
            Ok(())
        }
    }
}#[instrument(level = "debug", skip(self, relation))]
54    pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
55        &self,
56        relation: &mut R,
57        target_is_expected: bool,
58        target_vid: ty::TyVid,
59        instantiation_variance: ty::Variance,
60        source_ty: Ty<'tcx>,
61    ) -> RelateResult<'tcx, ()> {
62        debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown());
63
64        // Generalize `source_ty` depending on the current variance. As an example, assume
65        // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference
66        // variable.
67        //
68        // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh
69        // region/type inference variables.
70        //
71        // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
72        // `?1 <: ?3`.
73        let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
74            relation.span(),
75            relation.structurally_relate_aliases(),
76            target_vid,
77            instantiation_variance,
78            source_ty,
79        )?;
80
81        // Constrain `b_vid` to the generalized type `generalized_ty`.
82        if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() {
83            self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid);
84        } else {
85            self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty);
86        }
87
88        // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment.
89        //
90        // FIXME(#16847): This code is non-ideal because all these subtype
91        // relations wind up attributed to the same spans. We need
92        // to associate causes/spans with each of the relations in
93        // the stack to get this right.
94        if generalized_ty.is_ty_var() {
95            // This happens for cases like `<?0 as Trait>::Assoc == ?0`.
96            // We can't instantiate `?0` here as that would result in a
97            // cyclic type. We instead delay the unification in case
98            // the alias can be normalized to something which does not
99            // mention `?0`.
100            if self.next_trait_solver() {
101                let (lhs, rhs, direction) = match instantiation_variance {
102                    ty::Invariant => {
103                        (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Equate)
104                    }
105                    ty::Covariant => {
106                        (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Subtype)
107                    }
108                    ty::Contravariant => {
109                        (source_ty.into(), generalized_ty.into(), AliasRelationDirection::Subtype)
110                    }
111                    ty::Bivariant => unreachable!("bivariant generalization"),
112                };
113
114                relation.register_predicates([ty::PredicateKind::AliasRelate(lhs, rhs, direction)]);
115            } else {
116                match source_ty.kind() {
117                    &ty::Alias(ty::Projection, data) => {
118                        // FIXME: This does not handle subtyping correctly, we could
119                        // instead create a new inference variable `?normalized_source`, emitting
120                        // `Projection(normalized_source, ?ty_normalized)` and
121                        // `?normalized_source <: generalized_ty`.
122                        relation.register_predicates([ty::ProjectionPredicate {
123                            projection_term: data.into(),
124                            term: generalized_ty.into(),
125                        }]);
126                    }
127                    // The old solver only accepts projection predicates for associated types.
128                    ty::Alias(ty::Inherent | ty::Free | ty::Opaque, _) => {
129                        return Err(TypeError::CyclicTy(source_ty));
130                    }
131                    _ => bug!("generalized `{source_ty:?} to infer, not an alias"),
132                }
133            }
134        } else {
135            // NOTE: The `instantiation_variance` is not the same variance as
136            // used by the relation. When instantiating `b`, `target_is_expected`
137            // is flipped and the `instantiation_variance` is also flipped. To
138            // constrain the `generalized_ty` while using the original relation,
139            // we therefore only have to flip the arguments.
140            //
141            // ```ignore (not code)
142            // ?a rel B
143            // instantiate_ty_var(?a, B) # expected and variance not flipped
144            // B' rel B
145            // ```
146            // or
147            // ```ignore (not code)
148            // A rel ?b
149            // instantiate_ty_var(?b, A) # expected and variance flipped
150            // A rel A'
151            // ```
152            if target_is_expected {
153                relation.relate(generalized_ty, source_ty)?;
154            } else {
155                debug!("flip relation");
156                relation.relate(source_ty, generalized_ty)?;
157            }
158        }
159
160        Ok(())
161    }
162
163    /// Instantiates the const variable `target_vid` with the given constant.
164    ///
165    /// This also tests if the given const `ct` contains an inference variable which was previously
166    /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct`
167    /// would result in an infinite type as we continuously replace an inference variable
168    /// in `ct` with `ct` itself.
169    ///
170    /// This is especially important as unevaluated consts use their parents generics.
171    /// They therefore often contain unused args, making these errors far more likely.
172    ///
173    /// A good example of this is the following:
174    ///
175    /// ```compile_fail,E0308
176    /// #![feature(generic_const_exprs)]
177    ///
178    /// fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] {
179    ///     todo!()
180    /// }
181    ///
182    /// fn main() {
183    ///     let mut arr = Default::default();
184    ///     arr = bind(arr);
185    /// }
186    /// ```
187    ///
188    /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics
189    /// of `fn bind` (meaning that its args contain `N`).
190    ///
191    /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`.
192    /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`.
193    ///
194    /// As `3 + 4` contains `N` in its args, this must not succeed.
195    ///
196    /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
197    #[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("instantiate_const_var",
                                    "rustc_infer::infer::relate::generalize",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/generalize.rs"),
                                    ::tracing_core::__macro_support::Option::Some(197u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
                                    ::tracing_core::field::FieldSet::new(&["target_is_expected",
                                                    "target_vid", "source_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(&target_is_expected
                                                            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(&target_vid)
                                                            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(&source_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: RelateResult<'tcx, ()> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let Generalization { value_may_be_infer: generalized_ct } =
                self.generalize(relation.span(),
                        relation.structurally_relate_aliases(), target_vid,
                        ty::Invariant, source_ct)?;
            if true {
                if !!generalized_ct.is_ct_infer() {
                    ::core::panicking::panic("assertion failed: !generalized_ct.is_ct_infer()")
                };
            };
            self.inner.borrow_mut().const_unification_table().union_value(target_vid,
                ConstVariableValue::Known { value: generalized_ct });
            if target_is_expected {
                relation.relate_with_variance(ty::Invariant,
                        ty::VarianceDiagInfo::default(), generalized_ct,
                        source_ct)?;
            } else {
                relation.relate_with_variance(ty::Invariant,
                        ty::VarianceDiagInfo::default(), source_ct,
                        generalized_ct)?;
            }
            Ok(())
        }
    }
}#[instrument(level = "debug", skip(self, relation))]
198    pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
199        &self,
200        relation: &mut R,
201        target_is_expected: bool,
202        target_vid: ty::ConstVid,
203        source_ct: ty::Const<'tcx>,
204    ) -> RelateResult<'tcx, ()> {
205        // FIXME(generic_const_exprs): Occurs check failures for unevaluated
206        // constants and generic expressions are not yet handled correctly.
207        let Generalization { value_may_be_infer: generalized_ct } = self.generalize(
208            relation.span(),
209            relation.structurally_relate_aliases(),
210            target_vid,
211            ty::Invariant,
212            source_ct,
213        )?;
214
215        debug_assert!(!generalized_ct.is_ct_infer());
216
217        self.inner
218            .borrow_mut()
219            .const_unification_table()
220            .union_value(target_vid, ConstVariableValue::Known { value: generalized_ct });
221
222        // Make sure that the order is correct when relating the
223        // generalized const and the source.
224        if target_is_expected {
225            relation.relate_with_variance(
226                ty::Invariant,
227                ty::VarianceDiagInfo::default(),
228                generalized_ct,
229                source_ct,
230            )?;
231        } else {
232            relation.relate_with_variance(
233                ty::Invariant,
234                ty::VarianceDiagInfo::default(),
235                source_ct,
236                generalized_ct,
237            )?;
238        }
239
240        Ok(())
241    }
242
243    /// Attempts to generalize `source_term` for the type variable `target_vid`.
244    /// This checks for cycles -- that is, whether `source_term` references `target_vid`.
245    fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'tcx>>>(
246        &self,
247        span: Span,
248        structurally_relate_aliases: StructurallyRelateAliases,
249        target_vid: impl Into<TermVid>,
250        ambient_variance: ty::Variance,
251        source_term: T,
252    ) -> RelateResult<'tcx, Generalization<T>> {
253        if !!source_term.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !source_term.has_escaping_bound_vars()")
};assert!(!source_term.has_escaping_bound_vars());
254        let (for_universe, root_vid) = match target_vid.into() {
255            TermVid::Ty(ty_vid) => {
256                (self.probe_ty_var(ty_vid).unwrap_err(), TermVid::Ty(self.root_var(ty_vid)))
257            }
258            TermVid::Const(ct_vid) => (
259                self.probe_const_var(ct_vid).unwrap_err(),
260                TermVid::Const(self.inner.borrow_mut().const_unification_table().find(ct_vid).vid),
261            ),
262        };
263
264        let mut generalizer = Generalizer {
265            infcx: self,
266            span,
267            structurally_relate_aliases,
268            root_vid,
269            for_universe,
270            root_term: source_term.into(),
271            ambient_variance,
272            in_alias: false,
273            cache: Default::default(),
274        };
275
276        let value_may_be_infer = generalizer.relate(source_term, source_term)?;
277        Ok(Generalization { value_may_be_infer })
278    }
279}
280
281/// Finds the max universe present
282struct MaxUniverse {
283    max_universe: ty::UniverseIndex,
284}
285
286impl MaxUniverse {
287    fn new() -> Self {
288        MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
289    }
290
291    fn max_universe(self) -> ty::UniverseIndex {
292        self.max_universe
293    }
294}
295
296impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse {
297    fn visit_ty(&mut self, t: Ty<'tcx>) {
298        if let ty::Placeholder(placeholder) = t.kind() {
299            self.max_universe = self.max_universe.max(placeholder.universe);
300        }
301
302        t.super_visit_with(self)
303    }
304
305    fn visit_const(&mut self, c: ty::Const<'tcx>) {
306        if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
307            self.max_universe = self.max_universe.max(placeholder.universe);
308        }
309
310        c.super_visit_with(self)
311    }
312
313    fn visit_region(&mut self, r: ty::Region<'tcx>) {
314        if let ty::RePlaceholder(placeholder) = r.kind() {
315            self.max_universe = self.max_universe.max(placeholder.universe);
316        }
317    }
318}
319
320/// The "generalizer" is used when handling inference variables.
321///
322/// The basic strategy for handling a constraint like `?A <: B` is to
323/// apply a "generalization strategy" to the term `B` -- this replaces
324/// all the lifetimes in the term `B` with fresh inference variables.
325/// (You can read more about the strategy in this [blog post].)
326///
327/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
328/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
329/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
330/// establishes `'0: 'x` as a constraint.
331///
332/// [blog post]: https://is.gd/0hKvIr
333struct Generalizer<'me, 'tcx> {
334    infcx: &'me InferCtxt<'tcx>,
335
336    span: Span,
337
338    /// Whether aliases should be related structurally. If not, we have to
339    /// be careful when generalizing aliases.
340    structurally_relate_aliases: StructurallyRelateAliases,
341
342    /// The vid of the type variable that is in the process of being
343    /// instantiated. If we find this within the value we are folding,
344    /// that means we would have created a cyclic value.
345    root_vid: TermVid,
346
347    /// The universe of the type variable that is in the process of being
348    /// instantiated. If we find anything that this universe cannot name,
349    /// we reject the relation.
350    for_universe: ty::UniverseIndex,
351
352    /// The root term (const or type) we're generalizing. Used for cycle errors.
353    root_term: Term<'tcx>,
354
355    /// After we generalize this type, we are going to relate it to
356    /// some other type. What will be the variance at this point?
357    ambient_variance: ty::Variance,
358
359    /// This is set once we're generalizing the arguments of an alias.
360    ///
361    /// This is necessary to correctly handle
362    /// `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. This equality can
363    /// hold by either normalizing the outer or the inner associated type.
364    in_alias: bool,
365
366    cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>,
367}
368
369impl<'tcx> Generalizer<'_, 'tcx> {
370    /// Create an error that corresponds to the term kind in `root_term`
371    fn cyclic_term_error(&self) -> TypeError<'tcx> {
372        match self.root_term.kind() {
373            ty::TermKind::Ty(ty) => TypeError::CyclicTy(ty),
374            ty::TermKind::Const(ct) => TypeError::CyclicConst(ct),
375        }
376    }
377
378    /// Create a new type variable in the universe of the target when
379    /// generalizing an alias.
380    fn next_ty_var_for_alias(&self) -> Ty<'tcx> {
381        self.infcx.next_ty_var_in_universe(self.span, self.for_universe)
382    }
383
384    /// An occurs check failure inside of an alias does not mean
385    /// that the types definitely don't unify. We may be able
386    /// to normalize the alias after all.
387    ///
388    /// We handle this by lazily equating the alias and generalizing
389    /// it to an inference variable. In the new solver, we always
390    /// generalize to an infer var unless the alias contains escaping
391    /// bound variables.
392    ///
393    /// Correctly handling aliases with escaping bound variables is
394    /// difficult and currently incomplete in two opposite ways:
395    /// - if we get an occurs check failure in the alias, replace it with a new infer var.
396    ///   This causes us to later emit an alias-relate goal and is incomplete in case the
397    ///   alias normalizes to type containing one of the bound variables.
398    /// - if the alias contains an inference variable not nameable by `for_universe`, we
399    ///   continue generalizing the alias. This ends up pulling down the universe of the
400    ///   inference variable and is incomplete in case the alias would normalize to a type
401    ///   which does not mention that inference variable.
402    fn generalize_alias_ty(
403        &mut self,
404        alias: ty::AliasTy<'tcx>,
405    ) -> Result<Ty<'tcx>, TypeError<'tcx>> {
406        // We do not eagerly replace aliases with inference variables if they have
407        // escaping bound vars, see the method comment for details. However, when we
408        // are inside of an alias with escaping bound vars replacing nested aliases
409        // with inference variables can cause incorrect ambiguity.
410        //
411        // cc trait-system-refactor-initiative#110
412        if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias {
413            return Ok(self.next_ty_var_for_alias());
414        }
415
416        let is_nested_alias = mem::replace(&mut self.in_alias, true);
417        let result = match self.relate(alias, alias) {
418            Ok(alias) => Ok(alias.to_ty(self.cx())),
419            Err(e) => {
420                if is_nested_alias {
421                    return Err(e);
422                } else {
423                    let mut visitor = MaxUniverse::new();
424                    alias.visit_with(&mut visitor);
425                    let infer_replacement_is_complete =
426                        self.for_universe.can_name(visitor.max_universe())
427                            && !alias.has_escaping_bound_vars();
428                    if !infer_replacement_is_complete {
429                        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_infer/src/infer/relate/generalize.rs:429",
                        "rustc_infer::infer::relate::generalize",
                        ::tracing::Level::WARN,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/generalize.rs"),
                        ::tracing_core::__macro_support::Option::Some(429u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::WARN <=
                    ::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(&format_args!("may incompletely handle alias type: {0:?}",
                                                    alias) as &dyn Value))])
            });
    } else { ; }
};warn!("may incompletely handle alias type: {alias:?}");
430                    }
431
432                    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_infer/src/infer/relate/generalize.rs:432",
                        "rustc_infer::infer::relate::generalize",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/generalize.rs"),
                        ::tracing_core::__macro_support::Option::Some(432u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
                        ::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};
                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(&format_args!("generalization failure in alias")
                                            as &dyn Value))])
            });
    } else { ; }
};debug!("generalization failure in alias");
433                    Ok(self.next_ty_var_for_alias())
434                }
435            }
436        };
437        self.in_alias = is_nested_alias;
438        result
439    }
440}
441
442impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
443    fn cx(&self) -> TyCtxt<'tcx> {
444        self.infcx.tcx
445    }
446
447    fn relate_ty_args(
448        &mut self,
449        a_ty: Ty<'tcx>,
450        _: Ty<'tcx>,
451        def_id: DefId,
452        a_args: ty::GenericArgsRef<'tcx>,
453        b_args: ty::GenericArgsRef<'tcx>,
454        mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
455    ) -> RelateResult<'tcx, Ty<'tcx>> {
456        let args = if self.ambient_variance == ty::Invariant {
457            // Avoid fetching the variance if we are in an invariant
458            // context; no need, and it can induce dependency cycles
459            // (e.g., #41849).
460            relate::relate_args_invariantly(self, a_args, b_args)
461        } else {
462            let tcx = self.cx();
463            let variances = tcx.variances_of(def_id);
464            relate::relate_args_with_variances(self, variances, a_args, b_args)
465        }?;
466        if args == a_args { Ok(a_ty) } else { Ok(mk(args)) }
467    }
468
469    x;#[instrument(level = "debug", skip(self, variance, b), ret)]
470    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
471        &mut self,
472        variance: ty::Variance,
473        _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
474        a: T,
475        b: T,
476    ) -> RelateResult<'tcx, T> {
477        let old_ambient_variance = self.ambient_variance;
478        self.ambient_variance = self.ambient_variance.xform(variance);
479        debug!(?self.ambient_variance, "new ambient variance");
480        // Recursive calls to `relate` can overflow the stack. For example a deeper version of
481        // `ui/associated-consts/issue-93775.rs`.
482        let r = ensure_sufficient_stack(|| self.relate(a, b));
483        self.ambient_variance = old_ambient_variance;
484        r
485    }
486
487    x;#[instrument(level = "debug", skip(self, t2), ret)]
488    fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
489        assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
490
491        if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) {
492            return Ok(result);
493        }
494
495        // Check to see whether the type we are generalizing references
496        // any other type variable related to `vid` via
497        // subtyping. This is basically our "occurs check", preventing
498        // us from creating infinitely sized types.
499        let g = match *t.kind() {
500            ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
501                bug!("unexpected infer type: {t}")
502            }
503
504            ty::Infer(ty::TyVar(vid)) => {
505                let mut inner = self.infcx.inner.borrow_mut();
506                let vid = inner.type_variables().root_var(vid);
507                if TermVid::Ty(vid) == self.root_vid {
508                    // If sub-roots are equal, then `root_vid` and
509                    // `vid` are related via subtyping.
510                    Err(self.cyclic_term_error())
511                } else {
512                    let probe = inner.type_variables().probe(vid);
513                    match probe {
514                        TypeVariableValue::Known { value: u } => {
515                            drop(inner);
516                            self.relate(u, u)
517                        }
518                        TypeVariableValue::Unknown { universe } => {
519                            match self.ambient_variance {
520                                // Invariant: no need to make a fresh type variable
521                                // if we can name the universe.
522                                ty::Invariant => {
523                                    if self.for_universe.can_name(universe) {
524                                        return Ok(t);
525                                    }
526                                }
527
528                                // We do need a fresh type variable otherwise.
529                                ty::Bivariant | ty::Covariant | ty::Contravariant => (),
530                            }
531
532                            let origin = inner.type_variables().var_origin(vid);
533                            let new_var_id =
534                                inner.type_variables().new_var(self.for_universe, origin);
535                            // Record that `vid` and `new_var_id` have to be subtypes
536                            // of each other. This is currently only used for diagnostics.
537                            // To see why, see the docs in the `type_variables` module.
538                            inner.type_variables().sub_unify(vid, new_var_id);
539                            // If we're in the new solver and create a new inference
540                            // variable inside of an alias we eagerly constrain that
541                            // inference variable to prevent unexpected ambiguity errors.
542                            //
543                            // This is incomplete as it pulls down the universe of the
544                            // original inference variable, even though the alias could
545                            // normalize to a type which does not refer to that type at
546                            // all. I don't expect this to cause unexpected errors in
547                            // practice.
548                            //
549                            // We only need to do so for type and const variables, as
550                            // region variables do not impact normalization, and will get
551                            // correctly constrained by `AliasRelate` later on.
552                            //
553                            // cc trait-system-refactor-initiative#108
554                            if self.infcx.next_trait_solver()
555                                && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
556                                && self.in_alias
557                            {
558                                inner.type_variables().equate(vid, new_var_id);
559                            }
560
561                            debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
562                            Ok(Ty::new_var(self.cx(), new_var_id))
563                        }
564                    }
565                }
566            }
567
568            ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
569                // No matter what mode we are in,
570                // integer/floating-point types must be equal to be
571                // relatable.
572                Ok(t)
573            }
574
575            ty::Placeholder(placeholder) => {
576                if self.for_universe.can_name(placeholder.universe) {
577                    Ok(t)
578                } else {
579                    debug!(
580                        "root universe {:?} cannot name placeholder in universe {:?}",
581                        self.for_universe, placeholder.universe
582                    );
583                    Err(TypeError::Mismatch)
584                }
585            }
586
587            ty::Alias(_, data) => match self.structurally_relate_aliases {
588                StructurallyRelateAliases::No => self.generalize_alias_ty(data),
589                StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t),
590            },
591
592            _ => relate::structurally_relate_tys(self, t, t),
593        }?;
594
595        self.cache.insert((t, self.ambient_variance, self.in_alias), g);
596        Ok(g)
597    }
598
599    x;#[instrument(level = "debug", skip(self, r2), ret)]
600    fn regions(
601        &mut self,
602        r: ty::Region<'tcx>,
603        r2: ty::Region<'tcx>,
604    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
605        assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
606
607        match r.kind() {
608            // Never make variables for regions bound within the type itself,
609            // nor for erased regions.
610            ty::ReBound(..) | ty::ReErased => {
611                return Ok(r);
612            }
613
614            // It doesn't really matter for correctness if we generalize ReError,
615            // since we're already on a doomed compilation path.
616            ty::ReError(_) => {
617                return Ok(r);
618            }
619
620            ty::RePlaceholder(..)
621            | ty::ReVar(..)
622            | ty::ReStatic
623            | ty::ReEarlyParam(..)
624            | ty::ReLateParam(..) => {
625                // see common code below
626            }
627        }
628
629        // If we are in an invariant context, we can re-use the region
630        // as is, unless it happens to be in some universe that we
631        // can't name.
632        if let ty::Invariant = self.ambient_variance {
633            let r_universe = self.infcx.universe_of_region(r);
634            if self.for_universe.can_name(r_universe) {
635                return Ok(r);
636            }
637        }
638
639        Ok(self
640            .infcx
641            .next_region_var_in_universe(RegionVariableOrigin::Misc(self.span), self.for_universe))
642    }
643
644    x;#[instrument(level = "debug", skip(self, c2), ret)]
645    fn consts(
646        &mut self,
647        c: ty::Const<'tcx>,
648        c2: ty::Const<'tcx>,
649    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
650        assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
651
652        match c.kind() {
653            ty::ConstKind::Infer(InferConst::Var(vid)) => {
654                // If root const vids are equal, then `root_vid` and
655                // `vid` are related and we'd be inferring an infinitely
656                // deep const.
657                if TermVid::Const(
658                    self.infcx.inner.borrow_mut().const_unification_table().find(vid).vid,
659                ) == self.root_vid
660                {
661                    return Err(self.cyclic_term_error());
662                }
663
664                let mut inner = self.infcx.inner.borrow_mut();
665                let variable_table = &mut inner.const_unification_table();
666                match variable_table.probe_value(vid) {
667                    ConstVariableValue::Known { value: u } => {
668                        drop(inner);
669                        self.relate(u, u)
670                    }
671                    ConstVariableValue::Unknown { origin, universe } => {
672                        if self.for_universe.can_name(universe) {
673                            Ok(c)
674                        } else {
675                            let new_var_id = variable_table
676                                .new_key(ConstVariableValue::Unknown {
677                                    origin,
678                                    universe: self.for_universe,
679                                })
680                                .vid;
681
682                            // See the comment for type inference variables
683                            // for more details.
684                            if self.infcx.next_trait_solver()
685                                && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
686                                && self.in_alias
687                            {
688                                variable_table.union(vid, new_var_id);
689                            }
690                            Ok(ty::Const::new_var(self.cx(), new_var_id))
691                        }
692                    }
693                }
694            }
695            // FIXME: Unevaluated constants are also not rigid, so the current
696            // approach of always relating them structurally is incomplete.
697            //
698            // FIXME: remove this branch once `structurally_relate_consts` is fully
699            // structural.
700            ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
701                let args = self.relate_with_variance(
702                    ty::Invariant,
703                    ty::VarianceDiagInfo::default(),
704                    args,
705                    args,
706                )?;
707                Ok(ty::Const::new_unevaluated(self.cx(), ty::UnevaluatedConst { def, args }))
708            }
709            ty::ConstKind::Placeholder(placeholder) => {
710                if self.for_universe.can_name(placeholder.universe) {
711                    Ok(c)
712                } else {
713                    debug!(
714                        "root universe {:?} cannot name placeholder in universe {:?}",
715                        self.for_universe, placeholder.universe
716                    );
717                    Err(TypeError::Mismatch)
718                }
719            }
720            _ => relate::structurally_relate_consts(self, c, c),
721        }
722    }
723
724    x;#[instrument(level = "debug", skip(self), ret)]
725    fn binders<T>(
726        &mut self,
727        a: ty::Binder<'tcx, T>,
728        _: ty::Binder<'tcx, T>,
729    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
730    where
731        T: Relate<TyCtxt<'tcx>>,
732    {
733        let result = self.relate(a.skip_binder(), a.skip_binder())?;
734        Ok(a.rebind(result))
735    }
736}
737
738/// Result from a generalization operation. This includes
739/// not only the generalized type, but also a bool flag
740/// indicating whether further WF checks are needed.
741#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for Generalization<T> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "Generalization", "value_may_be_infer", &&self.value_may_be_infer)
    }
}Debug)]
742struct Generalization<T> {
743    /// When generalizing `<?0 as Trait>::Assoc` or
744    /// `<T as Bar<<?0 as Foo>::Assoc>>::Assoc`
745    /// for `?0` generalization returns an inference
746    /// variable.
747    ///
748    /// This has to be handled with care as it can
749    /// otherwise very easily result in infinite
750    /// recursion.
751    pub value_may_be_infer: T,
752}