Skip to main content

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