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