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::ImplSubject<'tcx> {
11    #[inline]
12    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
13        relation: &mut R,
14        a: ty::ImplSubject<'tcx>,
15        b: ty::ImplSubject<'tcx>,
16    ) -> RelateResult<'tcx, ty::ImplSubject<'tcx>> {
17        match (a, b) {
18            (ty::ImplSubject::Trait(trait_ref_a), ty::ImplSubject::Trait(trait_ref_b)) => {
19                let trait_ref = ty::TraitRef::relate(relation, trait_ref_a, trait_ref_b)?;
20                Ok(ty::ImplSubject::Trait(trait_ref))
21            }
22            (ty::ImplSubject::Inherent(ty_a), ty::ImplSubject::Inherent(ty_b)) => {
23                let ty = Ty::relate(relation, ty_a, ty_b)?;
24                Ok(ty::ImplSubject::Inherent(ty))
25            }
26            (ty::ImplSubject::Trait(_), ty::ImplSubject::Inherent(_))
27            | (ty::ImplSubject::Inherent(_), ty::ImplSubject::Trait(_)) => {
28                bug!("can not relate TraitRef and Ty");
29            }
30        }
31    }
32}
33
34impl<'tcx> Relate<TyCtxt<'tcx>> for Ty<'tcx> {
35    #[inline]
36    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
37        relation: &mut R,
38        a: Ty<'tcx>,
39        b: Ty<'tcx>,
40    ) -> RelateResult<'tcx, Ty<'tcx>> {
41        relation.tys(a, b)
42    }
43}
44
45impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'tcx> {
46    #[inline]
47    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
48        relation: &mut R,
49        a: Self,
50        b: Self,
51    ) -> RelateResult<'tcx, Self> {
52        match (&*a, &*b) {
53            (
54                &ty::PatternKind::Range { start: start_a, end: end_a, include_end: inc_a },
55                &ty::PatternKind::Range { start: start_b, end: end_b, include_end: inc_b },
56            ) => {
57                // FIXME(pattern_types): make equal patterns equal (`0..=` is the same as `..=`).
58                let mut relate_opt_const = |a, b| match (a, b) {
59                    (None, None) => Ok(None),
60                    (Some(a), Some(b)) => relation.relate(a, b).map(Some),
61                    // FIXME(pattern_types): report a better error
62                    _ => Err(TypeError::Mismatch),
63                };
64                let start = relate_opt_const(start_a, start_b)?;
65                let end = relate_opt_const(end_a, end_b)?;
66                if inc_a != inc_b {
67                    todo!()
68                }
69                Ok(relation.cx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a }))
70            }
71        }
72    }
73}
74
75impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
76    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
77        relation: &mut R,
78        a: Self,
79        b: Self,
80    ) -> RelateResult<'tcx, Self> {
81        let tcx = relation.cx();
82
83        // FIXME: this is wasteful, but want to do a perf run to see how slow it is.
84        // We need to perform this deduplication as we sometimes generate duplicate projections
85        // in `a`.
86        let mut a_v: Vec<_> = a.into_iter().collect();
87        let mut b_v: Vec<_> = b.into_iter().collect();
88        a_v.dedup();
89        b_v.dedup();
90        if a_v.len() != b_v.len() {
91            return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
92        }
93
94        let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
95            match (ep_a.skip_binder(), ep_b.skip_binder()) {
96                (ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => {
97                    Ok(ep_a.rebind(ty::ExistentialPredicate::Trait(
98                        relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
99                    )))
100                }
101                (
102                    ty::ExistentialPredicate::Projection(a),
103                    ty::ExistentialPredicate::Projection(b),
104                ) => Ok(ep_a.rebind(ty::ExistentialPredicate::Projection(
105                    relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
106                ))),
107                (
108                    ty::ExistentialPredicate::AutoTrait(a),
109                    ty::ExistentialPredicate::AutoTrait(b),
110                ) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))),
111                _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))),
112            }
113        });
114        tcx.mk_poly_existential_predicates_from_iter(v)
115    }
116}
117
118impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> {
119    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
120        relation: &mut R,
121        a: ty::GenericArgsRef<'tcx>,
122        b: ty::GenericArgsRef<'tcx>,
123    ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> {
124        relate_args_invariantly(relation, a, b)
125    }
126}
127
128impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Region<'tcx> {
129    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
130        relation: &mut R,
131        a: ty::Region<'tcx>,
132        b: ty::Region<'tcx>,
133    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
134        relation.regions(a, b)
135    }
136}
137
138impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Const<'tcx> {
139    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
140        relation: &mut R,
141        a: ty::Const<'tcx>,
142        b: ty::Const<'tcx>,
143    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
144        relation.consts(a, b)
145    }
146}
147
148impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Expr<'tcx> {
149    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
150        relation: &mut R,
151        ae: ty::Expr<'tcx>,
152        be: ty::Expr<'tcx>,
153    ) -> RelateResult<'tcx, ty::Expr<'tcx>> {
154        // FIXME(generic_const_exprs): is it possible to relate two consts which are not identical
155        // exprs? Should we care about that?
156        // FIXME(generic_const_exprs): relating the `ty()`s is a little weird since it is supposed to
157        // ICE If they mismatch. Unfortunately `ConstKind::Expr` is a little special and can be thought
158        // of as being generic over the argument types, however this is implicit so these types don't get
159        // related when we relate the args of the item this const arg is for.
160        match (ae.kind, be.kind) {
161            (ty::ExprKind::Binop(a_binop), ty::ExprKind::Binop(b_binop)) if a_binop == b_binop => {}
162            (ty::ExprKind::UnOp(a_unop), ty::ExprKind::UnOp(b_unop)) if a_unop == b_unop => {}
163            (ty::ExprKind::FunctionCall, ty::ExprKind::FunctionCall) => {}
164            (ty::ExprKind::Cast(a_kind), ty::ExprKind::Cast(b_kind)) if a_kind == b_kind => {}
165            _ => return Err(TypeError::Mismatch),
166        }
167
168        let args = relation.relate(ae.args(), be.args())?;
169        Ok(ty::Expr::new(ae.kind, args))
170    }
171}
172
173impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArg<'tcx> {
174    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
175        relation: &mut R,
176        a: ty::GenericArg<'tcx>,
177        b: ty::GenericArg<'tcx>,
178    ) -> RelateResult<'tcx, ty::GenericArg<'tcx>> {
179        match (a.unpack(), b.unpack()) {
180            (ty::GenericArgKind::Lifetime(a_lt), ty::GenericArgKind::Lifetime(b_lt)) => {
181                Ok(relation.relate(a_lt, b_lt)?.into())
182            }
183            (ty::GenericArgKind::Type(a_ty), ty::GenericArgKind::Type(b_ty)) => {
184                Ok(relation.relate(a_ty, b_ty)?.into())
185            }
186            (ty::GenericArgKind::Const(a_ct), ty::GenericArgKind::Const(b_ct)) => {
187                Ok(relation.relate(a_ct, b_ct)?.into())
188            }
189            _ => bug!("impossible case reached: can't relate: {a:?} with {b:?}"),
190        }
191    }
192}
193
194impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Term<'tcx> {
195    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
196        relation: &mut R,
197        a: Self,
198        b: Self,
199    ) -> RelateResult<'tcx, Self> {
200        Ok(match (a.unpack(), b.unpack()) {
201            (ty::TermKind::Ty(a), ty::TermKind::Ty(b)) => relation.relate(a, b)?.into(),
202            (ty::TermKind::Const(a), ty::TermKind::Const(b)) => relation.relate(a, b)?.into(),
203            _ => return Err(TypeError::Mismatch),
204        })
205    }
206}