Skip to main content

rustc_infer/infer/relate/
lattice.rs

1//! # Lattice variables
2//!
3//! Generic code for operating on [lattices] of inference variables
4//! that are characterized by an upper- and lower-bound.
5//!
6//! The code is defined quite generically so that it can be
7//! applied both to type variables, which represent types being inferred,
8//! and fn variables, which represent function types being inferred.
9//! (It may eventually be applied to their types as well.)
10//! In some cases, the functions are also generic with respect to the
11//! operation on the lattice (GLB vs LUB).
12//!
13//! ## Note
14//!
15//! Although all the functions are generic, for simplicity, comments in the source code
16//! generally refer to type variables and the LUB operation.
17//!
18//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
19
20use rustc_hir::def_id::DefId;
21use rustc_middle::traits::solve::Goal;
22use rustc_middle::ty::relate::combine::{combine_ty_args, super_combine_consts, super_combine_tys};
23use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
24use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
25use rustc_span::Span;
26use tracing::{debug, instrument};
27
28use super::combine::PredicateEmittingRelation;
29use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace};
30use crate::traits::{Obligation, PredicateObligations};
31
32#[derive(#[automatically_derived]
impl ::core::clone::Clone for LatticeOpKind {
    #[inline]
    fn clone(&self) -> LatticeOpKind { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for LatticeOpKind { }Copy)]
