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