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