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, Region};
11
12pub mod combine;
13pub mod solver_relating;
14
15pub type RelateResult<I, T> = Result<T, TypeError<I>>;
16
17/// Extra information about why we ended up with a particular variance.
18/// This is only used to add more information to error messages, and
19/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
20/// may lead to confusing notes in error messages, it will never cause
21/// a miscompilation or unsoundness.
22///
23/// When in doubt, use `VarianceDiagInfo::default()`
24#[automatically_derived]
impl<I: Interner> ::core::clone::Clone for VarianceDiagInfo<I> where
    I: Interner {
    #[inline]
    fn clone(&self) -> Self { *self }
}
#[automatically_derived]
impl<I: Interner> ::core::marker::Copy for VarianceDiagInfo<I> where
    I: Interner {
}
#[automatically_derived]
impl<I: Interner> ::core::cmp::PartialEq for VarianceDiagInfo<I> where
    I: Interner {
    #[inline]
    fn eq(&self, __other: &Self) -> ::core::primitive::bool {
        if ::core::mem::discriminant(self) ==
                ::core::mem::discriminant(__other) {
            match (self, __other) {
                (VarianceDiagInfo::Invariant {
                    ty: ref __field_ty, param_index: ref __field_param_index },
                    VarianceDiagInfo::Invariant {
                    ty: ref __other_field_ty,
                    param_index: ref __other_field_param_index }) =>
                    true &&
                            ::core::cmp::PartialEq::eq(__field_ty, __other_field_ty) &&
                        ::core::cmp::PartialEq::eq(__field_param_index,
                            __other_field_param_index),
                _ => true,
            }
        } else { false }
    }
}
#[automatically_derived]
impl<I: Interner> ::core::fmt::Debug for VarianceDiagInfo<I> where I: Interner
    {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            VarianceDiagInfo::None =>
                ::core::fmt::Formatter::write_str(__f, "None"),
            VarianceDiagInfo::Invariant {
                ty: ref __field_ty, param_index: ref __field_param_index } =>
                {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f, "Invariant");
                ::core::fmt::DebugStruct::field(&mut __builder, "ty",
                    __field_ty);
                ::core::fmt::DebugStruct::field(&mut __builder, "param_index",
                    __field_param_index);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
        }
    }
}
#[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)]
25pub enum VarianceDiagInfo<I: Interner> {
26    /// No additional information - this is the default.
27    /// We will not add any additional information to error messages.
28    #[derive_where(default)]
29    None,
30    /// We switched our variance because a generic argument occurs inside
31    /// the invariant generic argument of another type.
32    Invariant {
33        /// The generic type containing the generic parameter
34        /// that changes the variance (e.g. `*mut T`, `MyStruct<T>`)
35        ty: I::Ty,
36        /// The index of the generic parameter being used
37        /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`)
38        param_index: u32,
39    },
40}
41
42impl<I: Interner> Eq for VarianceDiagInfo<I> {}
43
44impl<I: Interner> VarianceDiagInfo<I> {
45    /// Mirrors `Variance::xform` - used to 'combine' the existing
46    /// and new `VarianceDiagInfo`s when our variance changes.
47    pub fn xform(self, other: VarianceDiagInfo<I>) -> VarianceDiagInfo<I> {
48        // For now, just use the first `VarianceDiagInfo::Invariant` that we see
49        match self {
50            VarianceDiagInfo::None => other,
51            VarianceDiagInfo::Invariant { .. } => self,
52        }
53    }
54}
55
56pub trait TypeRelation<I: Interner>: Sized {
57    fn cx(&self) -> I;
58
59    /// Generic relation routine suitable for most anything.
60    fn relate<T: Relate<I>>(&mut self, a: T, b: T) -> RelateResult<I, T> {
61        Relate::relate(self, a, b)
62    }
63
64    fn relate_ty_args(
65        &mut self,
66        a_ty: I::Ty,
67        b_ty: I::Ty,
68        ty_def_id: I::DefId,
69        a_args: I::GenericArgs,
70        b_args: I::GenericArgs,
71        mk: impl FnOnce(I::GenericArgs) -> I::Ty,
72    ) -> RelateResult<I, I::Ty>;
73
74    /// Switch variance for the purpose of relating `a` and `b`.
75    fn relate_with_variance<T: Relate<I>>(
76        &mut self,
77        variance: ty::Variance,
78        info: VarianceDiagInfo<I>,
79        a: T,
80        b: T,
81    ) -> RelateResult<I, T>;
82
83    // Overridable relations. You shouldn't typically call these
84    // directly, instead call `relate()`, which in turn calls
85    // these. This is both more uniform but also allows us to add
86    // additional hooks for other types in the future if needed
87    // without making older code, which called `relate`, obsolete.
88
89    fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty>;
90
91    fn regions(&mut self, a: Region<I>, b: Region<I>) -> RelateResult<I, Region<I>>;
92
93    fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const>;
94
95    fn binders<T>(
96        &mut self,
97        a: ty::Binder<I, T>,
98        b: ty::Binder<I, T>,
99    ) -> RelateResult<I, ty::Binder<I, T>>
100    where
101        T: Relate<I>;
102}
103
104pub trait Relate<I: Interner>: TypeFoldable<I> + PartialEq + Copy {
105    fn relate<R: TypeRelation<I>>(relation: &mut R, a: Self, b: Self) -> RelateResult<I, Self>;
106}
107
108///////////////////////////////////////////////////////////////////////////
109// Relate impls
110
111#[inline]
112pub fn relate_args_invariantly<I: Interner, R: TypeRelation<I>>(
113    relation: &mut R,
114    a_arg: I::GenericArgs,
115    b_arg: I::GenericArgs,
116) -> RelateResult<I, I::GenericArgs> {
117    relation.cx().mk_args_from_iter(iter::zip(a_arg.iter(), b_arg.iter()).map(|(a, b)| {
118        relation.relate_with_variance(ty::Invariant, VarianceDiagInfo::default(), a, b)
119    }))
120}
121
122pub fn relate_args_with_variances<I: Interner, R: TypeRelation<I>>(
123    relation: &mut R,
124    variances: I::VariancesOf,
125    a_args: I::GenericArgs,
126    b_args: I::GenericArgs,
127) -> RelateResult<I, I::GenericArgs> {
128    let cx = relation.cx();
129    let args = iter::zip(a_args.iter(), b_args.iter()).enumerate().map(|(i, (a, b))| {
130        let variance = variances.get(i).unwrap();
131        relation.relate_with_variance(variance, VarianceDiagInfo::None, a, b)
132    });
133    // FIXME: We can probably try to reuse `a_args` here if it did not change.
134    cx.mk_args_from_iter(args)
135}
136
137impl<I: Interner> Relate<I> for ty::FnSig<I> {
138    fn relate<R: TypeRelation<I>>(
139        relation: &mut R,
140        a: ty::FnSig<I>,
141        b: ty::FnSig<I>,
142    ) -> RelateResult<I, ty::FnSig<I>> {
143        let cx = relation.cx();
144
145        if a.c_variadic() != b.c_variadic() {
146            return Err(TypeError::VariadicMismatch(ExpectedFound::new(
147                a.c_variadic(),
148                b.c_variadic(),
149            )));
150        }
151
152        if a.safety() != b.safety() {
153            return Err(TypeError::SafetyMismatch(ExpectedFound::new(a.safety(), b.safety())));
154        }
155
156        if a.abi() != b.abi() {
157            return Err(TypeError::AbiMismatch(ExpectedFound::new(a.abi(), b.abi())));
158        };
159
160        if a.splatted() != b.splatted() {
161            return Err(TypeError::SplatMismatch(ExpectedFound::new(a.splatted(), b.splatted())));
162        }
163
164        let a_inputs = a.inputs();
165        let b_inputs = b.inputs();
166        if a_inputs.len() != b_inputs.len() {
167            return Err(TypeError::ArgCount);
168        }
169
170        let inputs_and_output = iter::zip(a_inputs.iter(), b_inputs.iter())
171            .map(|(a, b)| ((a, b), false))
172            .chain(iter::once(((a.output(), b.output()), true)))
173            .map(|((a, b), is_output)| {
174                if is_output {
175                    relation.relate(a, b)
176                } else {
177                    relation.relate_with_variance(
178                        ty::Contravariant,
179                        VarianceDiagInfo::default(),
180                        a,
181                        b,
182                    )
183                }
184            })
185            .enumerate()
186            .map(|(i, r)| match r {
187                Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => {
188                    Err(TypeError::ArgumentSorts(exp_found, i))
189                }
190                Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => {
191                    Err(TypeError::ArgumentMutability(i))
192                }
193                r => r,
194            });
195        Ok(ty::FnSig {
196            inputs_and_output: cx.mk_type_list_from_iter(inputs_and_output)?,
197            fn_sig_kind: a.fn_sig_kind,
198        })
199    }
200}
201
202impl<I: Interner> Relate<I> for ty::AliasTy<I> {
203    fn relate<R: TypeRelation<I>>(
204        relation: &mut R,
205        a: ty::AliasTy<I>,
206        b: ty::AliasTy<I>,
207    ) -> RelateResult<I, ty::AliasTy<I>> {
208        if a.kind != b.kind {
209            Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.kind.into(), b.kind.into())))
210        } else {
211            let cx = relation.cx();
212            let args = if let Some(variances) = cx.opt_alias_variances(a.kind) {
213                relate_args_with_variances(relation, variances, a.args, b.args)?
214            } else {
215                relate_args_invariantly(relation, a.args, b.args)?
216            };
217            Ok(ty::AliasTy::new_from_args(relation.cx(), a.kind, args))
218        }
219    }
220}
221
222impl<I: Interner> Relate<I> for ty::AliasConst<I> {
223    fn relate<R: TypeRelation<I>>(
224        relation: &mut R,
225        a: ty::AliasConst<I>,
226        b: ty::AliasConst<I>,
227    ) -> RelateResult<I, ty::AliasConst<I>> {
228        let cx = relation.cx();
229        if a.kind != b.kind {
230            Err(TypeError::ConstMismatch(ExpectedFound::new(
231                Const::new_alias(cx, ty::IsRigid::yes_if_next_solver(cx), a),
232                Const::new_alias(cx, ty::IsRigid::yes_if_next_solver(cx), b),
233            )))
234        } else {
235            // FIXME(mgca): remove this
236            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());
237
238            let args = relate_args_invariantly(relation, a.args, b.args)?;
239
240            Ok(ty::AliasConst::new(cx, a.kind, args))
241        }
242    }
243}
244
245impl<I: Interner> Relate<I> for ty::AliasTerm<I> {
246    fn relate<R: TypeRelation<I>>(
247        relation: &mut R,
248        a: ty::AliasTerm<I>,
249        b: ty::AliasTerm<I>,
250    ) -> RelateResult<I, ty::AliasTerm<I>> {
251        if a.kind != b.kind {
252            Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.kind, b.kind)))
253        } else {
254            let args = match a.kind {
255                ty::AliasTermKind::OpaqueTy { def_id } => relate_args_with_variances(
256                    relation,
257                    relation.cx().variances_of(def_id.into()),
258                    a.args,
259                    b.args,
260                )?,
261                ty::AliasTermKind::ProjectionTy { .. }
262                | ty::AliasTermKind::FreeConst { .. }
263                | ty::AliasTermKind::FreeTy { .. }
264                | ty::AliasTermKind::InherentTy { .. }
265                | ty::AliasTermKind::InherentConstSelf { .. }
266                | ty::AliasTermKind::InherentConstImpl { .. }
267                | ty::AliasTermKind::AnonConst { .. }
268                | ty::AliasTermKind::ProjectionConst { .. } => {
269                    relate_args_invariantly(relation, a.args, b.args)?
270                }
271            };
272            Ok(a.with_args(relation.cx(), args))
273        }
274    }
275}
276
277impl<I: Interner> Relate<I> for ty::ExistentialProjection<I> {
278    fn relate<R: TypeRelation<I>>(
279        relation: &mut R,
280        a: ty::ExistentialProjection<I>,
281        b: ty::ExistentialProjection<I>,
282    ) -> RelateResult<I, ty::ExistentialProjection<I>> {
283        if a.def_id != b.def_id {
284            Err(TypeError::ProjectionMismatched(ExpectedFound::new(
285                relation.cx().alias_term_kind_from_def_id(
286                    a.def_id.into(),
287                    ty::AliasConstInherentArgsKind::WithSelf,
288                ),
289                relation.cx().alias_term_kind_from_def_id(
290                    b.def_id.into(),
291                    ty::AliasConstInherentArgsKind::WithSelf,
292                ),
293            )))
294        } else {
295            let term = relation.relate_with_variance(
296                ty::Invariant,
297                VarianceDiagInfo::default(),
298                a.term,
299                b.term,
300            )?;
301            let args = relation.relate_with_variance(
302                ty::Invariant,
303                VarianceDiagInfo::default(),
304                a.args,
305                b.args,
306            )?;
307            Ok(ty::ExistentialProjection::new_from_args(relation.cx(), a.def_id, args, term))
308        }
309    }
310}
311
312impl<I: Interner> Relate<I> for ty::TraitRef<I> {
313    fn relate<R: TypeRelation<I>>(
314        relation: &mut R,
315        a: ty::TraitRef<I>,
316        b: ty::TraitRef<I>,
317    ) -> RelateResult<I, ty::TraitRef<I>> {
318        // Different traits cannot be related.
319        if a.def_id != b.def_id {
320            Err(TypeError::Traits({
321                let a = a.def_id;
322                let b = b.def_id;
323                ExpectedFound::new(a, b)
324            }))
325        } else {
326            let args = relate_args_invariantly(relation, a.args, b.args)?;
327            Ok(ty::TraitRef::new_from_args(relation.cx(), a.def_id, args))
328        }
329    }
330}
331
332impl<I: Interner> Relate<I> for ty::ExistentialTraitRef<I> {
333    fn relate<R: TypeRelation<I>>(
334        relation: &mut R,
335        a: ty::ExistentialTraitRef<I>,
336        b: ty::ExistentialTraitRef<I>,
337    ) -> RelateResult<I, ty::ExistentialTraitRef<I>> {
338        // Different traits cannot be related.
339        if a.def_id != b.def_id {
340            Err(TypeError::Traits({
341                let a = a.def_id;
342                let b = b.def_id;
343                ExpectedFound::new(a, b)
344            }))
345        } else {
346            let args = relate_args_invariantly(relation, a.args, b.args)?;
347            Ok(ty::ExistentialTraitRef::new_from_args(relation.cx(), a.def_id, args))
348        }
349    }
350}
351
352/// Relates `a` and `b` structurally, calling the relation for all nested values.
353/// Any semantic equality, e.g. of projections, and inference variables have to be
354/// handled by the caller.
355{}
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("structurally_relate_tys",
                                "rustc_type_ir::relate", ::tracing::Level::TRACE,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/5a2be9f5f075d31e3ca5526b5b029881ce441253/compiler/rustc_type_ir/src/relate.rs"),
                                ::tracing_core::__macro_support::Option::Some(355u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate"),
                                ::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();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[allow(unknown_lints, unreachable_code, clippy ::
                    diverging_sub_expression, clippy :: empty_loop, clippy ::
                    let_unit_value, clippy :: let_with_type_underscore, clippy
                    :: needless_return, clippy :: unreachable)]
                    if false {
                        let __tracing_attr_fake_return: RelateResult<I, I::Ty> =
                            loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        let cx = relation.cx();
                        match (a.kind(), b.kind()) {
                            (ty::Infer(_), _) | (_, ty::Infer(_)) => {
                                {
                                    ::core::panicking::panic_fmt(format_args!("var types encountered in structurally_relate_tys"));
                                }
                            }
                            (ty::Bound(..), _) | (_, ty::Bound(..)) => {
                                {
                                    ::core::panicking::panic_fmt(format_args!("bound types encountered in structurally_relate_tys"));
                                }
                            }
                            (ty::Error(guar), _) | (_, ty::Error(guar)) =>
                                Ok(Ty::new_error(cx, guar)),
                            (ty::Never, _) | (ty::Char, _) | (ty::Bool, _) |
                                (ty::Int(_), _) | (ty::Uint(_), _) | (ty::Float(_), _) |
                                (ty::Str, _) if a == b => {
                                Ok(a)
                            }
                            (ty::Param(a_p), ty::Param(b_p)) if
                                a_p.index() == b_p.index() => {
                                Ok(a)
                            }
                            (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 =>
                                Ok(a),
                            (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if
                                a_def == b_def => {
                                if a_args.is_empty() {
                                    Ok(a)
                                } else {
                                    relation.relate_ty_args(a, b, a_def.def_id().into(), a_args,
                                        b_args, |args| { Ty::new_adt(cx, a_def, args) })
                                }
                            }
                            (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id =>
                                Ok(Ty::new_foreign(cx, a_id)),
                            (ty::Dynamic(a_obj, a_region), ty::Dynamic(b_obj, b_region))
                                =>
                                Ok(Ty::new_dynamic(cx, relation.relate(a_obj, b_obj)?,
                                        relation.relate(a_region, b_region)?)),
                            (ty::Coroutine(a_id, a_args), ty::Coroutine(b_id, b_args))
                                if a_id == b_id => {
                                let args =
                                    relate_args_invariantly(relation, a_args, b_args)?;
                                Ok(Ty::new_coroutine(cx, a_id, args))
                            }
                            (ty::CoroutineWitness(a_id, a_args),
                                ty::CoroutineWitness(b_id, b_args)) if a_id == b_id => {
                                let args =
                                    relate_args_invariantly(relation, a_args, b_args)?;
                                Ok(Ty::new_coroutine_witness(cx, a_id, args))
                            }
                            (ty::Closure(a_id, a_args), ty::Closure(b_id, b_args)) if
                                a_id == b_id => {
                                let args =
                                    relate_args_invariantly(relation, a_args, b_args)?;
                                Ok(Ty::new_closure(cx, a_id, args))
                            }
                            (ty::CoroutineClosure(a_id, a_args),
                                ty::CoroutineClosure(b_id, b_args)) if a_id == b_id => {
                                let args =
                                    relate_args_invariantly(relation, a_args, b_args)?;
                                Ok(Ty::new_coroutine_closure(cx, a_id, args))
                            }
                            (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => {
                                if a_mutbl != b_mutbl { return Err(TypeError::Mutability); }
                                let (variance, info) =
                                    match a_mutbl {
                                        Mutability::Not => (ty::Covariant, VarianceDiagInfo::None),
                                        Mutability::Mut => {
                                            (ty::Invariant,
                                                VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
                                        }
                                    };
                                let ty =
                                    relation.relate_with_variance(variance, info, a_ty, b_ty)?;
                                Ok(Ty::new_ptr(cx, ty, a_mutbl))
                            }
                            (ty::Ref(a_r, a_ty, a_mutbl), ty::Ref(b_r, b_ty, b_mutbl))
                                => {
                                if a_mutbl != b_mutbl { return Err(TypeError::Mutability); }
                                let (variance, info) =
                                    match a_mutbl {
                                        Mutability::Not => (ty::Covariant, VarianceDiagInfo::None),
                                        Mutability::Mut => {
                                            (ty::Invariant,
                                                VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
                                        }
                                    };
                                let r = relation.relate(a_r, b_r)?;
                                let ty =
                                    relation.relate_with_variance(variance, info, a_ty, b_ty)?;
                                Ok(Ty::new_ref(cx, r, ty, a_mutbl))
                            }
                            (ty::Array(a_t, sz_a), ty::Array(b_t, sz_b)) => {
                                let t = relation.relate(a_t, b_t)?;
                                match relation.relate(sz_a, sz_b) {
                                    Ok(sz) => Ok(Ty::new_array_with_const_len(cx, t, sz)),
                                    Err(TypeError::ConstMismatch(_)) => {
                                        Err(TypeError::ArraySize(ExpectedFound::new(sz_a, sz_b)))
                                    }
                                    Err(e) => Err(e),
                                }
                            }
                            (ty::Slice(a_t), ty::Slice(b_t)) => {
                                let t = relation.relate(a_t, b_t)?;
                                Ok(Ty::new_slice(cx, t))
                            }
                            (ty::Tuple(as_), ty::Tuple(bs)) => {
                                if as_.len() == bs.len() {
                                    Ok(Ty::new_tup_from_iter(cx,
                                                iter::zip(as_.iter(),
                                                        bs.iter()).map(|(a, b)| relation.relate(a, b)))?)
                                } else if !(as_.is_empty() || bs.is_empty()) {
                                    Err(TypeError::TupleSize(ExpectedFound::new(as_.len(),
                                                bs.len())))
                                } else { Err(TypeError::Sorts(ExpectedFound::new(a, b))) }
                            }
                            (ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args))
                                if a_def_id == b_def_id => {
                                if a_args.skip_binder().is_empty() {
                                    Ok(a)
                                } else {
                                    let x =
                                        relation.relate_ty_args(a, b, a_def_id.into(),
                                            a_args.skip_binder(), b_args.skip_binder(),
                                            |args| Ty::new_fn_def(cx, a_def_id, a_args.rebind(args)));
                                    x
                                }
                            }
                            (ty::FnPtr(a_sig_tys, a_hdr), ty::FnPtr(b_sig_tys, b_hdr))
                                => {
                                let fty =
                                    relation.relate(a_sig_tys.with(a_hdr),
                                            b_sig_tys.with(b_hdr))?;
                                Ok(Ty::new_fn_ptr(cx, fty))
                            }
                            (ty::Alias(is_rigid_a, alias_a),
                                ty::Alias(is_rigid_b, alias_b)) => {
                                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)));
                                                }
                                            }
                                        }
                                    };
                                };
                                let alias_ty = relation.relate(alias_a, alias_b)?;
                                Ok(Ty::new_alias(cx, is_rigid_a, alias_ty))
                            }
                            (ty::Pat(a_ty, a_pat), ty::Pat(b_ty, b_pat)) => {
                                let ty = relation.relate(a_ty, b_ty)?;
                                let pat = relation.relate(a_pat, b_pat)?;
                                Ok(Ty::new_pat(cx, ty, pat))
                            }
                            (ty::UnsafeBinder(a_binder), ty::UnsafeBinder(b_binder)) =>
                                {
                                Ok(Ty::new_unsafe_binder(cx,
                                        relation.binders(*a_binder, *b_binder)?))
                            }
                            _ => Err(TypeError::Sorts(ExpectedFound::new(a, b))),
                        }
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5a2be9f5f075d31e3ca5526b5b029881ce441253/compiler/rustc_type_ir/src/relate.rs:355",
                        "rustc_type_ir::relate", ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5a2be9f5f075d31e3ca5526b5b029881ce441253/compiler/rustc_type_ir/src/relate.rs"),
                        ::tracing_core::__macro_support::Option::Some(355u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[instrument(level = "trace", skip(relation), ret)]
356pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
357    relation: &mut R,
358    a: I::Ty,
359    b: I::Ty,
360) -> RelateResult<I, I::Ty> {
361    let cx = relation.cx();
362    match (a.kind(), b.kind()) {
363        (ty::Infer(_), _) | (_, ty::Infer(_)) => {
364            // The caller should handle these cases!
365            panic!("var types encountered in structurally_relate_tys")
366        }
367
368        (ty::Bound(..), _) | (_, ty::Bound(..)) => {
369            panic!("bound types encountered in structurally_relate_tys")
370        }
371
372        (ty::Error(guar), _) | (_, ty::Error(guar)) => Ok(Ty::new_error(cx, guar)),
373
374        (ty::Never, _)
375        | (ty::Char, _)
376        | (ty::Bool, _)
377        | (ty::Int(_), _)
378        | (ty::Uint(_), _)
379        | (ty::Float(_), _)
380        | (ty::Str, _)
381            if a == b =>
382        {
383            Ok(a)
384        }
385
386        (ty::Param(a_p), ty::Param(b_p)) if a_p.index() == b_p.index() => {
387            // FIXME: Put this back
388            //debug_assert_eq!(a_p.name(), b_p.name(), "param types with same index differ in name");
389            Ok(a)
390        }
391
392        (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a),
393
394        (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => {
395            if a_args.is_empty() {
396                Ok(a)
397            } else {
398                relation.relate_ty_args(a, b, a_def.def_id().into(), a_args, b_args, |args| {
399                    Ty::new_adt(cx, a_def, args)
400                })
401            }
402        }
403
404        (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(cx, a_id)),
405
406        (ty::Dynamic(a_obj, a_region), ty::Dynamic(b_obj, b_region)) => Ok(Ty::new_dynamic(
407            cx,
408            relation.relate(a_obj, b_obj)?,
409            relation.relate(a_region, b_region)?,
410        )),
411
412        (ty::Coroutine(a_id, a_args), ty::Coroutine(b_id, b_args)) if a_id == b_id => {
413            // All Coroutine types with the same id represent
414            // the (anonymous) type of the same coroutine expression. So
415            // all of their regions should be equated.
416            let args = relate_args_invariantly(relation, a_args, b_args)?;
417            Ok(Ty::new_coroutine(cx, a_id, args))
418        }
419
420        (ty::CoroutineWitness(a_id, a_args), ty::CoroutineWitness(b_id, b_args))
421            if a_id == b_id =>
422        {
423            // All CoroutineWitness types with the same id represent
424            // the (anonymous) type of the same coroutine expression. So
425            // all of their regions should be equated.
426            let args = relate_args_invariantly(relation, a_args, b_args)?;
427            Ok(Ty::new_coroutine_witness(cx, a_id, args))
428        }
429
430        (ty::Closure(a_id, a_args), ty::Closure(b_id, b_args)) if a_id == b_id => {
431            // All Closure types with the same id represent
432            // the (anonymous) type of the same closure 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_closure(cx, a_id, args))
436        }
437
438        (ty::CoroutineClosure(a_id, a_args), ty::CoroutineClosure(b_id, b_args))
439            if a_id == b_id =>
440        {
441            let args = relate_args_invariantly(relation, a_args, b_args)?;
442            Ok(Ty::new_coroutine_closure(cx, a_id, args))
443        }
444
445        (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => {
446            if a_mutbl != b_mutbl {
447                return Err(TypeError::Mutability);
448            }
449
450            let (variance, info) = match a_mutbl {
451                Mutability::Not => (ty::Covariant, VarianceDiagInfo::None),
452                Mutability::Mut => {
453                    (ty::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
454                }
455            };
456
457            let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
458
459            Ok(Ty::new_ptr(cx, ty, a_mutbl))
460        }
461
462        (ty::Ref(a_r, a_ty, a_mutbl), ty::Ref(b_r, b_ty, b_mutbl)) => {
463            if a_mutbl != b_mutbl {
464                return Err(TypeError::Mutability);
465            }
466
467            let (variance, info) = match a_mutbl {
468                Mutability::Not => (ty::Covariant, VarianceDiagInfo::None),
469                Mutability::Mut => {
470                    (ty::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
471                }
472            };
473
474            let r = relation.relate(a_r, b_r)?;
475            let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
476
477            Ok(Ty::new_ref(cx, r, ty, a_mutbl))
478        }
479
480        (ty::Array(a_t, sz_a), ty::Array(b_t, sz_b)) => {
481            let t = relation.relate(a_t, b_t)?;
482            match relation.relate(sz_a, sz_b) {
483                Ok(sz) => Ok(Ty::new_array_with_const_len(cx, t, sz)),
484                Err(TypeError::ConstMismatch(_)) => {
485                    Err(TypeError::ArraySize(ExpectedFound::new(sz_a, sz_b)))
486                }
487                Err(e) => Err(e),
488            }
489        }
490
491        (ty::Slice(a_t), ty::Slice(b_t)) => {
492            let t = relation.relate(a_t, b_t)?;
493            Ok(Ty::new_slice(cx, t))
494        }
495
496        (ty::Tuple(as_), ty::Tuple(bs)) => {
497            if as_.len() == bs.len() {
498                Ok(Ty::new_tup_from_iter(
499                    cx,
500                    iter::zip(as_.iter(), bs.iter()).map(|(a, b)| relation.relate(a, b)),
501                )?)
502            } else if !(as_.is_empty() || bs.is_empty()) {
503                Err(TypeError::TupleSize(ExpectedFound::new(as_.len(), bs.len())))
504            } else {
505                Err(TypeError::Sorts(ExpectedFound::new(a, b)))
506            }
507        }
508
509        (ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => {
510            if a_args.skip_binder().is_empty() {
511                Ok(a)
512            } else {
513                // FIXME: this behavior is wrong; relations with binders needs fixing.
514                //        need to relate the bound vars first.
515                let x = relation.relate_ty_args(
516                    a,
517                    b,
518                    a_def_id.into(),
519                    a_args.skip_binder(),
520                    b_args.skip_binder(),
521                    |args| Ty::new_fn_def(cx, a_def_id, a_args.rebind(args)),
522                );
523                x
524            }
525        }
526
527        (ty::FnPtr(a_sig_tys, a_hdr), ty::FnPtr(b_sig_tys, b_hdr)) => {
528            let fty = relation.relate(a_sig_tys.with(a_hdr), b_sig_tys.with(b_hdr))?;
529            Ok(Ty::new_fn_ptr(cx, fty))
530        }
531
532        // Alias tend to mostly already be handled downstream due to normalization.
533        (ty::Alias(is_rigid_a, alias_a), ty::Alias(is_rigid_b, alias_b)) => {
534            // Users shouldn't know about this so the mismatch should be caught
535            // during development rather than presented as type error.
536            debug_assert_eq!(is_rigid_a, is_rigid_b, "{a:?} != {b:?}");
537            let alias_ty = relation.relate(alias_a, alias_b)?;
538            Ok(Ty::new_alias(cx, is_rigid_a, alias_ty))
539        }
540
541        (ty::Pat(a_ty, a_pat), ty::Pat(b_ty, b_pat)) => {
542            let ty = relation.relate(a_ty, b_ty)?;
543            let pat = relation.relate(a_pat, b_pat)?;
544            Ok(Ty::new_pat(cx, ty, pat))
545        }
546
547        (ty::UnsafeBinder(a_binder), ty::UnsafeBinder(b_binder)) => {
548            Ok(Ty::new_unsafe_binder(cx, relation.binders(*a_binder, *b_binder)?))
549        }
550
551        _ => Err(TypeError::Sorts(ExpectedFound::new(a, b))),
552    }
553}
554
555/// Relates `a` and `b` structurally, calling the relation for all nested values.
556/// Any semantic equality, e.g. of alias consts, and inference variables have
557/// to be handled by the caller.
558///
559/// FIXME: This is not totally structural, which probably should be fixed.
560/// See the HACKs below.
561pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>(
562    relation: &mut R,
563    mut a: I::Const,
564    mut b: I::Const,
565) -> RelateResult<I, I::Const> {
566    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5a2be9f5f075d31e3ca5526b5b029881ce441253/compiler/rustc_type_ir/src/relate.rs:566",
                        "rustc_type_ir::relate", ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5a2be9f5f075d31e3ca5526b5b029881ce441253/compiler/rustc_type_ir/src/relate.rs"),
                        ::tracing_core::__macro_support::Option::Some(566u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("structurally_relate_consts::<{0}>(a = {1:?}, b = {2:?})",
                                                    std::any::type_name::<R>(), a, b) as
                                            &dyn ::tracing::field::Value))])
            });
    } else { ; }
};trace!(
567        "structurally_relate_consts::<{}>(a = {:?}, b = {:?})",
568        std::any::type_name::<R>(),
569        a,
570        b
571    );
572    let cx = relation.cx();
573
574    if cx.features().generic_const_exprs() {
575        a = cx.expand_abstract_consts(a);
576        b = cx.expand_abstract_consts(b);
577    }
578
579    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5a2be9f5f075d31e3ca5526b5b029881ce441253/compiler/rustc_type_ir/src/relate.rs:579",
                        "rustc_type_ir::relate", ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5a2be9f5f075d31e3ca5526b5b029881ce441253/compiler/rustc_type_ir/src/relate.rs"),
                        ::tracing_core::__macro_support::Option::Some(579u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::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 ::tracing::field::Value))])
            });
    } else { ; }
};trace!(
580        "structurally_relate_consts::<{}>(normed_a = {:?}, normed_b = {:?})",
581        std::any::type_name::<R>(),
582        a,
583        b
584    );
585
586    // Currently, the values that can be unified are primitive types,
587    // and those that derive both `PartialEq` and `Eq`, corresponding
588    // to structural-match types.
589    let is_match = match (a.kind(), b.kind()) {
590        (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
591            // The caller should handle these cases!
592            {
    ::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)
593        }
594
595        (ty::ConstKind::Error(_), _) => return Ok(a),
596        (_, ty::ConstKind::Error(_)) => return Ok(b),
597
598        (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index() == b_p.index() => {
599            // FIXME: Put this back
600            // debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name");
601            true
602        }
603        (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
604        (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
605            match (a_val.valtree().kind(), b_val.valtree().kind()) {
606                (ty::ValTreeKind::Leaf(scalar_a), ty::ValTreeKind::Leaf(scalar_b)) => {
607                    scalar_a == scalar_b
608                }
609                (ty::ValTreeKind::Branch(branches_a), ty::ValTreeKind::Branch(branches_b))
610                    if branches_a.len() == branches_b.len() =>
611                {
612                    branches_a
613                        .iter()
614                        .zip(branches_b.iter())
615                        .all(|(a, b)| relation.relate(a, b).is_ok())
616                }
617                _ => false,
618            }
619        }
620
621        // While this is slightly incorrect, it shouldn't matter for `min_const_generics`
622        // and is the better alternative to waiting until `generic_const_exprs` can
623        // be stabilized.
624        (ty::ConstKind::Alias(is_rigid_a, au), ty::ConstKind::Alias(is_rigid_b, bu)) => {
625            // Users shouldn't know about this so the mismatch should be caught
626            // during development rather than presented as type error.
627            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:?}");
628            return Ok(Const::new_alias(cx, is_rigid_a, relation.relate(au, bu)?));
629        }
630        (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => {
631            let expr = relation.relate(ae, be)?;
632            return Ok(Const::new_expr(cx, expr));
633        }
634        _ => false,
635    };
636    if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(ExpectedFound::new(a, b))) }
637}
638
639impl<I: Interner, T: Relate<I>> Relate<I> for ty::Binder<I, T> {
640    fn relate<R: TypeRelation<I>>(
641        relation: &mut R,
642        a: ty::Binder<I, T>,
643        b: ty::Binder<I, T>,
644    ) -> RelateResult<I, ty::Binder<I, T>> {
645        relation.binders(a, b)
646    }
647}
648
649impl<I: Interner> Relate<I> for ty::TraitClause<I> {
650    fn relate<R: TypeRelation<I>>(
651        relation: &mut R,
652        a: ty::TraitClause<I>,
653        b: ty::TraitClause<I>,
654    ) -> RelateResult<I, ty::TraitClause<I>> {
655        let trait_ref = relation.relate(a.trait_ref, b.trait_ref)?;
656        if a.polarity != b.polarity {
657            return Err(TypeError::PolarityMismatch(ExpectedFound::new(a.polarity, b.polarity)));
658        }
659        Ok(ty::TraitClause { trait_ref, polarity: a.polarity })
660    }
661}