rustc_type_ir/
relate.rs

1use std::iter;
2
3use derive_where::derive_where;
4use rustc_ast_ir::Mutability;
5use tracing::{instrument, trace};
6
7use crate::error::{ExpectedFound, TypeError};
8use crate::fold::TypeFoldable;
9use crate::inherent::*;
10use crate::{self as ty, Interner};
11
12pub mod combine;
13pub mod solver_relating;
14
15pub type RelateResult<I, T> = Result<T, TypeError<I>>;
16
17/// Whether aliases should be related structurally or not. Used
18/// to adjust the behavior of generalization and combine.
19///
20/// This should always be `No` unless in a few special-cases when
21/// instantiating canonical responses and in the new solver. Each
22/// such case should have a comment explaining why it is used.
23#[derive(Debug, Copy, Clone)]
24pub enum StructurallyRelateAliases {
25    Yes,
26    No,
27}
28
29/// Extra information about why we ended up with a particular variance.
30/// This is only used to add more information to error messages, and
31/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
32/// may lead to confusing notes in error messages, it will never cause
33/// a miscompilation or unsoundness.
34///
35/// When in doubt, use `VarianceDiagInfo::default()`
36#[derive_where(Clone, Copy, PartialEq, Debug, Default; I: Interner)]
37pub enum VarianceDiagInfo<I: Interner> {
38    /// No additional information - this is the default.
39    /// We will not add any additional information to error messages.
40    #[derive_where(default)]
41    None,
42    /// We switched our variance because a generic argument occurs inside
43    /// the invariant generic argument of another type.
44    Invariant {
45        /// The generic type containing the generic parameter
46        /// that changes the variance (e.g. `*mut T`, `MyStruct<T>`)
47        ty: I::Ty,
48        /// The index of the generic parameter being used
49        /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`)
50        param_index: u32,
51    },
52}
53
54impl<I: Interner> Eq for VarianceDiagInfo<I> {}
55
56impl<I: Interner> VarianceDiagInfo<I> {
57    /// Mirrors `Variance::xform` - used to 'combine' the existing
58    /// and new `VarianceDiagInfo`s when our variance changes.
59    pub fn xform(self, other: VarianceDiagInfo<I>) -> VarianceDiagInfo<I> {
60        // For now, just use the first `VarianceDiagInfo::Invariant` that we see
61        match self {
62            VarianceDiagInfo::None => other,
63            VarianceDiagInfo::Invariant { .. } => self,
64        }
65    }
66}
67
68pub trait TypeRelation<I: Interner>: Sized {
69    fn cx(&self) -> I;
70
71    /// Generic relation routine suitable for most anything.
72    fn relate<T: Relate<I>>(&mut self, a: T, b: T) -> RelateResult<I, T> {
73        Relate::relate(self, a, b)
74    }
75
76    /// Relate the two args for the given item. The default
77    /// is to look up the variance for the item and proceed
78    /// accordingly.
79    #[instrument(skip(self), level = "trace")]
80    fn relate_item_args(
81        &mut self,
82        item_def_id: I::DefId,
83        a_arg: I::GenericArgs,
84        b_arg: I::GenericArgs,
85    ) -> RelateResult<I, I::GenericArgs> {
86        let cx = self.cx();
87        let opt_variances = cx.variances_of(item_def_id);
88        relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, true)
89    }
90
91    /// Switch variance for the purpose of relating `a` and `b`.
92    fn relate_with_variance<T: Relate<I>>(
93        &mut self,
94        variance: ty::Variance,
95        info: VarianceDiagInfo<I>,
96        a: T,
97        b: T,
98    ) -> RelateResult<I, T>;
99
100    // Overridable relations. You shouldn't typically call these
101    // directly, instead call `relate()`, which in turn calls
102    // these. This is both more uniform but also allows us to add
103    // additional hooks for other types in the future if needed
104    // without making older code, which called `relate`, obsolete.
105
106    fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty>;
107
108    fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region>;
109
110    fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const>;
111
112    fn binders<T>(
113        &mut self,
114        a: ty::Binder<I, T>,
115        b: ty::Binder<I, T>,
116    ) -> RelateResult<I, ty::Binder<I, T>>
117    where
118        T: Relate<I>;
119}
120
121pub trait Relate<I: Interner>: TypeFoldable<I> + PartialEq + Copy {
122    fn relate<R: TypeRelation<I>>(relation: &mut R, a: Self, b: Self) -> RelateResult<I, Self>;
123}
124
125///////////////////////////////////////////////////////////////////////////
126// Relate impls
127
128#[inline]
129pub fn relate_args_invariantly<I: Interner, R: TypeRelation<I>>(
130    relation: &mut R,
131    a_arg: I::GenericArgs,
132    b_arg: I::GenericArgs,
133) -> RelateResult<I, I::GenericArgs> {
134    relation.cx().mk_args_from_iter(iter::zip(a_arg.iter(), b_arg.iter()).map(|(a, b)| {
135        relation.relate_with_variance(ty::Invariant, VarianceDiagInfo::default(), a, b)
136    }))
137}
138
139pub fn relate_args_with_variances<I: Interner, R: TypeRelation<I>>(
140    relation: &mut R,
141    ty_def_id: I::DefId,
142    variances: I::VariancesOf,
143    a_arg: I::GenericArgs,
144    b_arg: I::GenericArgs,
145    fetch_ty_for_diag: bool,
146) -> RelateResult<I, I::GenericArgs> {
147    let cx = relation.cx();
148
149    let mut cached_ty = None;
150    let params = iter::zip(a_arg.iter(), b_arg.iter()).enumerate().map(|(i, (a, b))| {
151        let variance = variances.get(i).unwrap();
152        let variance_info = if variance == ty::Invariant && fetch_ty_for_diag {
153            let ty = *cached_ty.get_or_insert_with(|| cx.type_of(ty_def_id).instantiate(cx, a_arg));
154            VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
155        } else {
156            VarianceDiagInfo::default()
157        };
158        relation.relate_with_variance(variance, variance_info, a, b)
159    });
160
161    cx.mk_args_from_iter(params)
162}
163
164impl<I: Interner> Relate<I> for ty::FnSig<I> {
165    fn relate<R: TypeRelation<I>>(
166        relation: &mut R,
167        a: ty::FnSig<I>,
168        b: ty::FnSig<I>,
169    ) -> RelateResult<I, ty::FnSig<I>> {
170        let cx = relation.cx();
171
172        if a.c_variadic != b.c_variadic {
173            return Err(TypeError::VariadicMismatch({
174                let a = a.c_variadic;
175                let b = b.c_variadic;
176                ExpectedFound::new(a, b)
177            }));
178        }
179
180        if a.safety != b.safety {
181            return Err(TypeError::SafetyMismatch(ExpectedFound::new(a.safety, b.safety)));
182        }
183
184        if a.abi != b.abi {
185            return Err(TypeError::AbiMismatch(ExpectedFound::new(a.abi, b.abi)));
186        };
187
188        let a_inputs = a.inputs();
189        let b_inputs = b.inputs();
190        if a_inputs.len() != b_inputs.len() {
191            return Err(TypeError::ArgCount);
192        }
193
194        let inputs_and_output = iter::zip(a_inputs.iter(), b_inputs.iter())
195            .map(|(a, b)| ((a, b), false))
196            .chain(iter::once(((a.output(), b.output()), true)))
197            .map(|((a, b), is_output)| {
198                if is_output {
199                    relation.relate(a, b)
200                } else {
201                    relation.relate_with_variance(
202                        ty::Contravariant,
203                        VarianceDiagInfo::default(),
204                        a,
205                        b,
206                    )
207                }
208            })
209            .enumerate()
210            .map(|(i, r)| match r {
211                Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => {
212                    Err(TypeError::ArgumentSorts(exp_found, i))
213                }
214                Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => {
215                    Err(TypeError::ArgumentMutability(i))
216                }
217                r => r,
218            });
219        Ok(ty::FnSig {
220            inputs_and_output: cx.mk_type_list_from_iter(inputs_and_output)?,
221            c_variadic: a.c_variadic,
222            safety: a.safety,
223            abi: a.abi,
224        })
225    }
226}
227
228impl<I: Interner> Relate<I> for ty::AliasTy<I> {
229    fn relate<R: TypeRelation<I>>(
230        relation: &mut R,
231        a: ty::AliasTy<I>,
232        b: ty::AliasTy<I>,
233    ) -> RelateResult<I, ty::AliasTy<I>> {
234        if a.def_id != b.def_id {
235            Err(TypeError::ProjectionMismatched({
236                let a = a.def_id;
237                let b = b.def_id;
238                ExpectedFound::new(a, b)
239            }))
240        } else {
241            let cx = relation.cx();
242            let args = if let Some(variances) = cx.opt_alias_variances(a.kind(cx), a.def_id) {
243                relate_args_with_variances(
244                    relation, a.def_id, variances, a.args, b.args,
245                    false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
246                )?
247            } else {
248                relate_args_invariantly(relation, a.args, b.args)?
249            };
250            Ok(ty::AliasTy::new_from_args(relation.cx(), a.def_id, args))
251        }
252    }
253}
254
255impl<I: Interner> Relate<I> for ty::AliasTerm<I> {
256    fn relate<R: TypeRelation<I>>(
257        relation: &mut R,
258        a: ty::AliasTerm<I>,
259        b: ty::AliasTerm<I>,
260    ) -> RelateResult<I, ty::AliasTerm<I>> {
261        if a.def_id != b.def_id {
262            Err(TypeError::ProjectionMismatched({
263                let a = a.def_id;
264                let b = b.def_id;
265                ExpectedFound::new(a, b)
266            }))
267        } else {
268            let args = match a.kind(relation.cx()) {
269                ty::AliasTermKind::OpaqueTy => relate_args_with_variances(
270                    relation,
271                    a.def_id,
272                    relation.cx().variances_of(a.def_id),
273                    a.args,
274                    b.args,
275                    false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
276                )?,
277                ty::AliasTermKind::ProjectionTy
278                | ty::AliasTermKind::FreeConst
279                | ty::AliasTermKind::FreeTy
280                | ty::AliasTermKind::InherentTy
281                | ty::AliasTermKind::InherentConst
282                | ty::AliasTermKind::UnevaluatedConst
283                | ty::AliasTermKind::ProjectionConst => {
284                    relate_args_invariantly(relation, a.args, b.args)?
285                }
286            };
287            Ok(ty::AliasTerm::new_from_args(relation.cx(), a.def_id, args))
288        }
289    }
290}
291
292impl<I: Interner> Relate<I> for ty::ExistentialProjection<I> {
293    fn relate<R: TypeRelation<I>>(
294        relation: &mut R,
295        a: ty::ExistentialProjection<I>,
296        b: ty::ExistentialProjection<I>,
297    ) -> RelateResult<I, ty::ExistentialProjection<I>> {
298        if a.def_id != b.def_id {
299            Err(TypeError::ProjectionMismatched({
300                let a = a.def_id;
301                let b = b.def_id;
302                ExpectedFound::new(a, b)
303            }))
304        } else {
305            let term = relation.relate_with_variance(
306                ty::Invariant,
307                VarianceDiagInfo::default(),
308                a.term,
309                b.term,
310            )?;
311            let args = relation.relate_with_variance(
312                ty::Invariant,
313                VarianceDiagInfo::default(),
314                a.args,
315                b.args,
316            )?;
317            Ok(ty::ExistentialProjection::new_from_args(relation.cx(), a.def_id, args, term))
318        }
319    }
320}
321
322impl<I: Interner> Relate<I> for ty::TraitRef<I> {
323    fn relate<R: TypeRelation<I>>(
324        relation: &mut R,
325        a: ty::TraitRef<I>,
326        b: ty::TraitRef<I>,
327    ) -> RelateResult<I, ty::TraitRef<I>> {
328        // Different traits cannot be related.
329        if a.def_id != b.def_id {
330            Err(TypeError::Traits({
331                let a = a.def_id;
332                let b = b.def_id;
333                ExpectedFound::new(a, b)
334            }))
335        } else {
336            let args = relate_args_invariantly(relation, a.args, b.args)?;
337            Ok(ty::TraitRef::new_from_args(relation.cx(), a.def_id, args))
338        }
339    }
340}
341
342impl<I: Interner> Relate<I> for ty::ExistentialTraitRef<I> {
343    fn relate<R: TypeRelation<I>>(
344        relation: &mut R,
345        a: ty::ExistentialTraitRef<I>,
346        b: ty::ExistentialTraitRef<I>,
347    ) -> RelateResult<I, ty::ExistentialTraitRef<I>> {
348        // Different traits cannot be related.
349        if a.def_id != b.def_id {
350            Err(TypeError::Traits({
351                let a = a.def_id;
352                let b = b.def_id;
353                ExpectedFound::new(a, b)
354            }))
355        } else {
356            let args = relate_args_invariantly(relation, a.args, b.args)?;
357            Ok(ty::ExistentialTraitRef::new_from_args(relation.cx(), a.def_id, args))
358        }
359    }
360}
361
362/// Relates `a` and `b` structurally, calling the relation for all nested values.
363/// Any semantic equality, e.g. of projections, and inference variables have to be
364/// handled by the caller.
365#[instrument(level = "trace", skip(relation), ret)]
366pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
367    relation: &mut R,
368    a: I::Ty,
369    b: I::Ty,
370) -> RelateResult<I, I::Ty> {
371    let cx = relation.cx();
372    match (a.kind(), b.kind()) {
373        (ty::Infer(_), _) | (_, ty::Infer(_)) => {
374            // The caller should handle these cases!
375            panic!("var types encountered in structurally_relate_tys")
376        }
377
378        (ty::Bound(..), _) | (_, ty::Bound(..)) => {
379            panic!("bound types encountered in structurally_relate_tys")
380        }
381
382        (ty::Error(guar), _) | (_, ty::Error(guar)) => Ok(Ty::new_error(cx, guar)),
383
384        (ty::Never, _)
385        | (ty::Char, _)
386        | (ty::Bool, _)
387        | (ty::Int(_), _)
388        | (ty::Uint(_), _)
389        | (ty::Float(_), _)
390        | (ty::Str, _)
391            if a == b =>
392        {
393            Ok(a)
394        }
395
396        (ty::Param(a_p), ty::Param(b_p)) if a_p.index() == b_p.index() => {
397            // FIXME: Put this back
398            //debug_assert_eq!(a_p.name(), b_p.name(), "param types with same index differ in name");
399            Ok(a)
400        }
401
402        (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a),
403
404        (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => {
405            Ok(if a_args.is_empty() {
406                a
407            } else {
408                let args = relation.relate_item_args(a_def.def_id().into(), a_args, b_args)?;
409                if args == a_args { a } else { Ty::new_adt(cx, a_def, args) }
410            })
411        }
412
413        (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(cx, a_id)),
414
415        (ty::Dynamic(a_obj, a_region, a_repr), ty::Dynamic(b_obj, b_region, b_repr))
416            if a_repr == b_repr =>
417        {
418            Ok(Ty::new_dynamic(
419                cx,
420                relation.relate(a_obj, b_obj)?,
421                relation.relate(a_region, b_region)?,
422                a_repr,
423            ))
424        }
425
426        (ty::Coroutine(a_id, a_args), ty::Coroutine(b_id, b_args)) if a_id == b_id => {
427            // All Coroutine types with the same id represent
428            // the (anonymous) type of the same coroutine expression. So
429            // all of their regions should be equated.
430            let args = relate_args_invariantly(relation, a_args, b_args)?;
431            Ok(Ty::new_coroutine(cx, a_id, args))
432        }
433
434        (ty::CoroutineWitness(a_id, a_args), ty::CoroutineWitness(b_id, b_args))
435            if a_id == b_id =>
436        {
437            // All CoroutineWitness types with the same id represent
438            // the (anonymous) type of the same coroutine expression. So
439            // all of their regions should be equated.
440            let args = relate_args_invariantly(relation, a_args, b_args)?;
441            Ok(Ty::new_coroutine_witness(cx, a_id, args))
442        }
443
444        (ty::Closure(a_id, a_args), ty::Closure(b_id, b_args)) if a_id == b_id => {
445            // All Closure types with the same id represent
446            // the (anonymous) type of the same closure expression. So
447            // all of their regions should be equated.
448            let args = relate_args_invariantly(relation, a_args, b_args)?;
449            Ok(Ty::new_closure(cx, a_id, args))
450        }
451
452        (ty::CoroutineClosure(a_id, a_args), ty::CoroutineClosure(b_id, b_args))
453            if a_id == b_id =>
454        {
455            let args = relate_args_invariantly(relation, a_args, b_args)?;
456            Ok(Ty::new_coroutine_closure(cx, a_id, args))
457        }
458
459        (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => {
460            if a_mutbl != b_mutbl {
461                return Err(TypeError::Mutability);
462            }
463
464            let (variance, info) = match a_mutbl {
465                Mutability::Not => (ty::Covariant, VarianceDiagInfo::None),
466                Mutability::Mut => {
467                    (ty::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
468                }
469            };
470
471            let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
472
473            Ok(Ty::new_ptr(cx, ty, a_mutbl))
474        }
475
476        (ty::Ref(a_r, a_ty, a_mutbl), ty::Ref(b_r, b_ty, b_mutbl)) => {
477            if a_mutbl != b_mutbl {
478                return Err(TypeError::Mutability);
479            }
480
481            let (variance, info) = match a_mutbl {
482                Mutability::Not => (ty::Covariant, VarianceDiagInfo::None),
483                Mutability::Mut => {
484                    (ty::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
485                }
486            };
487
488            let r = relation.relate(a_r, b_r)?;
489            let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
490
491            Ok(Ty::new_ref(cx, r, ty, a_mutbl))
492        }
493
494        (ty::Array(a_t, sz_a), ty::Array(b_t, sz_b)) => {
495            let t = relation.relate(a_t, b_t)?;
496            match relation.relate(sz_a, sz_b) {
497                Ok(sz) => Ok(Ty::new_array_with_const_len(cx, t, sz)),
498                Err(TypeError::ConstMismatch(_)) => {
499                    Err(TypeError::ArraySize(ExpectedFound::new(sz_a, sz_b)))
500                }
501                Err(e) => Err(e),
502            }
503        }
504
505        (ty::Slice(a_t), ty::Slice(b_t)) => {
506            let t = relation.relate(a_t, b_t)?;
507            Ok(Ty::new_slice(cx, t))
508        }
509
510        (ty::Tuple(as_), ty::Tuple(bs)) => {
511            if as_.len() == bs.len() {
512                Ok(Ty::new_tup_from_iter(
513                    cx,
514                    iter::zip(as_.iter(), bs.iter()).map(|(a, b)| relation.relate(a, b)),
515                )?)
516            } else if !(as_.is_empty() || bs.is_empty()) {
517                Err(TypeError::TupleSize(ExpectedFound::new(as_.len(), bs.len())))
518            } else {
519                Err(TypeError::Sorts(ExpectedFound::new(a, b)))
520            }
521        }
522
523        (ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => {
524            Ok(if a_args.is_empty() {
525                a
526            } else {
527                let args = relation.relate_item_args(a_def_id.into(), a_args, b_args)?;
528                if args == a_args { a } else { Ty::new_fn_def(cx, a_def_id, args) }
529            })
530        }
531
532        (ty::FnPtr(a_sig_tys, a_hdr), ty::FnPtr(b_sig_tys, b_hdr)) => {
533            let fty = relation.relate(a_sig_tys.with(a_hdr), b_sig_tys.with(b_hdr))?;
534            Ok(Ty::new_fn_ptr(cx, fty))
535        }
536
537        // Alias tend to mostly already be handled downstream due to normalization.
538        (ty::Alias(a_kind, a_data), ty::Alias(b_kind, b_data)) => {
539            let alias_ty = relation.relate(a_data, b_data)?;
540            assert_eq!(a_kind, b_kind);
541            Ok(Ty::new_alias(cx, a_kind, alias_ty))
542        }
543
544        (ty::Pat(a_ty, a_pat), ty::Pat(b_ty, b_pat)) => {
545            let ty = relation.relate(a_ty, b_ty)?;
546            let pat = relation.relate(a_pat, b_pat)?;
547            Ok(Ty::new_pat(cx, ty, pat))
548        }
549
550        (ty::UnsafeBinder(a_binder), ty::UnsafeBinder(b_binder)) => {
551            Ok(Ty::new_unsafe_binder(cx, relation.binders(*a_binder, *b_binder)?))
552        }
553
554        _ => Err(TypeError::Sorts(ExpectedFound::new(a, b))),
555    }
556}
557
558/// Relates `a` and `b` structurally, calling the relation for all nested values.
559/// Any semantic equality, e.g. of unevaluated consts, and inference variables have
560/// to be handled by the caller.
561///
562/// FIXME: This is not totally structural, which probably should be fixed.
563/// See the HACKs below.
564pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>(
565    relation: &mut R,
566    mut a: I::Const,
567    mut b: I::Const,
568) -> RelateResult<I, I::Const> {
569    trace!(
570        "structurally_relate_consts::<{}>(a = {:?}, b = {:?})",
571        std::any::type_name::<R>(),
572        a,
573        b
574    );
575    let cx = relation.cx();
576
577    if cx.features().generic_const_exprs() {
578        a = cx.expand_abstract_consts(a);
579        b = cx.expand_abstract_consts(b);
580    }
581
582    trace!(
583        "structurally_relate_consts::<{}>(normed_a = {:?}, normed_b = {:?})",
584        std::any::type_name::<R>(),
585        a,
586        b
587    );
588
589    // Currently, the values that can be unified are primitive types,
590    // and those that derive both `PartialEq` and `Eq`, corresponding
591    // to structural-match types.
592    let is_match = match (a.kind(), b.kind()) {
593        (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
594            // The caller should handle these cases!
595            panic!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b)
596        }
597
598        (ty::ConstKind::Error(_), _) => return Ok(a),
599        (_, ty::ConstKind::Error(_)) => return Ok(b),
600
601        (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index() == b_p.index() => {
602            // FIXME: Put this back
603            // debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name");
604            true
605        }
606        (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
607        (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
608            a_val.valtree() == b_val.valtree()
609        }
610
611        // While this is slightly incorrect, it shouldn't matter for `min_const_generics`
612        // and is the better alternative to waiting until `generic_const_exprs` can
613        // be stabilized.
614        (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => {
615            if cfg!(debug_assertions) {
616                let a_ty = cx.type_of(au.def).instantiate(cx, au.args);
617                let b_ty = cx.type_of(bu.def).instantiate(cx, bu.args);
618                assert_eq!(a_ty, b_ty);
619            }
620
621            let args = relation.relate_with_variance(
622                ty::Invariant,
623                VarianceDiagInfo::default(),
624                au.args,
625                bu.args,
626            )?;
627            return Ok(Const::new_unevaluated(cx, ty::UnevaluatedConst { def: au.def, args }));
628        }
629        (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => {
630            let expr = relation.relate(ae, be)?;
631            return Ok(Const::new_expr(cx, expr));
632        }
633        _ => false,
634    };
635    if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(ExpectedFound::new(a, b))) }
636}
637
638impl<I: Interner, T: Relate<I>> Relate<I> for ty::Binder<I, T> {
639    fn relate<R: TypeRelation<I>>(
640        relation: &mut R,
641        a: ty::Binder<I, T>,
642        b: ty::Binder<I, T>,
643    ) -> RelateResult<I, ty::Binder<I, T>> {
644        relation.binders(a, b)
645    }
646}
647
648impl<I: Interner> Relate<I> for ty::TraitPredicate<I> {
649    fn relate<R: TypeRelation<I>>(
650        relation: &mut R,
651        a: ty::TraitPredicate<I>,
652        b: ty::TraitPredicate<I>,
653    ) -> RelateResult<I, ty::TraitPredicate<I>> {
654        let trait_ref = relation.relate(a.trait_ref, b.trait_ref)?;
655        if a.polarity != b.polarity {
656            return Err(TypeError::PolarityMismatch(ExpectedFound::new(a.polarity, b.polarity)));
657        }
658        Ok(ty::TraitPredicate { trait_ref, polarity: a.polarity })
659    }
660}