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::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
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(
21 feature = "nightly",
22 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
23)]
24pub enum SimplifiedType<DefId> {
25 Bool,
26 Char,
27 Int(ty::IntTy),
28 Uint(ty::UintTy),
29 Float(ty::FloatTy),
30 Adt(DefId),
31 Foreign(DefId),
32 Str,
33 Array,
34 Slice,
35 Ref(Mutability),
36 Ptr(Mutability),
37 Never,
38 Tuple(usize),
39 MarkerTraitObject,
42 Trait(DefId),
43 Closure(DefId),
44 Coroutine(DefId),
45 CoroutineWitness(DefId),
46 Function(usize),
47 UnsafeBinder,
48 Placeholder,
49 Error,
50}
51
52#[cfg(feature = "nightly")]
53impl<HCX: Clone, DefId: HashStable<HCX>> ToStableHashKey<HCX> for SimplifiedType<DefId> {
54 type KeyType = Fingerprint;
55
56 #[inline]
57 fn to_stable_hash_key(&self, hcx: &HCX) -> Fingerprint {
58 let mut hasher = StableHasher::new();
59 let mut hcx: HCX = hcx.clone();
60 self.hash_stable(&mut hcx, &mut hasher);
61 hasher.finish()
62 }
63}
64
65#[derive(PartialEq, Eq, Debug, Clone, Copy)]
78pub enum TreatParams {
79 InstantiateWithInfer,
82 AsRigid,
91}
92
93pub fn simplify_type<I: Interner>(
115 cx: I,
116 ty: I::Ty,
117 treat_params: TreatParams,
118) -> Option<SimplifiedType<I::DefId>> {
119 match ty.kind() {
120 ty::Bool => Some(SimplifiedType::Bool),
121 ty::Char => Some(SimplifiedType::Char),
122 ty::Int(int_type) => Some(SimplifiedType::Int(int_type)),
123 ty::Uint(uint_type) => Some(SimplifiedType::Uint(uint_type)),
124 ty::Float(float_type) => Some(SimplifiedType::Float(float_type)),
125 ty::Adt(def, _) => Some(SimplifiedType::Adt(def.def_id())),
126 ty::Str => Some(SimplifiedType::Str),
127 ty::Array(..) => Some(SimplifiedType::Array),
128 ty::Slice(..) => Some(SimplifiedType::Slice),
129 ty::Pat(ty, ..) => simplify_type(cx, ty, treat_params),
130 ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)),
131 ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() {
132 Some(principal_def_id) if !cx.trait_is_auto(principal_def_id) => {
133 Some(SimplifiedType::Trait(principal_def_id))
134 }
135 _ => Some(SimplifiedType::MarkerTraitObject),
136 },
137 ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)),
138 ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => {
139 Some(SimplifiedType::Closure(def_id))
140 }
141 ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)),
142 ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)),
143 ty::Never => Some(SimplifiedType::Never),
144 ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())),
145 ty::FnPtr(sig_tys, _hdr) => {
146 Some(SimplifiedType::Function(sig_tys.skip_binder().inputs().len()))
147 }
148 ty::UnsafeBinder(_) => Some(SimplifiedType::UnsafeBinder),
149 ty::Placeholder(..) => Some(SimplifiedType::Placeholder),
150 ty::Param(_) => match treat_params {
151 TreatParams::AsRigid => Some(SimplifiedType::Placeholder),
152 TreatParams::InstantiateWithInfer => None,
153 },
154 ty::Alias(..) => match treat_params {
155 TreatParams::AsRigid
158 if !ty.has_non_region_infer() || cx.next_trait_solver_globally() =>
159 {
160 Some(SimplifiedType::Placeholder)
161 }
162 TreatParams::AsRigid | TreatParams::InstantiateWithInfer => None,
163 },
164 ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)),
165 ty::Error(_) => Some(SimplifiedType::Error),
166 ty::Bound(..) | ty::Infer(_) => None,
167 }
168}
169
170impl<DefId> SimplifiedType<DefId> {
171 pub fn def(self) -> Option<DefId> {
172 match self {
173 SimplifiedType::Adt(d)
174 | SimplifiedType::Foreign(d)
175 | SimplifiedType::Trait(d)
176 | SimplifiedType::Closure(d)
177 | SimplifiedType::Coroutine(d)
178 | SimplifiedType::CoroutineWitness(d) => Some(d),
179 _ => None,
180 }
181 }
182}
183
184#[derive(Debug, Clone, Copy)]
195pub struct DeepRejectCtxt<
196 I: Interner,
197 const INSTANTIATE_LHS_WITH_INFER: bool,
198 const INSTANTIATE_RHS_WITH_INFER: bool,
199> {
200 _interner: PhantomData<I>,
201}
202
203impl<I: Interner> DeepRejectCtxt<I, false, false> {
204 pub fn relate_rigid_rigid(_interner: I) -> DeepRejectCtxt<I, false, false> {
206 DeepRejectCtxt { _interner: PhantomData }
207 }
208}
209
210impl<I: Interner> DeepRejectCtxt<I, true, true> {
211 pub fn relate_infer_infer(_interner: I) -> DeepRejectCtxt<I, true, true> {
213 DeepRejectCtxt { _interner: PhantomData }
214 }
215}
216
217impl<I: Interner> DeepRejectCtxt<I, false, true> {
218 pub fn relate_rigid_infer(_interner: I) -> DeepRejectCtxt<I, false, true> {
220 DeepRejectCtxt { _interner: PhantomData }
221 }
222}
223
224impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_WITH_INFER: bool>
225 DeepRejectCtxt<I, INSTANTIATE_LHS_WITH_INFER, INSTANTIATE_RHS_WITH_INFER>
226{
227 const STARTING_DEPTH: usize = 8;
230
231 pub fn args_may_unify(
232 self,
233 obligation_args: I::GenericArgs,
234 impl_args: I::GenericArgs,
235 ) -> bool {
236 self.args_may_unify_inner(obligation_args, impl_args, Self::STARTING_DEPTH)
237 }
238
239 pub fn types_may_unify(self, lhs: I::Ty, rhs: I::Ty) -> bool {
240 self.types_may_unify_inner(lhs, rhs, Self::STARTING_DEPTH)
241 }
242
243 pub fn types_may_unify_with_depth(self, lhs: I::Ty, rhs: I::Ty, depth_limit: usize) -> bool {
244 self.types_may_unify_inner(lhs, rhs, depth_limit)
245 }
246
247 fn args_may_unify_inner(
248 self,
249 obligation_args: I::GenericArgs,
250 impl_args: I::GenericArgs,
251 depth: usize,
252 ) -> bool {
253 iter::zip(obligation_args.iter(), impl_args.iter()).all(|(obl, imp)| {
257 match (obl.kind(), imp.kind()) {
258 (ty::GenericArgKind::Lifetime(_), ty::GenericArgKind::Lifetime(_)) => true,
260 (ty::GenericArgKind::Type(obl), ty::GenericArgKind::Type(imp)) => {
261 self.types_may_unify_inner(obl, imp, depth)
262 }
263 (ty::GenericArgKind::Const(obl), ty::GenericArgKind::Const(imp)) => {
264 self.consts_may_unify_inner(obl, imp)
265 }
266 _ => panic!("kind mismatch: {obl:?} {imp:?}"),
267 }
268 })
269 }
270
271 fn types_may_unify_inner(self, lhs: I::Ty, rhs: I::Ty, depth: usize) -> bool {
272 if lhs == rhs {
273 return true;
274 }
275
276 match rhs.kind() {
277 ty::Param(_) => {
280 if INSTANTIATE_RHS_WITH_INFER {
281 return true;
282 }
283 }
284 ty::Error(_) | ty::Alias(..) | ty::Bound(..) => return true,
285 ty::Infer(var) => return self.var_and_ty_may_unify(var, lhs),
286
287 ty::Bool
290 | ty::Char
291 | ty::Int(_)
292 | ty::Uint(_)
293 | ty::Float(_)
294 | ty::Adt(..)
295 | ty::Str
296 | ty::Array(..)
297 | ty::Slice(..)
298 | ty::RawPtr(..)
299 | ty::Dynamic(..)
300 | ty::Pat(..)
301 | ty::Ref(..)
302 | ty::Never
303 | ty::Tuple(..)
304 | ty::FnDef(..)
305 | ty::FnPtr(..)
306 | ty::Closure(..)
307 | ty::CoroutineClosure(..)
308 | ty::Coroutine(..)
309 | ty::CoroutineWitness(..)
310 | ty::Foreign(_)
311 | ty::Placeholder(_)
312 | ty::UnsafeBinder(_) => {}
313 };
314
315 let Some(depth) = depth.checked_sub(1) else {
325 return true;
326 };
327
328 match lhs.kind() {
330 ty::Ref(_, lhs_ty, lhs_mutbl) => match rhs.kind() {
331 ty::Ref(_, rhs_ty, rhs_mutbl) => {
332 lhs_mutbl == rhs_mutbl && self.types_may_unify_inner(lhs_ty, rhs_ty, depth)
333 }
334 _ => false,
335 },
336
337 ty::Adt(lhs_def, lhs_args) => match rhs.kind() {
338 ty::Adt(rhs_def, rhs_args) => {
339 lhs_def == rhs_def && self.args_may_unify_inner(lhs_args, rhs_args, depth)
340 }
341 _ => false,
342 },
343
344 ty::Param(lhs) => {
347 INSTANTIATE_LHS_WITH_INFER
348 || match rhs.kind() {
349 ty::Param(rhs) => lhs == rhs,
350 _ => false,
351 }
352 }
353
354 ty::Placeholder(lhs) => {
356 matches!(rhs.kind(), ty::Placeholder(rhs) if lhs == rhs)
357 }
358
359 ty::Infer(var) => self.var_and_ty_may_unify(var, rhs),
360
361 ty::Alias(..) => true,
367
368 ty::Int(_)
369 | ty::Uint(_)
370 | ty::Float(_)
371 | ty::Str
372 | ty::Bool
373 | ty::Char
374 | ty::Never
375 | ty::Foreign(_) => lhs == rhs,
376
377 ty::Tuple(lhs) => match rhs.kind() {
378 ty::Tuple(rhs) => {
379 lhs.len() == rhs.len()
380 && iter::zip(lhs.iter(), rhs.iter())
381 .all(|(lhs, rhs)| self.types_may_unify_inner(lhs, rhs, depth))
382 }
383 _ => false,
384 },
385
386 ty::Array(lhs_ty, lhs_len) => match rhs.kind() {
387 ty::Array(rhs_ty, rhs_len) => {
388 self.types_may_unify_inner(lhs_ty, rhs_ty, depth)
389 && self.consts_may_unify_inner(lhs_len, rhs_len)
390 }
391 _ => false,
392 },
393
394 ty::RawPtr(lhs_ty, lhs_mutbl) => match rhs.kind() {
395 ty::RawPtr(rhs_ty, rhs_mutbl) => {
396 lhs_mutbl == rhs_mutbl && self.types_may_unify_inner(lhs_ty, rhs_ty, depth)
397 }
398 _ => false,
399 },
400
401 ty::Slice(lhs_ty) => {
402 matches!(rhs.kind(), ty::Slice(rhs_ty) if self.types_may_unify_inner(lhs_ty, rhs_ty, depth))
403 }
404
405 ty::Dynamic(lhs_preds, ..) => {
406 matches!(rhs.kind(), ty::Dynamic(rhs_preds, ..) if
410 lhs_preds.principal_def_id() == rhs_preds.principal_def_id()
411 )
412 }
413
414 ty::FnPtr(lhs_sig_tys, lhs_hdr) => match rhs.kind() {
415 ty::FnPtr(rhs_sig_tys, rhs_hdr) => {
416 let lhs_sig_tys = lhs_sig_tys.skip_binder().inputs_and_output;
417 let rhs_sig_tys = rhs_sig_tys.skip_binder().inputs_and_output;
418
419 lhs_hdr == rhs_hdr
420 && lhs_sig_tys.len() == rhs_sig_tys.len()
421 && iter::zip(lhs_sig_tys.iter(), rhs_sig_tys.iter())
422 .all(|(lhs, rhs)| self.types_may_unify_inner(lhs, rhs, depth))
423 }
424 _ => false,
425 },
426
427 ty::Bound(..) => true,
428
429 ty::FnDef(lhs_def_id, lhs_args) => match rhs.kind() {
430 ty::FnDef(rhs_def_id, rhs_args) => {
431 lhs_def_id == rhs_def_id && self.args_may_unify_inner(lhs_args, rhs_args, depth)
432 }
433 _ => false,
434 },
435
436 ty::Closure(lhs_def_id, lhs_args) => match rhs.kind() {
437 ty::Closure(rhs_def_id, rhs_args) => {
438 lhs_def_id == rhs_def_id && self.args_may_unify_inner(lhs_args, rhs_args, depth)
439 }
440 _ => false,
441 },
442
443 ty::CoroutineClosure(lhs_def_id, lhs_args) => match rhs.kind() {
444 ty::CoroutineClosure(rhs_def_id, rhs_args) => {
445 lhs_def_id == rhs_def_id && self.args_may_unify_inner(lhs_args, rhs_args, depth)
446 }
447 _ => false,
448 },
449
450 ty::Coroutine(lhs_def_id, lhs_args) => match rhs.kind() {
451 ty::Coroutine(rhs_def_id, rhs_args) => {
452 lhs_def_id == rhs_def_id && self.args_may_unify_inner(lhs_args, rhs_args, depth)
453 }
454 _ => false,
455 },
456
457 ty::CoroutineWitness(lhs_def_id, lhs_args) => match rhs.kind() {
458 ty::CoroutineWitness(rhs_def_id, rhs_args) => {
459 lhs_def_id == rhs_def_id && self.args_may_unify_inner(lhs_args, rhs_args, depth)
460 }
461 _ => false,
462 },
463
464 ty::Pat(lhs_ty, _) => {
465 matches!(rhs.kind(), ty::Pat(rhs_ty, _) if self.types_may_unify_inner(lhs_ty, rhs_ty, depth))
467 }
468
469 ty::UnsafeBinder(lhs_ty) => match rhs.kind() {
470 ty::UnsafeBinder(rhs_ty) => {
471 self.types_may_unify(lhs_ty.skip_binder(), rhs_ty.skip_binder())
472 }
473 _ => false,
474 },
475
476 ty::Error(..) => true,
477 }
478 }
479
480 fn consts_may_unify_inner(self, lhs: I::Const, rhs: I::Const) -> bool {
483 match rhs.kind() {
484 ty::ConstKind::Param(_) => {
485 if INSTANTIATE_RHS_WITH_INFER {
486 return true;
487 }
488 }
489
490 ty::ConstKind::Expr(_)
491 | ty::ConstKind::Unevaluated(_)
492 | ty::ConstKind::Error(_)
493 | ty::ConstKind::Infer(_)
494 | ty::ConstKind::Bound(..) => {
495 return true;
496 }
497
498 ty::ConstKind::Value(..) | ty::ConstKind::Placeholder(_) => {}
499 };
500
501 match lhs.kind() {
502 ty::ConstKind::Value(lhs_val) => match rhs.kind() {
503 ty::ConstKind::Value(rhs_val) => lhs_val.valtree() == rhs_val.valtree(),
504 _ => false,
505 },
506
507 ty::ConstKind::Param(lhs) => {
508 INSTANTIATE_LHS_WITH_INFER
509 || match rhs.kind() {
510 ty::ConstKind::Param(rhs) => lhs == rhs,
511 _ => false,
512 }
513 }
514
515 ty::ConstKind::Placeholder(lhs) => {
517 matches!(rhs.kind(), ty::ConstKind::Placeholder(rhs) if lhs == rhs)
518 }
519
520 ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => {
523 true
524 }
525
526 ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) => true,
527 }
528 }
529
530 fn var_and_ty_may_unify(self, var: ty::InferTy, ty: I::Ty) -> bool {
531 if !ty.is_known_rigid() {
532 return true;
533 }
534
535 match var {
536 ty::IntVar(_) => ty.is_integral(),
537 ty::FloatVar(_) => ty.is_floating_point(),
538 _ => true,
539 }
540 }
541}