Skip to main content

rustc_type_ir/relate/
solver_relating.rs

1use tracing::{debug, instrument};
2
3use self::combine::{PredicateEmittingRelation, super_combine_consts, super_combine_tys};
4use crate::data_structures::DelayedSet;
5use crate::relate::combine::combine_ty_args;
6pub use crate::relate::*;
7use crate::solve::{Goal, VisibleForLeakCheck};
8use crate::{self as ty, InferCtxtLike, Interner, Region};
9
10pub trait RelateExt: InferCtxtLike {
11    fn relate<T: Relate<Self::Interner>>(
12        &self,
13        param_env: <Self::Interner as Interner>::ParamEnv,
14        lhs: T,
15        variance: ty::Variance,
16        rhs: T,
17        span: <Self::Interner as Interner>::Span,
18    ) -> Result<
19        Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
20        TypeError<Self::Interner>,
21    >;
22}
23
24impl<Infcx: InferCtxtLike> RelateExt for Infcx {
25    fn relate<T: Relate<Self::Interner>>(
26        &self,
27        param_env: <Self::Interner as Interner>::ParamEnv,
28        lhs: T,
29        variance: ty::Variance,
30        rhs: T,
31        span: <Self::Interner as Interner>::Span,
32    ) -> Result<
33        Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
34        TypeError<Self::Interner>,
35    > {
36        let mut relate = SolverRelating::new(self, variance, param_env, span);
37        relate.relate(lhs, rhs)?;
38        Ok(relate.goals)
39    }
40}
41
42/// Enforce that `a` is equal to or a subtype of `b`.
43pub struct SolverRelating<'infcx, Infcx, I: Interner> {
44    infcx: &'infcx Infcx,
45    // Immutable fields.
46    param_env: I::ParamEnv,
47    span: I::Span,
48    // Mutable fields.
49    ambient_variance: ty::Variance,
50    goals: Vec<Goal<I, I::Predicate>>,
51    /// The cache only tracks the `ambient_variance` as it's the
52    /// only field which is mutable and which meaningfully changes
53    /// the result when relating types.
54    ///
55    /// The cache does not track whether the state of the
56    /// `Infcx` has been changed or whether we've added any
57    /// goals to `self.goals`. Whether a goal is added once or multiple
58    /// times is not really meaningful.
59    ///
60    /// Changes in the inference state may delay some type inference to
61    /// the next fulfillment loop. Given that this loop is already
62    /// necessary, this is also not a meaningful change. Consider
63    /// the following three relations:
64    /// ```text
65    /// Vec<?0> sub Vec<?1>
66    /// ?0 eq u32
67    /// Vec<?0> sub Vec<?1>
68    /// ```
69    /// Without a cache, the second `Vec<?0> sub Vec<?1>` would eagerly
70    /// constrain `?1` to `u32`. When using the cache entry from the
71    /// first time we've related these types, this only happens when
72    /// later proving the `Subtype(?0, ?1)` goal from the first relation.
73    cache: DelayedSet<(ty::Variance, I::Ty, I::Ty)>,
74}
75
76impl<'infcx, Infcx, I> SolverRelating<'infcx, Infcx, I>
77where
78    Infcx: InferCtxtLike<Interner = I>,
79    I: Interner,
80{
81    pub fn new(
82        infcx: &'infcx Infcx,
83        ambient_variance: ty::Variance,
84        param_env: I::ParamEnv,
85        span: I::Span,
86    ) -> Self {
87        SolverRelating {
88            infcx,
89            span,
90            ambient_variance,
91            param_env,
92            goals: ::alloc::vec::Vec::new()vec![],
93            cache: Default::default(),
94        }
95    }
96}
97
98impl<Infcx, I> TypeRelation<I> for SolverRelating<'_, Infcx, I>
99where
100    Infcx: InferCtxtLike<Interner = I>,
101    I: Interner,
102{
103    fn cx(&self) -> I {
104        self.infcx.cx()
105    }
106
107    fn relate_ty_args(
108        &mut self,
109        a_ty: I::Ty,
110        b_ty: I::Ty,
111        def_id: I::DefId,
112        a_args: I::GenericArgs,
113        b_args: I::GenericArgs,
114        _: impl FnOnce(I::GenericArgs) -> I::Ty,
115    ) -> RelateResult<I, I::Ty> {
116        if self.ambient_variance == ty::Invariant {
117            // Avoid fetching the variance if we are in an invariant
118            // context; no need, and it can induce dependency cycles
119            // (e.g., #41849).
120            relate_args_invariantly(self, a_args, b_args)?;
121            Ok(a_ty)
122        } else {
123            let variances = self.cx().variances_of(def_id);
124            combine_ty_args(self.infcx, self, a_ty, b_ty, variances, a_args, b_args, |_| a_ty)
125        }
126    }
127    fn relate_with_variance<T: Relate<I>>(
128        &mut self,
129        variance: ty::Variance,
130        _info: VarianceDiagInfo<I>,
131        a: T,
132        b: T,
133    ) -> RelateResult<I, T> {
134        let old_ambient_variance = self.ambient_variance;
135        self.ambient_variance = self.ambient_variance.xform(variance);
136        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_type_ir/src/relate/solver_relating.rs:136",
                        "rustc_type_ir::relate::solver_relating",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/relate/solver_relating.rs"),
                        ::tracing_core::__macro_support::Option::Some(136u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate::solver_relating"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("self.ambient_variance")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("self.ambient_variance");
                                            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(&format_args!("new ambient variance")
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.ambient_variance)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?self.ambient_variance, "new ambient variance");
137
138        let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) };
139
140        self.ambient_variance = old_ambient_variance;
141        r
142    }
143
144    #[allow(clippy :: suspicious_else_formatting)]
{
    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("tys",
                                    "rustc_type_ir::relate::solver_relating",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/relate/solver_relating.rs"),
                                    ::tracing_core::__macro_support::Option::Some(144u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate::solver_relating"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("a")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("a");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("b")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("b");
                                                        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(&a)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&b)
                                                            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: RelateResult<I, I::Ty> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if a == b { return Ok(a); }
            let infcx = self.infcx;
            let a = infcx.shallow_resolve(a);
            let b = infcx.shallow_resolve(b);
            if self.cache.contains(&(self.ambient_variance, a, b)) {
                return Ok(a);
            }
            match (a.kind(), b.kind()) {
                (ty::Infer(ty::TyVar(a_id)), ty::Infer(ty::TyVar(b_id))) => {
                    match self.ambient_variance {
                        ty::Covariant => {
                            self.goals.push(Goal::new(self.cx(), self.param_env,
                                    ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
                                                a_is_expected: true,
                                                a,
                                                b,
                                            }))));
                        }
                        ty::Contravariant => {
                            self.goals.push(Goal::new(self.cx(), self.param_env,
                                    ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
                                                a_is_expected: false,
                                                a: b,
                                                b: a,
                                            }))));
                        }
                        ty::Invariant => { infcx.equate_ty_vids_raw(a_id, b_id); }
                        ty::Bivariant => {
                            {
                                ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
                                        format_args!("Expected bivariance to be handled in relate_with_variance")));
                            }
                        }
                    }
                }
                (ty::Infer(ty::TyVar(a_vid)), _) => {
                    infcx.instantiate_ty_var(self, true, a_vid,
                            self.ambient_variance, b)?;
                }
                (_, ty::Infer(ty::TyVar(b_vid))) => {
                    infcx.instantiate_ty_var(self, false, b_vid,
                            self.ambient_variance.xform(ty::Contravariant), a)?;
                }
                _ => { super_combine_tys(self.infcx, self, a, b)?; }
            }
            if !self.cache.insert((self.ambient_variance, a, b)) {
                ::core::panicking::panic("assertion failed: self.cache.insert((self.ambient_variance, a, b))")
            };
            Ok(a)
        }
    }
}#[instrument(skip(self), level = "trace")]
145    fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty> {
146        if a == b {
147            return Ok(a);
148        }
149
150        let infcx = self.infcx;
151        let a = infcx.shallow_resolve(a);
152        let b = infcx.shallow_resolve(b);
153
154        if self.cache.contains(&(self.ambient_variance, a, b)) {
155            return Ok(a);
156        }
157
158        match (a.kind(), b.kind()) {
159            (ty::Infer(ty::TyVar(a_id)), ty::Infer(ty::TyVar(b_id))) => {
160                match self.ambient_variance {
161                    ty::Covariant => {
162                        // can't make progress on `A <: B` if both A and B are
163                        // type variables, so record an obligation.
164                        self.goals.push(Goal::new(
165                            self.cx(),
166                            self.param_env,
167                            ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
168                                a_is_expected: true,
169                                a,
170                                b,
171                            })),
172                        ));
173                    }
174                    ty::Contravariant => {
175                        // can't make progress on `B <: A` if both A and B are
176                        // type variables, so record an obligation.
177                        self.goals.push(Goal::new(
178                            self.cx(),
179                            self.param_env,
180                            ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
181                                a_is_expected: false,
182                                a: b,
183                                b: a,
184                            })),
185                        ));
186                    }
187                    ty::Invariant => {
188                        infcx.equate_ty_vids_raw(a_id, b_id);
189                    }
190                    ty::Bivariant => {
191                        unreachable!("Expected bivariance to be handled in relate_with_variance")
192                    }
193                }
194            }
195
196            (ty::Infer(ty::TyVar(a_vid)), _) => {
197                infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?;
198            }
199            (_, ty::Infer(ty::TyVar(b_vid))) => {
200                infcx.instantiate_ty_var(
201                    self,
202                    false,
203                    b_vid,
204                    self.ambient_variance.xform(ty::Contravariant),
205                    a,
206                )?;
207            }
208
209            _ => {
210                super_combine_tys(self.infcx, self, a, b)?;
211            }
212        }
213
214        assert!(self.cache.insert((self.ambient_variance, a, b)));
215
216        Ok(a)
217    }
218
219    #[allow(clippy :: suspicious_else_formatting)]
{
    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("regions",
                                    "rustc_type_ir::relate::solver_relating",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/relate/solver_relating.rs"),
                                    ::tracing_core::__macro_support::Option::Some(219u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate::solver_relating"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("a")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("a");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("b")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("b");
                                                        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(&a)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&b)
                                                            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: RelateResult<I, Region<I>> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            match self.ambient_variance {
                ty::Covariant =>
                    self.infcx.sub_regions(b, a, VisibleForLeakCheck::Yes,
                        self.span),
                ty::Contravariant =>
                    self.infcx.sub_regions(a, b, VisibleForLeakCheck::Yes,
                        self.span),
                ty::Invariant =>
                    self.infcx.equate_regions(a, b, VisibleForLeakCheck::Yes,
                        self.span),
                ty::Bivariant => {
                    {
                        ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
                                format_args!("Expected bivariance to be handled in relate_with_variance")));
                    }
                }
            }
            Ok(a)
        }
    }
}#[instrument(skip(self), level = "trace")]
220    fn regions(&mut self, a: Region<I>, b: Region<I>) -> RelateResult<I, Region<I>> {
221        match self.ambient_variance {
222            // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
223            ty::Covariant => self.infcx.sub_regions(b, a, VisibleForLeakCheck::Yes, self.span),
224            // Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b)
225            ty::Contravariant => self.infcx.sub_regions(a, b, VisibleForLeakCheck::Yes, self.span),
226            ty::Invariant => self.infcx.equate_regions(a, b, VisibleForLeakCheck::Yes, self.span),
227            ty::Bivariant => {
228                unreachable!("Expected bivariance to be handled in relate_with_variance")
229            }
230        }
231
232        Ok(a)
233    }
234
235    #[allow(clippy :: suspicious_else_formatting)]
{
    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("consts",
                                    "rustc_type_ir::relate::solver_relating",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/relate/solver_relating.rs"),
                                    ::tracing_core::__macro_support::Option::Some(235u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate::solver_relating"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("a")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("a");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("b")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("b");
                                                        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(&a)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&b)
                                                            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: RelateResult<I, I::Const> =
                loop {};
            return __tracing_attr_fake_return;
        }
        { super_combine_consts(self.infcx, self, a, b) }
    }
}#[instrument(skip(self), level = "trace")]
236    fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const> {
237        super_combine_consts(self.infcx, self, a, b)
238    }
239
240    fn binders<T>(
241        &mut self,
242        a: ty::Binder<I, T>,
243        b: ty::Binder<I, T>,
244    ) -> RelateResult<I, ty::Binder<I, T>>
245    where
246        T: Relate<I>,
247    {
248        // If they're equal, then short-circuit.
249        if a == b {
250            return Ok(a);
251        }
252
253        // If they have no bound vars, relate normally.
254        if let Some(a_inner) = a.no_bound_vars()
255            && let Some(b_inner) = b.no_bound_vars()
256        {
257            self.relate(a_inner, b_inner)?;
258            return Ok(a);
259        }
260
261        match self.ambient_variance {
262            // Checks whether `for<..> sub <: for<..> sup` holds.
263            //
264            // For this to hold, **all** instantiations of the super type
265            // have to be a super type of **at least one** instantiation of
266            // the subtype.
267            //
268            // This is implemented by first entering a new universe.
269            // We then replace all bound variables in `sup` with placeholders,
270            // and all bound variables in `sub` with inference vars.
271            // We can then just relate the two resulting types as normal.
272            //
273            // Note: this is a subtle algorithm. For a full explanation, please see
274            // the [rustc dev guide][rd]
275            //
276            // [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html
277            ty::Covariant => {
278                self.infcx.enter_forall_with_empty_assumptions(b, |b| {
279                    let a = self.infcx.instantiate_binder_with_infer(a);
280                    self.relate(a, b)
281                })?;
282            }
283            ty::Contravariant => {
284                self.infcx.enter_forall_with_empty_assumptions(a, |a| {
285                    let b = self.infcx.instantiate_binder_with_infer(b);
286                    self.relate(a, b)
287                })?;
288            }
289
290            // When **equating** binders, we check that there is a 1-to-1
291            // correspondence between the bound vars in both types.
292            //
293            // We do so by separately instantiating one of the binders with
294            // placeholders and the other with inference variables and then
295            // equating the instantiated types.
296            //
297            // We want `for<..> A == for<..> B` -- therefore we want
298            // `exists<..> A == for<..> B` and `exists<..> B == for<..> A`.
299            // Check if `exists<..> A == for<..> B`
300            ty::Invariant => {
301                self.infcx.enter_forall_with_empty_assumptions(b, |b| {
302                    let a = self.infcx.instantiate_binder_with_infer(a);
303                    self.relate(a, b)
304                })?;
305
306                // Check if `exists<..> B == for<..> A`.
307                self.infcx.enter_forall_with_empty_assumptions(a, |a| {
308                    let b = self.infcx.instantiate_binder_with_infer(b);
309                    self.relate(a, b)
310                })?;
311            }
312            ty::Bivariant => {
313                {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Expected bivariance to be handled in relate_with_variance")));
}unreachable!("Expected bivariance to be handled in relate_with_variance")
314            }
315        }
316        Ok(a)
317    }
318}
319
320impl<Infcx, I> PredicateEmittingRelation<Infcx> for SolverRelating<'_, Infcx, I>
321where
322    Infcx: InferCtxtLike<Interner = I>,
323    I: Interner,
324{
325    fn span(&self) -> I::Span {
326        Span::dummy()
327    }
328
329    fn param_env(&self) -> I::ParamEnv {
330        self.param_env
331    }
332
333    fn register_predicates(
334        &mut self,
335        obligations: impl IntoIterator<Item: ty::Upcast<I, I::Predicate>>,
336    ) {
337        self.goals.extend(
338            obligations.into_iter().map(|pred| Goal::new(self.infcx.cx(), self.param_env, pred)),
339        );
340    }
341
342    fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>) {
343        self.goals.extend(obligations);
344    }
345
346    fn ambient_variance(&self) -> ty::Variance {
347        self.ambient_variance
348    }
349}