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#[derive(Debug, Copy, Clone)]
24pub enum StructurallyRelateAliases {
25 Yes,
26 No,
27}
28
29#[derive_where(Clone, Copy, PartialEq, Eq, Debug, Default; I: Interner)]
37pub enum VarianceDiagInfo<I: Interner> {
38 #[derive_where(default)]
41 None,
42 Invariant {
45 ty: I::Ty,
48 param_index: u32,
51 },
52}
53
54impl<I: Interner> VarianceDiagInfo<I> {
55 pub fn xform(self, other: VarianceDiagInfo<I>) -> VarianceDiagInfo<I> {
58 match self {
60 VarianceDiagInfo::None => other,
61 VarianceDiagInfo::Invariant { .. } => self,
62 }
63 }
64}
65
66pub trait TypeRelation<I: Interner>: Sized {
67 fn cx(&self) -> I;
68
69 fn relate<T: Relate<I>>(&mut self, a: T, b: T) -> RelateResult<I, T> {
71 Relate::relate(self, a, b)
72 }
73
74 #[instrument(skip(self), level = "trace")]
78 fn relate_item_args(
79 &mut self,
80 item_def_id: I::DefId,
81 a_arg: I::GenericArgs,
82 b_arg: I::GenericArgs,
83 ) -> RelateResult<I, I::GenericArgs> {
84 let cx = self.cx();
85 let opt_variances = cx.variances_of(item_def_id);
86 relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, true)
87 }
88
89 fn relate_with_variance<T: Relate<I>>(
91 &mut self,
92 variance: ty::Variance,
93 info: VarianceDiagInfo<I>,
94 a: T,
95 b: T,
96 ) -> RelateResult<I, T>;
97
98 fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty>;
105
106 fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region>;
107
108 fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const>;
109
110 fn binders<T>(
111 &mut self,
112 a: ty::Binder<I, T>,
113 b: ty::Binder<I, T>,
114 ) -> RelateResult<I, ty::Binder<I, T>>
115 where
116 T: Relate<I>;
117}
118
119pub trait Relate<I: Interner>: TypeFoldable<I> + PartialEq + Copy {
120 fn relate<R: TypeRelation<I>>(relation: &mut R, a: Self, b: Self) -> RelateResult<I, Self>;
121}
122
123#[inline]
127pub fn relate_args_invariantly<I: Interner, R: TypeRelation<I>>(
128 relation: &mut R,
129 a_arg: I::GenericArgs,
130 b_arg: I::GenericArgs,
131) -> RelateResult<I, I::GenericArgs> {
132 relation.cx().mk_args_from_iter(iter::zip(a_arg.iter(), b_arg.iter()).map(|(a, b)| {
133 relation.relate_with_variance(ty::Invariant, VarianceDiagInfo::default(), a, b)
134 }))
135}
136
137pub fn relate_args_with_variances<I: Interner, R: TypeRelation<I>>(
138 relation: &mut R,
139 ty_def_id: I::DefId,
140 variances: I::VariancesOf,
141 a_arg: I::GenericArgs,
142 b_arg: I::GenericArgs,
143 fetch_ty_for_diag: bool,
144) -> RelateResult<I, I::GenericArgs> {
145 let cx = relation.cx();
146
147 let mut cached_ty = None;
148 let params = iter::zip(a_arg.iter(), b_arg.iter()).enumerate().map(|(i, (a, b))| {
149 let variance = variances.get(i).unwrap();
150 let variance_info = if variance == ty::Invariant && fetch_ty_for_diag {
151 let ty = *cached_ty.get_or_insert_with(|| cx.type_of(ty_def_id).instantiate(cx, a_arg));
152 VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
153 } else {
154 VarianceDiagInfo::default()
155 };
156 relation.relate_with_variance(variance, variance_info, a, b)
157 });
158
159 cx.mk_args_from_iter(params)
160}
161
162impl<I: Interner> Relate<I> for ty::FnSig<I> {
163 fn relate<R: TypeRelation<I>>(
164 relation: &mut R,
165 a: ty::FnSig<I>,
166 b: ty::FnSig<I>,
167 ) -> RelateResult<I, ty::FnSig<I>> {
168 let cx = relation.cx();
169
170 if a.c_variadic != b.c_variadic {
171 return Err(TypeError::VariadicMismatch({
172 let a = a.c_variadic;
173 let b = b.c_variadic;
174 ExpectedFound::new(a, b)
175 }));
176 }
177
178 if a.safety != b.safety {
179 return Err(TypeError::SafetyMismatch(ExpectedFound::new(a.safety, b.safety)));
180 }
181
182 if a.abi != b.abi {
183 return Err(TypeError::AbiMismatch(ExpectedFound::new(a.abi, b.abi)));
184 };
185
186 let a_inputs = a.inputs();
187 let b_inputs = b.inputs();
188 if a_inputs.len() != b_inputs.len() {
189 return Err(TypeError::ArgCount);
190 }
191
192 let inputs_and_output = iter::zip(a_inputs.iter(), b_inputs.iter())
193 .map(|(a, b)| ((a, b), false))
194 .chain(iter::once(((a.output(), b.output()), true)))
195 .map(|((a, b), is_output)| {
196 if is_output {
197 relation.relate(a, b)
198 } else {
199 relation.relate_with_variance(
200 ty::Contravariant,
201 VarianceDiagInfo::default(),
202 a,
203 b,
204 )
205 }
206 })
207 .enumerate()
208 .map(|(i, r)| match r {
209 Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => {
210 Err(TypeError::ArgumentSorts(exp_found, i))
211 }
212 Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => {
213 Err(TypeError::ArgumentMutability(i))
214 }
215 r => r,
216 });
217 Ok(ty::FnSig {
218 inputs_and_output: cx.mk_type_list_from_iter(inputs_and_output)?,
219 c_variadic: a.c_variadic,
220 safety: a.safety,
221 abi: a.abi,
222 })
223 }
224}
225
226impl<I: Interner> Relate<I> for ty::AliasTy<I> {
227 fn relate<R: TypeRelation<I>>(
228 relation: &mut R,
229 a: ty::AliasTy<I>,
230 b: ty::AliasTy<I>,
231 ) -> RelateResult<I, ty::AliasTy<I>> {
232 if a.def_id != b.def_id {
233 Err(TypeError::ProjectionMismatched({
234 let a = a.def_id;
235 let b = b.def_id;
236 ExpectedFound::new(a, b)
237 }))
238 } else {
239 let cx = relation.cx();
240 let args = if let Some(variances) = cx.opt_alias_variances(a.kind(cx), a.def_id) {
241 relate_args_with_variances(
242 relation, a.def_id, variances, a.args, b.args,
243 false, )?
245 } else {
246 relate_args_invariantly(relation, a.args, b.args)?
247 };
248 Ok(ty::AliasTy::new_from_args(relation.cx(), a.def_id, args))
249 }
250 }
251}
252
253impl<I: Interner> Relate<I> for ty::AliasTerm<I> {
254 fn relate<R: TypeRelation<I>>(
255 relation: &mut R,
256 a: ty::AliasTerm<I>,
257 b: ty::AliasTerm<I>,
258 ) -> RelateResult<I, ty::AliasTerm<I>> {
259 if a.def_id != b.def_id {
260 Err(TypeError::ProjectionMismatched({
261 let a = a.def_id;
262 let b = b.def_id;
263 ExpectedFound::new(a, b)
264 }))
265 } else {
266 let args = match a.kind(relation.cx()) {
267 ty::AliasTermKind::OpaqueTy => relate_args_with_variances(
268 relation,
269 a.def_id,
270 relation.cx().variances_of(a.def_id),
271 a.args,
272 b.args,
273 false, )?,
275 ty::AliasTermKind::ProjectionTy
276 | ty::AliasTermKind::FreeConst
277 | ty::AliasTermKind::FreeTy
278 | ty::AliasTermKind::InherentTy
279 | ty::AliasTermKind::InherentConst
280 | ty::AliasTermKind::UnevaluatedConst
281 | ty::AliasTermKind::ProjectionConst => {
282 relate_args_invariantly(relation, a.args, b.args)?
283 }
284 };
285 Ok(ty::AliasTerm::new_from_args(relation.cx(), a.def_id, args))
286 }
287 }
288}
289
290impl<I: Interner> Relate<I> for ty::ExistentialProjection<I> {
291 fn relate<R: TypeRelation<I>>(
292 relation: &mut R,
293 a: ty::ExistentialProjection<I>,
294 b: ty::ExistentialProjection<I>,
295 ) -> RelateResult<I, ty::ExistentialProjection<I>> {
296 if a.def_id != b.def_id {
297 Err(TypeError::ProjectionMismatched({
298 let a = a.def_id;
299 let b = b.def_id;
300 ExpectedFound::new(a, b)
301 }))
302 } else {
303 let term = relation.relate_with_variance(
304 ty::Invariant,
305 VarianceDiagInfo::default(),
306 a.term,
307 b.term,
308 )?;
309 let args = relation.relate_with_variance(
310 ty::Invariant,
311 VarianceDiagInfo::default(),
312 a.args,
313 b.args,
314 )?;
315 Ok(ty::ExistentialProjection::new_from_args(relation.cx(), a.def_id, args, term))
316 }
317 }
318}
319
320impl<I: Interner> Relate<I> for ty::TraitRef<I> {
321 fn relate<R: TypeRelation<I>>(
322 relation: &mut R,
323 a: ty::TraitRef<I>,
324 b: ty::TraitRef<I>,
325 ) -> RelateResult<I, ty::TraitRef<I>> {
326 if a.def_id != b.def_id {
328 Err(TypeError::Traits({
329 let a = a.def_id;
330 let b = b.def_id;
331 ExpectedFound::new(a, b)
332 }))
333 } else {
334 let args = relate_args_invariantly(relation, a.args, b.args)?;
335 Ok(ty::TraitRef::new_from_args(relation.cx(), a.def_id, args))
336 }
337 }
338}
339
340impl<I: Interner> Relate<I> for ty::ExistentialTraitRef<I> {
341 fn relate<R: TypeRelation<I>>(
342 relation: &mut R,
343 a: ty::ExistentialTraitRef<I>,
344 b: ty::ExistentialTraitRef<I>,
345 ) -> RelateResult<I, ty::ExistentialTraitRef<I>> {
346 if a.def_id != b.def_id {
348 Err(TypeError::Traits({
349 let a = a.def_id;
350 let b = b.def_id;
351 ExpectedFound::new(a, b)
352 }))
353 } else {
354 let args = relate_args_invariantly(relation, a.args, b.args)?;
355 Ok(ty::ExistentialTraitRef::new_from_args(relation.cx(), a.def_id, args))
356 }
357 }
358}
359
360#[instrument(level = "trace", skip(relation), ret)]
364pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
365 relation: &mut R,
366 a: I::Ty,
367 b: I::Ty,
368) -> RelateResult<I, I::Ty> {
369 let cx = relation.cx();
370 match (a.kind(), b.kind()) {
371 (ty::Infer(_), _) | (_, ty::Infer(_)) => {
372 panic!("var types encountered in structurally_relate_tys")
374 }
375
376 (ty::Bound(..), _) | (_, ty::Bound(..)) => {
377 panic!("bound types encountered in structurally_relate_tys")
378 }
379
380 (ty::Error(guar), _) | (_, ty::Error(guar)) => Ok(Ty::new_error(cx, guar)),
381
382 (ty::Never, _)
383 | (ty::Char, _)
384 | (ty::Bool, _)
385 | (ty::Int(_), _)
386 | (ty::Uint(_), _)
387 | (ty::Float(_), _)
388 | (ty::Str, _)
389 if a == b =>
390 {
391 Ok(a)
392 }
393
394 (ty::Param(a_p), ty::Param(b_p)) if a_p.index() == b_p.index() => {
395 Ok(a)
398 }
399
400 (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a),
401
402 (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => {
403 let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?;
404 Ok(Ty::new_adt(cx, a_def, args))
405 }
406
407 (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(cx, a_id)),
408
409 (ty::Dynamic(a_obj, a_region, a_repr), ty::Dynamic(b_obj, b_region, b_repr))
410 if a_repr == b_repr =>
411 {
412 Ok(Ty::new_dynamic(
413 cx,
414 relation.relate(a_obj, b_obj)?,
415 relation.relate(a_region, b_region)?,
416 a_repr,
417 ))
418 }
419
420 (ty::Coroutine(a_id, a_args), ty::Coroutine(b_id, b_args)) if a_id == b_id => {
421 let args = relate_args_invariantly(relation, a_args, b_args)?;
425 Ok(Ty::new_coroutine(cx, a_id, args))
426 }
427
428 (ty::CoroutineWitness(a_id, a_args), ty::CoroutineWitness(b_id, b_args))
429 if a_id == b_id =>
430 {
431 let args = relate_args_invariantly(relation, a_args, b_args)?;
435 Ok(Ty::new_coroutine_witness(cx, a_id, args))
436 }
437
438 (ty::Closure(a_id, a_args), ty::Closure(b_id, b_args)) if a_id == b_id => {
439 let args = relate_args_invariantly(relation, a_args, b_args)?;
443 Ok(Ty::new_closure(cx, a_id, args))
444 }
445
446 (ty::CoroutineClosure(a_id, a_args), ty::CoroutineClosure(b_id, b_args))
447 if a_id == b_id =>
448 {
449 let args = relate_args_invariantly(relation, a_args, b_args)?;
450 Ok(Ty::new_coroutine_closure(cx, a_id, args))
451 }
452
453 (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => {
454 if a_mutbl != b_mutbl {
455 return Err(TypeError::Mutability);
456 }
457
458 let (variance, info) = match a_mutbl {
459 Mutability::Not => (ty::Covariant, VarianceDiagInfo::None),
460 Mutability::Mut => {
461 (ty::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
462 }
463 };
464
465 let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
466
467 Ok(Ty::new_ptr(cx, ty, a_mutbl))
468 }
469
470 (ty::Ref(a_r, a_ty, a_mutbl), ty::Ref(b_r, b_ty, b_mutbl)) => {
471 if a_mutbl != b_mutbl {
472 return Err(TypeError::Mutability);
473 }
474
475 let (variance, info) = match a_mutbl {
476 Mutability::Not => (ty::Covariant, VarianceDiagInfo::None),
477 Mutability::Mut => {
478 (ty::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
479 }
480 };
481
482 let r = relation.relate(a_r, b_r)?;
483 let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
484
485 Ok(Ty::new_ref(cx, r, ty, a_mutbl))
486 }
487
488 (ty::Array(a_t, sz_a), ty::Array(b_t, sz_b)) => {
489 let t = relation.relate(a_t, b_t)?;
490 match relation.relate(sz_a, sz_b) {
491 Ok(sz) => Ok(Ty::new_array_with_const_len(cx, t, sz)),
492 Err(TypeError::ConstMismatch(_)) => {
493 Err(TypeError::ArraySize(ExpectedFound::new(sz_a, sz_b)))
494 }
495 Err(e) => Err(e),
496 }
497 }
498
499 (ty::Slice(a_t), ty::Slice(b_t)) => {
500 let t = relation.relate(a_t, b_t)?;
501 Ok(Ty::new_slice(cx, t))
502 }
503
504 (ty::Tuple(as_), ty::Tuple(bs)) => {
505 if as_.len() == bs.len() {
506 Ok(Ty::new_tup_from_iter(
507 cx,
508 iter::zip(as_.iter(), bs.iter()).map(|(a, b)| relation.relate(a, b)),
509 )?)
510 } else if !(as_.is_empty() || bs.is_empty()) {
511 Err(TypeError::TupleSize(ExpectedFound::new(as_.len(), bs.len())))
512 } else {
513 Err(TypeError::Sorts(ExpectedFound::new(a, b)))
514 }
515 }
516
517 (ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => {
518 let args = relation.relate_item_args(a_def_id, a_args, b_args)?;
519 Ok(Ty::new_fn_def(cx, a_def_id, args))
520 }
521
522 (ty::FnPtr(a_sig_tys, a_hdr), ty::FnPtr(b_sig_tys, b_hdr)) => {
523 let fty = relation.relate(a_sig_tys.with(a_hdr), b_sig_tys.with(b_hdr))?;
524 Ok(Ty::new_fn_ptr(cx, fty))
525 }
526
527 (ty::Alias(a_kind, a_data), ty::Alias(b_kind, b_data)) => {
529 let alias_ty = relation.relate(a_data, b_data)?;
530 assert_eq!(a_kind, b_kind);
531 Ok(Ty::new_alias(cx, a_kind, alias_ty))
532 }
533
534 (ty::Pat(a_ty, a_pat), ty::Pat(b_ty, b_pat)) => {
535 let ty = relation.relate(a_ty, b_ty)?;
536 let pat = relation.relate(a_pat, b_pat)?;
537 Ok(Ty::new_pat(cx, ty, pat))
538 }
539
540 (ty::UnsafeBinder(a_binder), ty::UnsafeBinder(b_binder)) => {
541 Ok(Ty::new_unsafe_binder(cx, relation.binders(*a_binder, *b_binder)?))
542 }
543
544 _ => Err(TypeError::Sorts(ExpectedFound::new(a, b))),
545 }
546}
547
548pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>(
555 relation: &mut R,
556 mut a: I::Const,
557 mut b: I::Const,
558) -> RelateResult<I, I::Const> {
559 trace!(
560 "structurally_relate_consts::<{}>(a = {:?}, b = {:?})",
561 std::any::type_name::<R>(),
562 a,
563 b
564 );
565 let cx = relation.cx();
566
567 if cx.features().generic_const_exprs() {
568 a = cx.expand_abstract_consts(a);
569 b = cx.expand_abstract_consts(b);
570 }
571
572 trace!(
573 "structurally_relate_consts::<{}>(normed_a = {:?}, normed_b = {:?})",
574 std::any::type_name::<R>(),
575 a,
576 b
577 );
578
579 let is_match = match (a.kind(), b.kind()) {
583 (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
584 panic!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b)
586 }
587
588 (ty::ConstKind::Error(_), _) => return Ok(a),
589 (_, ty::ConstKind::Error(_)) => return Ok(b),
590
591 (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index() == b_p.index() => {
592 true
595 }
596 (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
597 (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
598 a_val.valtree() == b_val.valtree()
599 }
600
601 (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => {
605 if cfg!(debug_assertions) {
606 let a_ty = cx.type_of(au.def).instantiate(cx, au.args);
607 let b_ty = cx.type_of(bu.def).instantiate(cx, bu.args);
608 assert_eq!(a_ty, b_ty);
609 }
610
611 let args = relation.relate_with_variance(
612 ty::Invariant,
613 VarianceDiagInfo::default(),
614 au.args,
615 bu.args,
616 )?;
617 return Ok(Const::new_unevaluated(cx, ty::UnevaluatedConst { def: au.def, args }));
618 }
619 (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => {
620 let expr = relation.relate(ae, be)?;
621 return Ok(Const::new_expr(cx, expr));
622 }
623 _ => false,
624 };
625 if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(ExpectedFound::new(a, b))) }
626}
627
628impl<I: Interner, T: Relate<I>> Relate<I> for ty::Binder<I, T> {
629 fn relate<R: TypeRelation<I>>(
630 relation: &mut R,
631 a: ty::Binder<I, T>,
632 b: ty::Binder<I, T>,
633 ) -> RelateResult<I, ty::Binder<I, T>> {
634 relation.binders(a, b)
635 }
636}
637
638impl<I: Interner> Relate<I> for ty::TraitPredicate<I> {
639 fn relate<R: TypeRelation<I>>(
640 relation: &mut R,
641 a: ty::TraitPredicate<I>,
642 b: ty::TraitPredicate<I>,
643 ) -> RelateResult<I, ty::TraitPredicate<I>> {
644 let trait_ref = relation.relate(a.trait_ref, b.trait_ref)?;
645 if a.polarity != b.polarity {
646 return Err(TypeError::PolarityMismatch(ExpectedFound::new(a.polarity, b.polarity)));
647 }
648 Ok(ty::TraitPredicate { trait_ref, polarity: a.polarity })
649 }
650}