1use std::ops::ControlFlow;
4
5use hir_def::{HasModule, ImplId, TraitId, TypeAliasId};
6use rustc_abi::{Float, HasDataLayout, Integer, IntegerType, Primitive, ReprOptions};
7use rustc_hash::FxHashSet;
8use rustc_type_ir::{
9 ConstKind, CoroutineArgs, DebruijnIndex, FloatTy, INNERMOST, IntTy, Interner,
10 PredicatePolarity, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
11 TypeVisitableExt, TypeVisitor, UintTy, UniverseIndex, Upcast,
12 elaborate::{self, elaborate},
13 inherent::{AdtDef, GenericArg as _, IntoKind, ParamEnv as _, SliceLike, Ty as _},
14 lang_items::SolverTraitLangItem,
15 solve::SizedTraitKind,
16};
17use stdx::impl_from;
18
19use crate::{
20 ImplTraitId,
21 db::{HirDatabase, InternedOpaqueTyId},
22 next_solver::{
23 BoundConst, Clauses, FxIndexMap, ParamEnv, PlaceholderConst, PlaceholderRegion,
24 PlaceholderType, PolyTraitRef, StoredClauses, StoredEarlyBinder,
25 infer::{
26 InferCtxt,
27 traits::{Obligation, ObligationCause, PredicateObligation},
28 },
29 },
30 representability::Representability,
31};
32
33use super::{
34 Binder, BoundRegion, BoundTy, Clause, ClauseKind, Const, DbInterner, EarlyBinder, GenericArgs,
35 Predicate, PredicateKind, Region, SolverDefId, Ty, TyKind,
36 fold::{BoundVarReplacer, FnMutDelegate},
37};
38
39#[derive(Clone, Debug)]
40pub struct Discr<'db> {
41 pub val: u128,
43 pub ty: Ty<'db>,
44}
45
46impl<'db> Discr<'db> {
47 pub fn wrap_incr(self, interner: DbInterner<'db>) -> Self {
49 self.checked_add(interner, 1).0
50 }
51 pub fn checked_add(self, interner: DbInterner<'db>, n: u128) -> (Self, bool) {
52 let (size, signed) = self.ty.int_size_and_signed(interner);
53 let (val, oflo) = if signed {
54 let min = size.signed_int_min();
55 let max = size.signed_int_max();
56 let val = size.sign_extend(self.val);
57 assert!(n < (i128::MAX as u128));
58 let n = n as i128;
59 let oflo = val > max - n;
60 let val = if oflo { min + (n - (max - val) - 1) } else { val + n };
61 let val = val as u128;
63 let val = size.truncate(val);
64 (val, oflo)
65 } else {
66 let max = size.unsigned_int_max();
67 let val = self.val;
68 let oflo = val > max - n;
69 let val = if oflo { n - (max - val) - 1 } else { val + n };
70 (val, oflo)
71 };
72 (Self { val, ty: self.ty }, oflo)
73 }
74}
75
76pub trait IntegerTypeExt {
77 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
78 fn initial_discriminant<'db>(&self, interner: DbInterner<'db>) -> Discr<'db>;
79 fn disr_incr<'db>(
80 &self,
81 interner: DbInterner<'db>,
82 val: Option<Discr<'db>>,
83 ) -> Option<Discr<'db>>;
84}
85
86impl IntegerTypeExt for IntegerType {
87 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> {
88 let types = interner.default_types();
89 match self {
90 IntegerType::Pointer(true) => types.types.isize,
91 IntegerType::Pointer(false) => types.types.usize,
92 IntegerType::Fixed(i, s) => i.to_ty(interner, *s),
93 }
94 }
95
96 fn initial_discriminant<'db>(&self, interner: DbInterner<'db>) -> Discr<'db> {
97 Discr { val: 0, ty: self.to_ty(interner) }
98 }
99
100 fn disr_incr<'db>(
101 &self,
102 interner: DbInterner<'db>,
103 val: Option<Discr<'db>>,
104 ) -> Option<Discr<'db>> {
105 if let Some(val) = val {
106 assert_eq!(self.to_ty(interner), val.ty);
107 let (new, oflo) = val.checked_add(interner, 1);
108 if oflo { None } else { Some(new) }
109 } else {
110 Some(self.initial_discriminant(interner))
111 }
112 }
113}
114
115pub trait IntegerExt {
116 fn to_ty<'db>(&self, interner: DbInterner<'db>, signed: bool) -> Ty<'db>;
117 fn from_int_ty<C: HasDataLayout>(cx: &C, ity: IntTy) -> Integer;
118 fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: UintTy) -> Integer;
119 fn repr_discr<'db>(
120 interner: DbInterner<'db>,
121 ty: Ty<'db>,
122 repr: &ReprOptions,
123 min: i128,
124 max: i128,
125 ) -> (Integer, bool);
126}
127
128impl IntegerExt for Integer {
129 #[inline]
130 fn to_ty<'db>(&self, interner: DbInterner<'db>, signed: bool) -> Ty<'db> {
131 use Integer::*;
132 let types = interner.default_types();
133 match (*self, signed) {
134 (I8, false) => types.types.u8,
135 (I16, false) => types.types.u16,
136 (I32, false) => types.types.u32,
137 (I64, false) => types.types.u64,
138 (I128, false) => types.types.u128,
139 (I8, true) => types.types.i8,
140 (I16, true) => types.types.i16,
141 (I32, true) => types.types.i32,
142 (I64, true) => types.types.i64,
143 (I128, true) => types.types.i128,
144 }
145 }
146
147 fn from_int_ty<C: HasDataLayout>(cx: &C, ity: IntTy) -> Integer {
148 use Integer::*;
149 match ity {
150 IntTy::I8 => I8,
151 IntTy::I16 => I16,
152 IntTy::I32 => I32,
153 IntTy::I64 => I64,
154 IntTy::I128 => I128,
155 IntTy::Isize => cx.data_layout().ptr_sized_integer(),
156 }
157 }
158 fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: UintTy) -> Integer {
159 use Integer::*;
160 match ity {
161 UintTy::U8 => I8,
162 UintTy::U16 => I16,
163 UintTy::U32 => I32,
164 UintTy::U64 => I64,
165 UintTy::U128 => I128,
166 UintTy::Usize => cx.data_layout().ptr_sized_integer(),
167 }
168 }
169
170 fn repr_discr<'db>(
175 interner: DbInterner<'db>,
176 ty: Ty<'db>,
177 repr: &ReprOptions,
178 min: i128,
179 max: i128,
180 ) -> (Integer, bool) {
181 let unsigned_fit = Integer::fit_unsigned(std::cmp::max(min as u128, max as u128));
186 let signed_fit = std::cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
187
188 if let Some(ity) = repr.int {
189 let discr = Integer::from_attr(&interner, ity);
190 let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
191 if discr < fit {
192 panic!(
193 "Integer::repr_discr: `#[repr]` hint too small for \
194 discriminant range of enum `{ty:?}`"
195 )
196 }
197 return (discr, ity.is_signed());
198 }
199
200 let at_least = if repr.c() {
201 interner.data_layout().c_enum_min_size
204 } else {
205 Integer::I8
207 };
208
209 if min >= 0 {
211 (std::cmp::max(unsigned_fit, at_least), false)
212 } else {
213 (std::cmp::max(signed_fit, at_least), true)
214 }
215 }
216}
217
218pub trait FloatExt {
219 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
220 fn from_float_ty(fty: FloatTy) -> Self;
221}
222
223impl FloatExt for Float {
224 #[inline]
225 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> {
226 use Float::*;
227 let types = interner.default_types();
228 match *self {
229 F16 => types.types.f16,
230 F32 => types.types.f32,
231 F64 => types.types.f64,
232 F128 => types.types.f128,
233 }
234 }
235
236 fn from_float_ty(fty: FloatTy) -> Self {
237 use Float::*;
238 match fty {
239 FloatTy::F16 => F16,
240 FloatTy::F32 => F32,
241 FloatTy::F64 => F64,
242 FloatTy::F128 => F128,
243 }
244 }
245}
246
247pub trait PrimitiveExt {
248 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
249 fn to_int_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
250}
251
252impl PrimitiveExt for Primitive {
253 #[inline]
254 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> {
255 match *self {
256 Primitive::Int(i, signed) => i.to_ty(interner, signed),
257 Primitive::Float(f) => f.to_ty(interner),
258 Primitive::Pointer(_) => interner.default_types().types.mut_unit_ptr,
259 }
260 }
261
262 #[inline]
265 fn to_int_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> {
266 match *self {
267 Primitive::Int(i, signed) => i.to_ty(interner, signed),
268 Primitive::Pointer(_) => {
269 let signed = false;
270 interner.data_layout().ptr_sized_integer().to_ty(interner, signed)
271 }
272 Primitive::Float(_) => panic!("floats do not have an int type"),
273 }
274 }
275}
276
277impl<'db> HasDataLayout for DbInterner<'db> {
278 fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
279 unimplemented!()
280 }
281}
282
283pub trait CoroutineArgsExt<'db> {
284 fn discr_ty(&self, interner: DbInterner<'db>) -> Ty<'db>;
285}
286
287impl<'db> CoroutineArgsExt<'db> for CoroutineArgs<DbInterner<'db>> {
288 #[inline]
290 fn discr_ty(&self, interner: DbInterner<'db>) -> Ty<'db> {
291 interner.default_types().types.u32
292 }
293}
294
295pub struct MaxUniverse {
297 max_universe: UniverseIndex,
298}
299
300impl Default for MaxUniverse {
301 fn default() -> Self {
302 Self::new()
303 }
304}
305
306impl MaxUniverse {
307 pub fn new() -> Self {
308 MaxUniverse { max_universe: UniverseIndex::ROOT }
309 }
310
311 pub fn max_universe(self) -> UniverseIndex {
312 self.max_universe
313 }
314}
315
316impl<'db> TypeVisitor<DbInterner<'db>> for MaxUniverse {
317 type Result = ();
318
319 fn visit_ty(&mut self, t: Ty<'db>) {
320 if let TyKind::Placeholder(placeholder) = t.kind() {
321 self.max_universe = UniverseIndex::from_u32(
322 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
323 );
324 }
325
326 t.super_visit_with(self)
327 }
328
329 fn visit_const(&mut self, c: Const<'db>) {
330 if let ConstKind::Placeholder(placeholder) = c.kind() {
331 self.max_universe = UniverseIndex::from_u32(
332 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
333 );
334 }
335
336 c.super_visit_with(self)
337 }
338
339 fn visit_region(&mut self, r: Region<'db>) {
340 if let RegionKind::RePlaceholder(placeholder) = r.kind() {
341 self.max_universe = UniverseIndex::from_u32(
342 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
343 );
344 }
345 }
346}
347
348pub struct BottomUpFolder<'db, F, G, H>
349where
350 F: FnMut(Ty<'db>) -> Ty<'db>,
351 G: FnMut(Region<'db>) -> Region<'db>,
352 H: FnMut(Const<'db>) -> Const<'db>,
353{
354 pub interner: DbInterner<'db>,
355 pub ty_op: F,
356 pub lt_op: G,
357 pub ct_op: H,
358}
359
360impl<'db, F, G, H> TypeFolder<DbInterner<'db>> for BottomUpFolder<'db, F, G, H>
361where
362 F: FnMut(Ty<'db>) -> Ty<'db>,
363 G: FnMut(Region<'db>) -> Region<'db>,
364 H: FnMut(Const<'db>) -> Const<'db>,
365{
366 fn cx(&self) -> DbInterner<'db> {
367 self.interner
368 }
369
370 fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
371 let t = ty.super_fold_with(self);
372 (self.ty_op)(t)
373 }
374
375 fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
376 (self.lt_op)(r)
379 }
380
381 fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
382 let ct = ct.super_fold_with(self);
383 (self.ct_op)(ct)
384 }
385}
386
387pub fn sizedness_constraint_for_ty<'db>(
389 interner: DbInterner<'db>,
390 sizedness: SizedTraitKind,
391 ty: Ty<'db>,
392) -> Option<Ty<'db>> {
393 use rustc_type_ir::TyKind::*;
394
395 match ty.kind() {
396 Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
398 | FnPtr(..) | Array(..) | Closure(..) | CoroutineClosure(..) | Coroutine(..)
399 | CoroutineWitness(..) | Never => None,
400
401 Str | Slice(..) | Dynamic(_, _) => match sizedness {
403 SizedTraitKind::Sized => Some(ty),
405 SizedTraitKind::MetaSized => None,
407 },
408
409 Param(..) | Alias(..) | Error(_) => Some(ty),
411
412 UnsafeBinder(inner_ty) => {
416 sizedness_constraint_for_ty(interner, sizedness, inner_ty.skip_binder()).map(|_| ty)
417 }
418
419 Foreign(..) => Some(ty),
421
422 Pat(ty, _) => sizedness_constraint_for_ty(interner, sizedness, ty),
424
425 Tuple(tys) => tys
426 .into_iter()
427 .next_back()
428 .and_then(|ty| sizedness_constraint_for_ty(interner, sizedness, ty)),
429
430 Adt(adt, args) => {
431 if crate::representability::representability(interner.db, adt.def_id())
432 == Representability::Infinite
433 {
434 return None;
435 }
436
437 adt.struct_tail_ty(interner).and_then(|tail_ty| {
438 let tail_ty = tail_ty.instantiate(interner, args).skip_norm_wip();
439 sizedness_constraint_for_ty(interner, sizedness, tail_ty)
440 })
441 }
442
443 Placeholder(..) | Bound(..) | Infer(..) => {
444 panic!("unexpected type `{ty:?}` in sizedness_constraint_for_ty")
445 }
446 }
447}
448
449pub fn apply_args_to_binder<'db, T: TypeFoldable<DbInterner<'db>>>(
450 b: Binder<'db, T>,
451 args: GenericArgs<'db>,
452 interner: DbInterner<'db>,
453) -> T {
454 let types = &mut |ty: BoundTy<'db>| args.as_slice()[ty.var.index()].expect_ty();
455 let regions =
456 &mut |region: BoundRegion<'db>| args.as_slice()[region.var.index()].expect_region();
457 let consts = &mut |const_: BoundConst<'db>| args.as_slice()[const_.var.index()].expect_const();
458 let mut instantiate = BoundVarReplacer::new(interner, FnMutDelegate { types, regions, consts });
459 b.skip_binder().fold_with(&mut instantiate)
460}
461
462#[derive(salsa::Supertype)]
463pub(crate) enum ItemWithBounds<'db> {
464 TypeAliasId(TypeAliasId),
465 InternedOpaqueTyId(InternedOpaqueTyId<'db>),
466}
467impl_from!(impl<'db> TypeAliasId, InternedOpaqueTyId<'db> for ItemWithBounds<'db>);
468
469#[derive(Debug, PartialEq, Eq)]
470pub(crate) struct ItemBounds {
471 bounds: StoredEarlyBinder<StoredClauses>,
472 non_self_bounds_start: u32,
473}
474
475impl ItemBounds {
476 #[inline]
477 pub(crate) fn of_solver_def<'db>(
478 db: &'db dyn HirDatabase,
479 def_id: SolverDefId<'db>,
480 ) -> &'db ItemBounds {
481 let def_id = match def_id {
482 SolverDefId::TypeAliasId(def_id) => def_id.into(),
483 SolverDefId::InternedOpaqueTyId(def_id) => def_id.into(),
484 _ => panic!("unexpected SolverDefId"),
485 };
486 ItemBounds::of(db, def_id)
487 }
488
489 #[inline]
490 pub(crate) fn all_bounds(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
491 self.bounds.get().map_bound(|it| it.iter())
492 }
493
494 #[inline]
495 pub(crate) fn self_bounds(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
496 self.bounds
497 .get()
498 .map_bound(|it| it.as_slice()[..self.non_self_bounds_start as usize].iter().copied())
499 }
500
501 #[inline]
502 pub(crate) fn non_self_bounds(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
503 self.bounds
504 .get()
505 .map_bound(|it| it.as_slice()[self.non_self_bounds_start as usize..].iter().copied())
506 }
507}
508
509#[salsa::tracked]
510impl ItemBounds {
511 #[allow(
512 clippy::drop_non_drop,
513 reason = "this happens in a Salsa macro, not sure why only here"
514 )]
515 #[salsa::tracked]
516 fn of(db: &dyn HirDatabase, def_id: ItemWithBounds<'_>) -> ItemBounds {
517 let (krate, explicit_bounds) = match def_id {
518 ItemWithBounds::TypeAliasId(type_alias) => (
519 type_alias.krate(db),
520 &crate::lower::type_alias_bounds_with_diagnostics(db, type_alias).value,
521 ),
522 ItemWithBounds::InternedOpaqueTyId(id) => {
523 let loc = id.loc(db);
524 let krate = match loc {
525 ImplTraitId::ReturnTypeImplTrait(def, _) => def.krate(db),
526 ImplTraitId::TypeAliasImplTrait(def, _) => def.krate(db),
527 };
528 (krate, loc.bounds(db))
529 }
530 };
531 let interner = DbInterner::new_with(db, krate);
532
533 let all_bounds =
534 elaborate(interner, explicit_bounds.all_bounds().skip_binder().iter().copied());
535 let self_bounds =
536 elaborate(interner, explicit_bounds.self_bounds().skip_binder().iter().copied())
537 .filter_only_self();
538
539 let self_bounds = FxHashSet::from_iter(self_bounds);
540 let non_self_bounds = all_bounds.filter(|bound| !self_bounds.contains(bound));
541
542 let non_self_bounds_start = self_bounds.len() as u32;
543 let bounds = StoredEarlyBinder::bind(
544 Clauses::new_from_iter(self_bounds.iter().copied().chain(non_self_bounds)).store(),
545 );
546
547 ItemBounds { bounds, non_self_bounds_start }
548 }
549}
550
551#[salsa::tracked]
552pub(crate) fn impl_super_outlives(
553 db: &dyn HirDatabase,
554 impl_: ImplId,
555) -> StoredEarlyBinder<StoredClauses> {
556 let interner = DbInterner::new_with(db, impl_.krate(db));
557 let trait_ref = db.impl_trait(impl_).expect("invalid impl passed to trait solver");
558 let result = trait_ref.map_bound(|trait_ref| {
559 let clause: Clause<'_> = trait_ref.upcast(interner);
560 elaborate(interner, [clause]).filter(|clause| {
561 matches!(
562 clause.kind().skip_binder(),
563 ClauseKind::TypeOutlives(_) | ClauseKind::RegionOutlives(_)
564 )
565 })
566 });
567 StoredEarlyBinder::bind(Clauses::new_from_iter(result.skip_binder()).store())
568}
569
570pub struct ContainsTypeErrors;
571
572impl<'db> TypeVisitor<DbInterner<'db>> for ContainsTypeErrors {
573 type Result = ControlFlow<()>;
574
575 fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result {
576 match t.kind() {
577 rustc_type_ir::TyKind::Error(_) => ControlFlow::Break(()),
578 _ => t.super_visit_with(self),
579 }
580 }
581}
582
583pub struct PlaceholderReplacer<'a, 'db> {
585 infcx: &'a InferCtxt<'db>,
586 mapped_regions: FxIndexMap<PlaceholderRegion<'db>, BoundRegion<'db>>,
587 mapped_types: FxIndexMap<PlaceholderType<'db>, BoundTy<'db>>,
588 mapped_consts: FxIndexMap<PlaceholderConst<'db>, BoundConst<'db>>,
589 universe_indices: &'a [Option<UniverseIndex>],
590 current_index: DebruijnIndex,
591}
592
593impl<'a, 'db> PlaceholderReplacer<'a, 'db> {
594 pub fn replace_placeholders<T: TypeFoldable<DbInterner<'db>>>(
595 infcx: &'a InferCtxt<'db>,
596 mapped_regions: FxIndexMap<PlaceholderRegion<'db>, BoundRegion<'db>>,
597 mapped_types: FxIndexMap<PlaceholderType<'db>, BoundTy<'db>>,
598 mapped_consts: FxIndexMap<PlaceholderConst<'db>, BoundConst<'db>>,
599 universe_indices: &'a [Option<UniverseIndex>],
600 value: T,
601 ) -> T {
602 let mut replacer = PlaceholderReplacer {
603 infcx,
604 mapped_regions,
605 mapped_types,
606 mapped_consts,
607 universe_indices,
608 current_index: INNERMOST,
609 };
610 value.fold_with(&mut replacer)
611 }
612}
613
614impl<'db> TypeFolder<DbInterner<'db>> for PlaceholderReplacer<'_, 'db> {
615 fn cx(&self) -> DbInterner<'db> {
616 self.infcx.interner
617 }
618
619 fn fold_binder<T: TypeFoldable<DbInterner<'db>>>(
620 &mut self,
621 t: Binder<'db, T>,
622 ) -> Binder<'db, T> {
623 if !t.has_placeholders() && !t.has_infer() {
624 return t;
625 }
626 self.current_index.shift_in(1);
627 let t = t.super_fold_with(self);
628 self.current_index.shift_out(1);
629 t
630 }
631
632 fn fold_region(&mut self, r0: Region<'db>) -> Region<'db> {
633 let r1 = match r0.kind() {
634 RegionKind::ReVar(vid) => self
635 .infcx
636 .inner
637 .borrow_mut()
638 .unwrap_region_constraints()
639 .opportunistic_resolve_var(self.infcx.interner, vid),
640 _ => r0,
641 };
642
643 let r2 = match r1.kind() {
644 RegionKind::RePlaceholder(p) => {
645 let replace_var = self.mapped_regions.get(&p);
646 match replace_var {
647 Some(replace_var) => {
648 let index = self
649 .universe_indices
650 .iter()
651 .position(|u| matches!(u, Some(pu) if *pu == p.universe))
652 .unwrap_or_else(|| panic!("Unexpected placeholder universe."));
653 let db = DebruijnIndex::from_usize(
654 self.universe_indices.len() - index + self.current_index.as_usize() - 1,
655 );
656 Region::new_bound(self.cx(), db, *replace_var)
657 }
658 None => r1,
659 }
660 }
661 _ => r1,
662 };
663
664 tracing::debug!(?r0, ?r1, ?r2, "fold_region");
665
666 r2
667 }
668
669 fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
670 let ty = self.infcx.shallow_resolve(ty);
671 match ty.kind() {
672 TyKind::Placeholder(p) => {
673 let replace_var = self.mapped_types.get(&p);
674 match replace_var {
675 Some(replace_var) => {
676 let index = self
677 .universe_indices
678 .iter()
679 .position(|u| matches!(u, Some(pu) if *pu == p.universe))
680 .unwrap_or_else(|| panic!("Unexpected placeholder universe."));
681 let db = DebruijnIndex::from_usize(
682 self.universe_indices.len() - index + self.current_index.as_usize() - 1,
683 );
684 Ty::new_bound(self.infcx.interner, db, *replace_var)
685 }
686 None => {
687 if ty.has_infer() {
688 ty.super_fold_with(self)
689 } else {
690 ty
691 }
692 }
693 }
694 }
695
696 _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self),
697 _ => ty,
698 }
699 }
700
701 fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
702 let ct = self.infcx.shallow_resolve_const(ct);
703 if let ConstKind::Placeholder(p) = ct.kind() {
704 let replace_var = self.mapped_consts.get(&p);
705 match replace_var {
706 Some(replace_var) => {
707 let index = self
708 .universe_indices
709 .iter()
710 .position(|u| matches!(u, Some(pu) if *pu == p.universe))
711 .unwrap_or_else(|| panic!("Unexpected placeholder universe."));
712 let db = DebruijnIndex::from_usize(
713 self.universe_indices.len() - index + self.current_index.as_usize() - 1,
714 );
715 Const::new_bound(self.infcx.interner, db, *replace_var)
716 }
717 None => {
718 if ct.has_infer() {
719 ct.super_fold_with(self)
720 } else {
721 ct
722 }
723 }
724 }
725 } else {
726 ct.super_fold_with(self)
727 }
728 }
729}
730
731pub fn sizedness_fast_path<'db>(
732 tcx: DbInterner<'db>,
733 predicate: Predicate<'db>,
734 param_env: ParamEnv<'db>,
735) -> bool {
736 if let PredicateKind::Clause(ClauseKind::Trait(trait_pred)) = predicate.kind().skip_binder()
740 && trait_pred.polarity == PredicatePolarity::Positive
741 {
742 let sizedness = match tcx.as_trait_lang_item(trait_pred.def_id()) {
743 Some(SolverTraitLangItem::Sized) => SizedTraitKind::Sized,
744 Some(SolverTraitLangItem::MetaSized) => SizedTraitKind::MetaSized,
745 _ => return false,
746 };
747
748 if matches!(sizedness, SizedTraitKind::MetaSized) {
752 return true;
753 }
754
755 if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) {
756 tracing::debug!("fast path -- trivial sizedness");
757 return true;
758 }
759
760 if matches!(trait_pred.self_ty().kind(), TyKind::Param(_) | TyKind::Placeholder(_)) {
761 for clause in param_env.caller_bounds().iter() {
762 if let ClauseKind::Trait(clause_pred) = clause.kind().skip_binder()
763 && clause_pred.polarity == PredicatePolarity::Positive
764 && clause_pred.self_ty() == trait_pred.self_ty()
765 && (clause_pred.def_id() == trait_pred.def_id()
766 || (sizedness == SizedTraitKind::MetaSized
767 && tcx.is_trait_lang_item(
768 clause_pred.def_id(),
769 SolverTraitLangItem::Sized,
770 )))
771 {
772 return true;
773 }
774 }
775 }
776 }
777
778 false
779}
780
781pub(crate) fn upcast_choices<'db>(
785 interner: DbInterner<'db>,
786 source_trait_ref: PolyTraitRef<'db>,
787 target_trait_def_id: TraitId,
788) -> Vec<PolyTraitRef<'db>> {
789 if source_trait_ref.def_id().0 == target_trait_def_id {
790 return vec![source_trait_ref]; }
792
793 elaborate::supertraits(interner, source_trait_ref)
794 .filter(|r| r.def_id().0 == target_trait_def_id)
795 .collect()
796}
797
798#[inline]
799pub(crate) fn clauses_as_obligations<'db>(
800 clauses: impl IntoIterator<Item = Clause<'db>>,
801 cause: ObligationCause,
802 param_env: ParamEnv<'db>,
803) -> impl Iterator<Item = PredicateObligation<'db>> {
804 clauses.into_iter().map(move |clause| Obligation {
805 cause,
806 param_env,
807 predicate: clause.as_predicate(),
808 recursion_depth: 0,
809 })
810}