Skip to main content

rustc_middle/ty/
relate.rs

1use std::iter;
2
3pub use rustc_type_ir::relate::*;
4
5use crate::ty::error::{ExpectedFound, TypeError};
6use crate::ty::{self as ty, Ty, TyCtxt};
7
8pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>;
9
10impl<'tcx> Relate<TyCtxt<'tcx>> for Ty<'tcx> {
11    #[inline]
12    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
13        relation: &mut R,
14        a: Ty<'tcx>,
15        b: Ty<'tcx>,
16    ) -> RelateResult<'tcx, Ty<'tcx>> {
17        relation.tys(a, b)
18    }
19}
20
21impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'tcx> {
22    #[inline]
23    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
24        relation: &mut R,
25        a: Self,
26        b: Self,
27    ) -> RelateResult<'tcx, Self> {
28        let tcx = relation.cx();
29        match (&*a, &*b) {
30            (
31                &ty::PatternKind::Range { start: start_a, end: end_a },
32                &ty::PatternKind::Range { start: start_b, end: end_b },
33            ) => {
34                let start = relation.relate(start_a, start_b)?;
35                let end = relation.relate(end_a, end_b)?;
36                Ok(tcx.mk_pat(ty::PatternKind::Range { start, end }))
37            }
38            (ty::PatternKind::NotNull, ty::PatternKind::NotNull) => Ok(a),
39            (&ty::PatternKind::Or(a), &ty::PatternKind::Or(b)) => {
40                if a.len() != b.len() {
41                    return Err(TypeError::Mismatch);
42                }
43                let v = iter::zip(a, b).map(|(a, b)| relation.relate(a, b));
44                let patterns = tcx.mk_patterns_from_iter(v)?;
45                Ok(tcx.mk_pat(ty::PatternKind::Or(patterns)))
46            }
47            (
48                ty::PatternKind::NotNull | ty::PatternKind::Range { .. } | ty::PatternKind::Or(_),
49                _,
50            ) => Err(TypeError::Mismatch),
51        }
52    }
53}
54
55impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
56    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
57        relation: &mut R,
58        a: Self,
59        b: Self,
60    ) -> RelateResult<'tcx, Self> {
61        let tcx = relation.cx();
62        // Fast path for when the auto traits do not match, or if the principals
63        // are from different traits and therefore the projections definitely don't
64        // match up.
65        if a.len() != b.len() {
66            return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
67        }
68        let v =
69            iter::zip(a, b).map(|(ep_a, ep_b)| match (ep_a.skip_binder(), ep_b.skip_binder()) {
70                (ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => {
71                    Ok(ep_a.rebind(ty::ExistentialPredicate::Trait(
72                        relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
73                    )))
74                }
75                (
76                    ty::ExistentialPredicate::Projection(a),
77                    ty::ExistentialPredicate::Projection(b),
78                ) => Ok(ep_a.rebind(ty::ExistentialPredicate::Projection(
79                    relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
80                ))),
81                (
82                    ty::ExistentialPredicate::AutoTrait(a),
83                    ty::ExistentialPredicate::AutoTrait(b),
84                ) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))),
85                _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))),
86            });
87        tcx.mk_poly_existential_predicates_from_iter(v)
88    }
89}
90
91impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> {
92    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
93        relation: &mut R,
94        a: ty::GenericArgsRef<'tcx>,
95        b: ty::GenericArgsRef<'tcx>,
96    ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> {
97        relate_args_invariantly(relation, a, b)
98    }
99}
100
101impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Const<'tcx> {
102    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
103        relation: &mut R,
104        a: ty::Const<'tcx>,
105        b: ty::Const<'tcx>,
106    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
107        relation.consts(a, b)
108    }
109}
110
111impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Expr<'tcx> {
112    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
113        relation: &mut R,
114        ae: ty::Expr<'tcx>,
115        be: ty::Expr<'tcx>,
116    ) -> RelateResult<'tcx, ty::Expr<'tcx>> {
117        // FIXME(generic_const_exprs): is it possible to relate two consts which are not identical
118        // exprs? Should we care about that?
119        // FIXME(generic_const_exprs): relating the `ty()`s is a little weird since it is supposed to
120        // ICE If they mismatch. Unfortunately `ConstKind::Expr` is a little special and can be thought
121        // of as being generic over the argument types, however this is implicit so these types don't get
122        // related when we relate the args of the item this const arg is for.
123        match (ae.kind, be.kind) {
124            (ty::ExprKind::Binop(a_binop), ty::ExprKind::Binop(b_binop)) if a_binop == b_binop => {}
125            (ty::ExprKind::UnOp(a_unop), ty::ExprKind::UnOp(b_unop)) if a_unop == b_unop => {}
126            (ty::ExprKind::FunctionCall, ty::ExprKind::FunctionCall) => {}
127            (ty::ExprKind::Cast(a_kind), ty::ExprKind::Cast(b_kind)) if a_kind == b_kind => {}
128            _ => return Err(TypeError::Mismatch),
129        }
130
131        let args = relation.relate(ae.args(), be.args())?;
132        Ok(ty::Expr::new(ae.kind, args))
133    }
134}
135
136impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArg<'tcx> {
137    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
138        relation: &mut R,
139        a: ty::GenericArg<'tcx>,
140        b: ty::GenericArg<'tcx>,
141    ) -> RelateResult<'tcx, ty::GenericArg<'tcx>> {
142        match (a.kind(), b.kind()) {
143            (ty::GenericArgKind::Lifetime(a_lt), ty::GenericArgKind::Lifetime(b_lt)) => {
144                Ok(relation.relate(a_lt, b_lt)?.into())
145            }
146            (ty::GenericArgKind::Type(a_ty), ty::GenericArgKind::Type(b_ty)) => {
147                Ok(relation.relate(a_ty, b_ty)?.into())
148            }
149            (ty::GenericArgKind::Const(a_ct), ty::GenericArgKind::Const(b_ct)) => {
150                Ok(relation.relate(a_ct, b_ct)?.into())
151            }
152            _ => crate::util::bug::bug_fmt(format_args!("impossible case reached: can\'t relate: {0:?} with {1:?}",
        a, b))bug!("impossible case reached: can't relate: {a:?} with {b:?}"),
153        }
154    }
155}
156
157impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Term<'tcx> {
158    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
159        relation: &mut R,
160        a: Self,
161        b: Self,
162    ) -> RelateResult<'tcx, Self> {
163        Ok(match (a.kind(), b.kind()) {
164            (ty::TermKind::Ty(a), ty::TermKind::Ty(b)) => relation.relate(a, b)?.into(),
165            (ty::TermKind::Const(a), ty::TermKind::Const(b)) => relation.relate(a, b)?.into(),
166            _ => return Err(TypeError::Mismatch),
167        })
168    }
169}