33pub(crate) enum LatticeOpKind {
34    Glb,
35    Lub,
36}
37
38impl LatticeOpKind {
39    fn invert(self) -> Self {
40        match self {
41            LatticeOpKind::Glb => LatticeOpKind::Lub,
42            LatticeOpKind::Lub => LatticeOpKind::Glb,
43        }
44    }
45}
46
47/// A greatest lower bound" (common subtype) or least upper bound (common supertype).
48pub(crate) struct LatticeOp<'infcx, 'tcx> {
49    infcx: &'infcx InferCtxt<'tcx>,
50    // Immutable fields
51    trace: TypeTrace<'tcx>,
52    param_env: ty::ParamEnv<'tcx>,
53    // Mutable fields
54    kind: LatticeOpKind,
55    obligations: PredicateObligations<'tcx>,
56}
57
58impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> {
59    pub(crate) fn new(
60        infcx: &'infcx InferCtxt<'tcx>,
61        trace: TypeTrace<'tcx>,
62        param_env: ty::ParamEnv<'tcx>,
63        kind: LatticeOpKind,
64    ) -> LatticeOp<'infcx, 'tcx> {
65        LatticeOp { infcx, trace, param_env, kind, obligations: PredicateObligations::new() }
66    }
67
68    pub(crate) fn into_obligations(self) -> PredicateObligations<'tcx> {
69        self.obligations
70    }
71}
72
73impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
74    fn cx(&self) -> TyCtxt<'tcx> {
75        self.infcx.tcx
76    }
77
78    fn relate_ty_args(
79        &mut self,
80        a_ty: Ty<'tcx>,
81        b_ty: Ty<'tcx>,
82        def_id: DefId,
83        a_args: ty::GenericArgsRef<'tcx>,
84        b_args: ty::GenericArgsRef<'tcx>,
85        mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
86    ) -> RelateResult<'tcx, Ty<'tcx>> {
87        let variances = self.cx().variances_of(def_id);
88        combine_ty_args(self.infcx, self, a_ty, b_ty, variances, a_args, b_args, |args| mk(args))
89    }
90
91    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
92        &mut self,
93        variance: ty::Variance,
94        _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
95        a: T,
96        b: T,
97    ) -> RelateResult<'tcx, T> {
98        match variance {
99            ty::Invariant => {
100                self.obligations.extend(
101                    self.infcx
102                        .at(&self.trace.cause, self.param_env)
103                        .eq_trace(DefineOpaqueTypes::Yes, self.trace.clone(), a, b)?
104                        .into_obligations(),
105                );
106                Ok(a)
107            }
108            ty::Covariant => self.relate(a, b),
109            // FIXME(#41044) -- not correct, need test
110            ty::Bivariant => Ok(a),
111            ty::Contravariant => {
112                self.kind = self.kind.invert();
113                let res = self.relate(a, b);
114                self.kind = self.kind.invert();
115                res
116            }
117        }
118    }
119
120    /// Relates two types using a given lattice.
121    #[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_infer::infer::relate::lattice",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/lattice.rs"),
                                    ::tracing_core::__macro_support::Option::Some(121u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::lattice"),
                                    ::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<'tcx, Ty<'tcx>> =
                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);
            match (a.kind(), b.kind()) {
                (&ty::Infer(TyVar(..)), _) => {
                    let v = infcx.next_ty_var(self.trace.cause.span);
                    self.relate_bound(v, b, a)?;
                    Ok(v)
                }
                (_, &ty::Infer(TyVar(..))) => {
                    let v = infcx.next_ty_var(self.trace.cause.span);
                    self.relate_bound(v, a, b)?;
                    Ok(v)
                }
                (&ty::Alias(_, ty::AliasTy {
                    kind: ty::Opaque { def_id: a_def_id }, .. }),
                    &ty::Alias(_, ty::AliasTy {
                    kind: ty::Opaque { def_id: b_def_id }, .. })) if
                    a_def_id == b_def_id =>
                    super_combine_tys(infcx, self, a, b),
                (&ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, ..
                    }), _) |
                    (_,
                    &ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, ..
                    })) if def_id.is_local() && !infcx.next_trait_solver() => {
                    self.register_goals(infcx.handle_opaque_type(a, b,
                                self.span(), self.param_env())?);
                    Ok(a)
                }
                _ => super_combine_tys(infcx, self, a, b),
            }
        }
    }
}#[instrument(skip(self), level = "trace")]
122    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
123        if a == b {
124            return Ok(a);
125        }
126
127        let infcx = self.infcx;
128
129        let a = infcx.shallow_resolve(a);
130        let b = infcx.shallow_resolve(b);
131
132        match (a.kind(), b.kind()) {
133            // If one side is known to be a variable and one is not,
134            // create a variable (`v`) to represent the LUB. Make sure to
135            // relate `v` to the non-type-variable first (by passing it
136            // first to `relate_bound`). Otherwise, we would produce a
137            // subtype obligation that must then be processed.
138            //
139            // Example: if the LHS is a type variable, and RHS is
140            // `Box<i32>`, then we current compare `v` to the RHS first,
141            // which will instantiate `v` with `Box<i32>`. Then when `v`
142            // is compared to the LHS, we instantiate LHS with `Box<i32>`.
143            // But if we did in reverse order, we would create a `v <:
144            // LHS` (or vice versa) constraint and then instantiate
145            // `v`. This would require further processing to achieve same
146            // end-result; in particular, this screws up some of the logic
147            // in coercion, which expects LUB to figure out that the LHS
148            // is (e.g.) `Box<i32>`. A more obvious solution might be to
149            // iterate on the subtype obligations that are returned, but I
150            // think this suffices. -nmatsakis
151            (&ty::Infer(TyVar(..)), _) => {
152                let v = infcx.next_ty_var(self.trace.cause.span);
153                self.relate_bound(v, b, a)?;
154                Ok(v)
155            }
156            (_, &ty::Infer(TyVar(..))) => {
157                let v = infcx.next_ty_var(self.trace.cause.span);
158                self.relate_bound(v, a, b)?;
159                Ok(v)
160            }
161
162            (
163                &ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id: a_def_id }, .. }),
164                &ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id: b_def_id }, .. }),
165            ) if a_def_id == b_def_id => super_combine_tys(infcx, self, a, b),
166
167            (&ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, .. }), _)
168            | (_, &ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, .. }))
169                if def_id.is_local() && !infcx.next_trait_solver() =>
170            {
171                self.register_goals(infcx.handle_opaque_type(
172                    a,
173                    b,
174                    self.span(),
175                    self.param_env(),
176                )?);
177                Ok(a)
178            }
179
180            _ => super_combine_tys(infcx, self, a, b),
181        }
182    }
183
184    #[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_infer::infer::relate::lattice",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/lattice.rs"),
                                    ::tracing_core::__macro_support::Option::Some(184u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::lattice"),
                                    ::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<'tcx, ty::Region<'tcx>> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let origin =
                SubregionOrigin::Subtype(Box::new(self.trace.clone()));
            let mut inner = self.infcx.inner.borrow_mut();
            let mut constraints = inner.unwrap_region_constraints();
            Ok(match self.kind {
                    LatticeOpKind::Glb =>
                        constraints.lub_regions(self.cx(), origin, a, b),
                    LatticeOpKind::Lub =>
                        constraints.glb_regions(self.cx(), origin, a, b),
                })
        }
    }
}#[instrument(skip(self), level = "trace")]
185    fn regions(
186        &mut self,
187        a: ty::Region<'tcx>,
188        b: ty::Region<'tcx>,
189    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
190        let origin = SubregionOrigin::Subtype(Box::new(self.trace.clone()));
191        let mut inner = self.infcx.inner.borrow_mut();
192        let mut constraints = inner.unwrap_region_constraints();
193        Ok(match self.kind {
194            // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
195            LatticeOpKind::Glb => constraints.lub_regions(self.cx(), origin, a, b),
196
197            // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
198            LatticeOpKind::Lub => constraints.glb_regions(self.cx(), origin, a, b),
199        })
200    }
201
202    #[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_infer::infer::relate::lattice",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/lattice.rs"),
                                    ::tracing_core::__macro_support::Option::Some(202u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::lattice"),
                                    ::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<'tcx, ty::Const<'tcx>> = loop {};
            return __tracing_attr_fake_return;
        }
        { super_combine_consts(self.infcx, self, a, b) }
    }
}#[instrument(skip(self), level = "trace")]
203    fn consts(
204        &mut self,
205        a: ty::Const<'tcx>,
206        b: ty::Const<'tcx>,
207    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
208        super_combine_consts(self.infcx, self, a, b)
209    }
210
211    fn binders<T>(
212        &mut self,
213        a: ty::Binder<'tcx, T>,
214        b: ty::Binder<'tcx, T>,
215    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
216    where
217        T: Relate<TyCtxt<'tcx>>,
218    {
219        // GLB/LUB of a binder and itself is just itself
220        if a == b {
221            return Ok(a);
222        }
223
224        {
    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/lattice.rs:224",
                        "rustc_infer::infer::relate::lattice",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/lattice.rs"),
                        ::tracing_core::__macro_support::Option::Some(224u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::lattice"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("binders(a={0:?}, b={1:?})",
                                                    a, b) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("binders(a={:?}, b={:?})", a, b);
225        if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
226            // When higher-ranked types are involved, computing the GLB/LUB is
227            // very challenging, switch to invariance. This is obviously
228            // overly conservative but works ok in practice.
229            self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
230            Ok(a)
231        } else {
232            Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
233        }
234    }
235}
236
237impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> {
238    // Relates the type `v` to `a` and `b` such that `v` represents
239    // the LUB/GLB of `a` and `b` as appropriate.
240    //
241    // Subtle hack: ordering *may* be significant here. This method
242    // relates `v` to `a` first, which may help us to avoid unnecessary
243    // type variable obligations. See caller for details.
244    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
245        let at = self.infcx.at(&self.trace.cause, self.param_env);
246        match self.kind {
247            LatticeOpKind::Glb => {
248                self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, a)?.into_obligations());
249                self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, b)?.into_obligations());
250            }
251            LatticeOpKind::Lub => {
252                self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, a, v)?.into_obligations());
253                self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, b, v)?.into_obligations());
254            }
255        }
256        Ok(())
257    }
258}
259
260impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
261    fn span(&self) -> Span {
262        self.trace.span()
263    }
264
265    fn param_env(&self) -> ty::ParamEnv<'tcx> {
266        self.param_env
267    }
268
269    fn register_predicates(
270        &mut self,
271        preds: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
272    ) {
273        self.obligations.extend(preds.into_iter().map(|pred| {
274            Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, pred)
275        }))
276    }
277
278    fn register_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) {
279        self.obligations.extend(goals.into_iter().map(|goal| {
280            Obligation::new(
281                self.infcx.tcx,
282                self.trace.cause.clone(),
283                goal.param_env,
284                goal.predicate,
285            )
286        }))
287    }
288
289    fn ambient_variance(&self) -> ty::Variance {
290        // FIXME(deferred_projection_equality): This isn't right, I think?
291        ty::Variance::Invariant
292    }
293}