1use std::fmt::Debug;
2use std::hash::Hash;
3use std::iter;
4use std::marker::PhantomData;
5
6use rustc_ast_ir::Mutability;
7#[cfg(feature = "nightly")]
8use rustc_data_structures::fingerprint::Fingerprint;
9#[cfg(feature = "nightly")]
10use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
11#[cfg(feature = "nightly")]
12use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
13
14use crate::inherent::*;
15use crate::visit::TypeVisitableExt as _;
16use crate::{self as ty, Interner};
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
20#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
21pub enum SimplifiedType<DefId> {
22 Bool,
23 Char,
24 Int(ty::IntTy),
25 Uint(ty::UintTy),
26 Float(ty::FloatTy),
27 Adt(DefId),
28 Foreign(DefId),
29 Str,
30 Array,
31 Slice,
32 Ref(Mutability),
33 Ptr(Mutability),
34 Never,
35 Tuple(usize),
36 MarkerTraitObject,
39 Trait(DefId),
40 Closure(DefId),
41 Coroutine(DefId),
42 CoroutineWitness(DefId),
43 Function(usize),
44 UnsafeBinder,
45 Placeholder,
46 Error,
47}
48
49#[cfg(feature = "nightly")]
50impl<HCX: Clone, DefId: HashStable<HCX>> ToStableHashKey<HCX> for SimplifiedType<DefId> {
51 type KeyType = Fingerprint;
52
53 #[inline]
54 fn to_stable_hash_key(&self, hcx: &HCX) -> Fingerprint {
55 let mut hasher = StableHasher::new();
56 let mut hcx: HCX = hcx.clone();
57 self.hash_stable(&mut hcx, &mut hasher);
58 hasher.finish()
59 }
60}
61
62#[derive(PartialEq, Eq, Debug, Clone, Copy)]
75pub enum TreatParams {
76 InstantiateWithInfer,
79 AsRigid,
85}
86
87pub fn simplify_type<I: Interner>(
109 cx: I,
110 ty: I::Ty,
111 treat_params: TreatParams,
112) -> Option<SimplifiedType<I::DefId>> {
113 match ty.kind() {
114 ty::Bool => Some(SimplifiedType::Bool),
115 ty::Char => Some(SimplifiedType::Char),
116 ty::Int(int_type) => Some(SimplifiedType::Int(int_type)),
117 ty::Uint(uint_type) => Some(SimplifiedType::Uint(uint_type)),
118 ty::Float(float_type) => Some(SimplifiedType::Float(float_type)),
119 ty::Adt(def, _) => Some(SimplifiedType::Adt(def.def_id())),
120 ty::Str => Some(SimplifiedType::Str),
121 ty::Array(..) => Some(SimplifiedType::Array),
122 ty::Slice(..) => Some(SimplifiedType::Slice),
123 ty::Pat(ty, ..) => simplify_type(cx, ty, treat_params),
124 ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)),
125 ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() {
126 Some(principal_def_id) if !cx.trait_is_auto(principal_def_id) => {
127 Some(SimplifiedType::Trait(principal_def_id))
128 }
129 _ => Some(SimplifiedType::MarkerTraitObject),
130 },
131 ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)),
132 ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => {
133 Some(SimplifiedType::Closure(def_id))
134 }
135 ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)),
136 ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)),
137 ty::Never => Some(SimplifiedType::Never),
138 ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())),
139 ty::FnPtr(sig_tys, _hdr) => {
140 Some(SimplifiedType::Function(sig_tys.skip_binder().inputs().len()))
141 }
142 ty::UnsafeBinder(_) => Some(SimplifiedType::UnsafeBinder),
143 ty::Placeholder(..) => Some(SimplifiedType::Placeholder),
144 ty::Param(_) => match treat_params {
145 TreatParams::AsRigid => Some(SimplifiedType::Placeholder),
146 TreatParams::InstantiateWithInfer => None,
147 },
148 ty::Alias(..) => match treat_params {
149 TreatParams::AsRigid if !ty.has_non_region_infer() => Some(SimplifiedType::Placeholder),
154 TreatParams::AsRigid | TreatParams::InstantiateWithInfer => None,
155 },
156 ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)),
157 ty::Error(_) => Some(SimplifiedType::Error),
158 ty::Bound(..) | ty::Infer(_) => None,
159 }
160}
161
162impl<DefId> SimplifiedType<DefId> {
163 pub fn def(self) -> Option<DefId> {
164 match self {
165 SimplifiedType::Adt(d)
166 | SimplifiedType::Foreign(d)
167 | SimplifiedType::Trait(d)
168 | SimplifiedType::Closure(d)
169 | SimplifiedType::Coroutine(d)
170 | SimplifiedType::CoroutineWitness(d) => Some(d),
171 _ => None,
172 }
173 }
174}
175
176#[derive(Debug, Clone, Copy)]
187pub struct DeepRejectCtxt<
188 I: Interner,
189 const INSTANTIATE_LHS_WITH_INFER: bool,
190 const INSTANTIATE_RHS_WITH_INFER: bool,
191> {
192 _interner: PhantomData<I>,
193}
194
195impl<I: Interner> DeepRejectCtxt<I, false, false> {
196 pub fn relate_rigid_rigid(_interner: I) -> DeepRejectCtxt<I, false, false> {
198 DeepRejectCtxt { _interner: PhantomData }
199 }
200}
201
202impl<I: Interner> DeepRejectCtxt<I, true, true> {
203 pub fn relate_infer_infer(_interner: I) -> DeepRejectCtxt<I, true, true> {
205 DeepRejectCtxt { _interner: PhantomData }
206 }
207}
208
209impl<I: Interner> DeepRejectCtxt<I, false, true> {
210 pub fn relate_rigid_infer(_interner: I) -> DeepRejectCtxt<I, false, true> {
212 DeepRejectCtxt { _interner: PhantomData }
213 }
214}
215
216impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_WITH_INFER: bool>
217 DeepRejectCtxt<I, INSTANTIATE_LHS_WITH_INFER, INSTANTIATE_RHS_WITH_INFER>
218{
219 const STARTING_DEPTH: usize = 8;
222
223 pub fn args_may_unify(
224 self,
225 obligation_args: I::GenericArgs,
226 impl_args: I::GenericArgs,
227 ) -> bool {
228 self.args_may_unify_inner(obligation_args, impl_args, Self::STARTING_DEPTH)
229 }
230
231 pub fn types_may_unify(self, lhs: I::Ty, rhs: I::Ty) -> bool {
232 self.types_may_unify_inner(lhs, rhs, Self::STARTING_DEPTH)
233 }
234
235 fn args_may_unify_inner(
236 self,
237 obligation_args: I::GenericArgs,
238 impl_args: I::GenericArgs,
239 depth: usize,
240 ) -> bool {
241 iter::zip(obligation_args.iter(), impl_args.iter()).all(|(obl, imp)| {
245 match (obl.kind(), imp.kind()) {
246 (ty::GenericArgKind::Lifetime(_), ty::GenericArgKind::Lifetime(_)) => true,
248 (ty::GenericArgKind::Type(obl), ty::GenericArgKind::Type(imp)) => {
249 self.types_may_unify_inner(obl, imp, depth)
250 }
251 (ty::GenericArgKind::Const(obl), ty::GenericArgKind::Const(imp)) => {
252 self.consts_may_unify_inner(obl, imp)
253 }
254 _ => panic!("kind mismatch: {obl:?} {imp:?}"),
255 }
256 })
257 }
258
259 fn types_may_unify_inner(self, lhs: I::Ty, rhs: I::Ty, depth: usize) -> bool {
260 match rhs.kind() {
261 ty::Param(_) => {
264 if INSTANTIATE_RHS_WITH_INFER {
265 return true;
266 }
267 }
268 ty::Error(_) | ty::Alias(..) | ty::Bound(..) => return true,
269 ty::Infer(var) => return self.var_and_ty_may_unify(var, lhs),
270
271 ty::Bool
274 | ty::Char
275 | ty::Int(_)
276 | ty::Uint(_)
277 | ty::Float(_)
278 | ty::Adt(..)
279 | ty::Str
280 | ty::Array(..)
281 | ty::Slice(..)
282 | ty::RawPtr(..)
283 | ty::Dynamic(..)
284 | ty::Pat(..)
285 | ty::Ref(..)
286 | ty::Never
287 | ty::Tuple(..)
288 | ty::FnDef(..)
289 | ty::FnPtr(..)
290 | ty::Closure(..)
291 | ty::CoroutineClosure(..)
292 | ty::Coroutine(..)
293 | ty::CoroutineWitness(..)
294 | ty::Foreign(_)
295 | ty::Placeholder(_)
296 | ty::UnsafeBinder(_) => {}
297 };
298
299 let Some(depth) = depth.checked_sub(1) else {
309 return true;
310 };
311
312 match lhs.kind() {
314 ty::Ref(_, lhs_ty, lhs_mutbl) => match rhs.kind() {
315 ty::Ref(_, rhs_ty, rhs_mutbl) => {
316 lhs_mutbl == rhs_mutbl && self.types_may_unify_inner(lhs_ty, rhs_ty, depth)
317 }
318 _ => false,
319 },
320
321 ty::Adt(lhs_def, lhs_args) => match rhs.kind() {
322 ty::Adt(rhs_def, rhs_args) => {
323 lhs_def == rhs_def && self.args_may_unify_inner(lhs_args, rhs_args, depth)
324 }
325 _ => false,
326 },
327
328 ty::Param(lhs) => {
331 INSTANTIATE_LHS_WITH_INFER
332 || match rhs.kind() {
333 ty::Param(rhs) => lhs == rhs,
334 _ => false,
335 }
336 }
337
338 ty::Placeholder(lhs) => {
340 matches!(rhs.kind(), ty::Placeholder(rhs) if lhs == rhs)
341 }
342
343 ty::Infer(var) => self.var_and_ty_may_unify(var, rhs),
344
345 ty::Alias(..) => true,
351
352 ty::Int(_)
353 | ty::Uint(_)
354 | ty::Float(_)
355 | ty::Str
356 | ty::Bool
357 | ty::Char
358 | ty::Never
359 | ty::Foreign(_) => lhs == rhs,
360
361 ty::Tuple(lhs) => match rhs.kind() {
362 ty::Tuple(rhs) => {
363 lhs.len() == rhs.len()
364 && iter::zip(lhs.iter(), rhs.iter())
365 .all(|(lhs, rhs)| self.types_may_unify_inner(lhs, rhs, depth))
366 }
367 _ => false,
368 },
369
370 ty::Array(lhs_ty, lhs_len) => match rhs.kind() {
371 ty::Array(rhs_ty, rhs_len) => {
372 self.types_may_unify_inner(lhs_ty, rhs_ty, depth)
373 && self.consts_may_unify_inner(lhs_len, rhs_len)
374 }
375 _ => false,
376 },
377
378 ty::RawPtr(lhs_ty, lhs_mutbl) => match rhs.kind() {
379 ty::RawPtr(rhs_ty, rhs_mutbl) => {
380 lhs_mutbl == rhs_mutbl && self.types_may_unify_inner(lhs_ty, rhs_ty, depth)
381 }
382 _ => false,
383 },
384
385 ty::Slice(lhs_ty) => {
386 matches!(rhs.kind(), ty::Slice(rhs_ty) if self.types_may_unify_inner(lhs_ty, rhs_ty, depth))
387 }
388
389 ty::Dynamic(lhs_preds, ..) => {
390 matches!(rhs.kind(), ty::Dynamic(rhs_preds, ..) if
394 lhs_preds.principal_def_id() == rhs_preds.principal_def_id()
395 )
396 }
397
398 ty::FnPtr(lhs_sig_tys, lhs_hdr) => match rhs.kind() {
399 ty::FnPtr(rhs_sig_tys, rhs_hdr) => {
400 let lhs_sig_tys = lhs_sig_tys.skip_binder().inputs_and_output;
401 let rhs_sig_tys = rhs_sig_tys.skip_binder().inputs_and_output;
402
403 lhs_hdr == rhs_hdr
404 && lhs_sig_tys.len() == rhs_sig_tys.len()
405 && iter::zip(lhs_sig_tys.iter(), rhs_sig_tys.iter())
406 .all(|(lhs, rhs)| self.types_may_unify_inner(lhs, rhs, depth))
407 }
408 _ => false,
409 },
410
411 ty::Bound(..) => true,
412
413 ty::FnDef(lhs_def_id, lhs_args) => match rhs.kind() {
414 ty::FnDef(rhs_def_id, rhs_args) => {
415 lhs_def_id == rhs_def_id && self.args_may_unify_inner(lhs_args, rhs_args, depth)
416 }
417 _ => false,
418 },
419
420 ty::Closure(lhs_def_id, lhs_args) => match rhs.kind() {
421 ty::Closure(rhs_def_id, rhs_args) => {
422 lhs_def_id == rhs_def_id && self.args_may_unify_inner(lhs_args, rhs_args, depth)
423 }
424 _ => false,
425 },
426
427 ty::CoroutineClosure(lhs_def_id, lhs_args) => match rhs.kind() {
428 ty::CoroutineClosure(rhs_def_id, rhs_args) => {
429 lhs_def_id == rhs_def_id && self.args_may_unify_inner(lhs_args, rhs_args, depth)
430 }
431 _ => false,
432 },
433
434 ty::Coroutine(lhs_def_id, lhs_args) => match rhs.kind() {
435 ty::Coroutine(rhs_def_id, rhs_args) => {
436 lhs_def_id == rhs_def_id && self.args_may_unify_inner(lhs_args, rhs_args, depth)
437 }
438 _ => false,
439 },
440
441 ty::CoroutineWitness(lhs_def_id, lhs_args) => match rhs.kind() {
442 ty::CoroutineWitness(rhs_def_id, rhs_args) => {
443 lhs_def_id == rhs_def_id && self.args_may_unify_inner(lhs_args, rhs_args, depth)
444 }
445 _ => false,
446 },
447
448 ty::Pat(lhs_ty, _) => {
449 matches!(rhs.kind(), ty::Pat(rhs_ty, _) if self.types_may_unify_inner(lhs_ty, rhs_ty, depth))
451 }
452
453 ty::UnsafeBinder(lhs_ty) => match rhs.kind() {
454 ty::UnsafeBinder(rhs_ty) => {
455 self.types_may_unify(lhs_ty.skip_binder(), rhs_ty.skip_binder())
456 }
457 _ => false,
458 },
459
460 ty::Error(..) => true,
461 }
462 }
463
464 fn consts_may_unify_inner(self, lhs: I::Const, rhs: I::Const) -> bool {
467 match rhs.kind() {
468 ty::ConstKind::Param(_) => {
469 if INSTANTIATE_RHS_WITH_INFER {
470 return true;
471 }
472 }
473
474 ty::ConstKind::Expr(_)
475 | ty::ConstKind::Unevaluated(_)
476 | ty::ConstKind::Error(_)
477 | ty::ConstKind::Infer(_)
478 | ty::ConstKind::Bound(..) => {
479 return true;
480 }
481
482 ty::ConstKind::Value(..) | ty::ConstKind::Placeholder(_) => {}
483 };
484
485 match lhs.kind() {
486 ty::ConstKind::Value(lhs_val) => match rhs.kind() {
487 ty::ConstKind::Value(rhs_val) => lhs_val.valtree() == rhs_val.valtree(),
488 _ => false,
489 },
490
491 ty::ConstKind::Param(lhs) => {
492 INSTANTIATE_LHS_WITH_INFER
493 || match rhs.kind() {
494 ty::ConstKind::Param(rhs) => lhs == rhs,
495 _ => false,
496 }
497 }
498
499 ty::ConstKind::Placeholder(lhs) => {
501 matches!(rhs.kind(), ty::ConstKind::Placeholder(rhs) if lhs == rhs)
502 }
503
504 ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => {
507 true
508 }
509
510 ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) => true,
511 }
512 }
513
514 fn var_and_ty_may_unify(self, var: ty::InferTy, ty: I::Ty) -> bool {
515 if !ty.is_known_rigid() {
516 return true;
517 }
518
519 match var {
520 ty::IntVar(_) => ty.is_integral(),
521 ty::FloatVar(_) => ty.is_floating_point(),
522 _ => true,
523 }
524 }
525}