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 let tcx = relation.cx();
53 match (&*a, &*b) {
54 (
55 &ty::PatternKind::Range { start: start_a, end: end_a },
56 &ty::PatternKind::Range { start: start_b, end: end_b },
57 ) => {
58 let start = relation.relate(start_a, start_b)?;
59 let end = relation.relate(end_a, end_b)?;
60 Ok(tcx.mk_pat(ty::PatternKind::Range { start, end }))
61 }
62 (&ty::PatternKind::Or(a), &ty::PatternKind::Or(b)) => {
63 if a.len() != b.len() {
64 return Err(TypeError::Mismatch);
65 }
66 let v = iter::zip(a, b).map(|(a, b)| relation.relate(a, b));
67 let patterns = tcx.mk_patterns_from_iter(v)?;
68 Ok(tcx.mk_pat(ty::PatternKind::Or(patterns)))
69 }
70 (ty::PatternKind::Range { .. } | ty::PatternKind::Or(_), _) => Err(TypeError::Mismatch),
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 if a.len() != b.len() {
86 return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
87 }
88 let v =
89 iter::zip(a, b).map(|(ep_a, ep_b)| match (ep_a.skip_binder(), ep_b.skip_binder()) {
90 (ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => {
91 Ok(ep_a.rebind(ty::ExistentialPredicate::Trait(
92 relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
93 )))
94 }
95 (
96 ty::ExistentialPredicate::Projection(a),
97 ty::ExistentialPredicate::Projection(b),
98 ) => Ok(ep_a.rebind(ty::ExistentialPredicate::Projection(
99 relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
100 ))),
101 (
102 ty::ExistentialPredicate::AutoTrait(a),
103 ty::ExistentialPredicate::AutoTrait(b),
104 ) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))),
105 _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))),
106 });
107 tcx.mk_poly_existential_predicates_from_iter(v)
108 }
109}
110
111impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> {
112 fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
113 relation: &mut R,
114 a: ty::GenericArgsRef<'tcx>,
115 b: ty::GenericArgsRef<'tcx>,
116 ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> {
117 relate_args_invariantly(relation, a, b)
118 }
119}
120
121impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Region<'tcx> {
122 fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
123 relation: &mut R,
124 a: ty::Region<'tcx>,
125 b: ty::Region<'tcx>,
126 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
127 relation.regions(a, b)
128 }
129}
130
131impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Const<'tcx> {
132 fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
133 relation: &mut R,
134 a: ty::Const<'tcx>,
135 b: ty::Const<'tcx>,
136 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
137 relation.consts(a, b)
138 }
139}
140
141impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Expr<'tcx> {
142 fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
143 relation: &mut R,
144 ae: ty::Expr<'tcx>,
145 be: ty::Expr<'tcx>,
146 ) -> RelateResult<'tcx, ty::Expr<'tcx>> {
147 match (ae.kind, be.kind) {
154 (ty::ExprKind::Binop(a_binop), ty::ExprKind::Binop(b_binop)) if a_binop == b_binop => {}
155 (ty::ExprKind::UnOp(a_unop), ty::ExprKind::UnOp(b_unop)) if a_unop == b_unop => {}
156 (ty::ExprKind::FunctionCall, ty::ExprKind::FunctionCall) => {}
157 (ty::ExprKind::Cast(a_kind), ty::ExprKind::Cast(b_kind)) if a_kind == b_kind => {}
158 _ => return Err(TypeError::Mismatch),
159 }
160
161 let args = relation.relate(ae.args(), be.args())?;
162 Ok(ty::Expr::new(ae.kind, args))
163 }
164}
165
166impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArg<'tcx> {
167 fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
168 relation: &mut R,
169 a: ty::GenericArg<'tcx>,
170 b: ty::GenericArg<'tcx>,
171 ) -> RelateResult<'tcx, ty::GenericArg<'tcx>> {
172 match (a.unpack(), b.unpack()) {
173 (ty::GenericArgKind::Lifetime(a_lt), ty::GenericArgKind::Lifetime(b_lt)) => {
174 Ok(relation.relate(a_lt, b_lt)?.into())
175 }
176 (ty::GenericArgKind::Type(a_ty), ty::GenericArgKind::Type(b_ty)) => {
177 Ok(relation.relate(a_ty, b_ty)?.into())
178 }
179 (ty::GenericArgKind::Const(a_ct), ty::GenericArgKind::Const(b_ct)) => {
180 Ok(relation.relate(a_ct, b_ct)?.into())
181 }
182 _ => bug!("impossible case reached: can't relate: {a:?} with {b:?}"),
183 }
184 }
185}
186
187impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Term<'tcx> {
188 fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
189 relation: &mut R,
190 a: Self,
191 b: Self,
192 ) -> RelateResult<'tcx, Self> {
193 Ok(match (a.unpack(), b.unpack()) {
194 (ty::TermKind::Ty(a), ty::TermKind::Ty(b)) => relation.relate(a, b)?.into(),
195 (ty::TermKind::Const(a), ty::TermKind::Const(b)) => relation.relate(a, b)?.into(),
196 _ => return Err(TypeError::Mismatch),
197 })
198 }
199}