Skip to main content

hir_ty/next_solver/
util.rs

1//! Various utilities for the next-trait-solver.
2
3use std::ops::ControlFlow;
4
5use hir_def::TraitId;
6use rustc_abi::{Float, HasDataLayout, Integer, IntegerType, Primitive, ReprOptions};
7use rustc_type_ir::{
8    ConstKind, CoroutineArgs, DebruijnIndex, FloatTy, INNERMOST, IntTy, Interner,
9    PredicatePolarity, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
10    TypeVisitableExt, TypeVisitor, UintTy, UniverseIndex, elaborate,
11    inherent::{AdtDef, GenericArg as _, IntoKind, ParamEnv as _, SliceLike, Ty as _},
12    lang_items::SolverTraitLangItem,
13    solve::SizedTraitKind,
14};
15
16use crate::{
17    next_solver::{
18        BoundConst, FxIndexMap, ParamEnv, PlaceholderConst, PlaceholderRegion, PlaceholderType,
19        PolyTraitRef,
20        infer::{
21            InferCtxt,
22            traits::{Obligation, ObligationCause, PredicateObligation},
23        },
24    },
25    representability::Representability,
26};
27
28use super::{
29    Binder, BoundRegion, BoundTy, Clause, ClauseKind, Const, DbInterner, EarlyBinder, GenericArgs,
30    Predicate, PredicateKind, Region, SolverDefId, Ty, TyKind,
31    fold::{BoundVarReplacer, FnMutDelegate},
32};
33
34#[derive(Clone, Debug)]
35pub struct Discr<'db> {
36    /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`).
37    pub val: u128,
38    pub ty: Ty<'db>,
39}
40
41impl<'db> Discr<'db> {
42    /// Adds `1` to the value and wraps around if the maximum for the type is reached.
43    pub fn wrap_incr(self, interner: DbInterner<'db>) -> Self {
44        self.checked_add(interner, 1).0
45    }
46    pub fn checked_add(self, interner: DbInterner<'db>, n: u128) -> (Self, bool) {
47        let (size, signed) = self.ty.int_size_and_signed(interner);
48        let (val, oflo) = if signed {
49            let min = size.signed_int_min();
50            let max = size.signed_int_max();
51            let val = size.sign_extend(self.val);
52            assert!(n < (i128::MAX as u128));
53            let n = n as i128;
54            let oflo = val > max - n;
55            let val = if oflo { min + (n - (max - val) - 1) } else { val + n };
56            // zero the upper bits
57            let val = val as u128;
58            let val = size.truncate(val);
59            (val, oflo)
60        } else {
61            let max = size.unsigned_int_max();
62            let val = self.val;
63            let oflo = val > max - n;
64            let val = if oflo { n - (max - val) - 1 } else { val + n };
65            (val, oflo)
66        };
67        (Self { val, ty: self.ty }, oflo)
68    }
69}
70
71pub trait IntegerTypeExt {
72    fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
73    fn initial_discriminant<'db>(&self, interner: DbInterner<'db>) -> Discr<'db>;
74    fn disr_incr<'db>(
75        &self,
76        interner: DbInterner<'db>,
77        val: Option<Discr<'db>>,
78    ) -> Option<Discr<'db>>;
79}
80
81impl IntegerTypeExt for IntegerType {
82    fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> {
83        let types = interner.default_types();
84        match self {
85            IntegerType::Pointer(true) => types.types.isize,
86            IntegerType::Pointer(false) => types.types.usize,
87            IntegerType::Fixed(i, s) => i.to_ty(interner, *s),
88        }
89    }
90
91    fn initial_discriminant<'db>(&self, interner: DbInterner<'db>) -> Discr<'db> {
92        Discr { val: 0, ty: self.to_ty(interner) }
93    }
94
95    fn disr_incr<'db>(
96        &self,
97        interner: DbInterner<'db>,
98        val: Option<Discr<'db>>,
99    ) -> Option<Discr<'db>> {
100        if let Some(val) = val {
101            assert_eq!(self.to_ty(interner), val.ty);
102            let (new, oflo) = val.checked_add(interner, 1);
103            if oflo { None } else { Some(new) }
104        } else {
105            Some(self.initial_discriminant(interner))
106        }
107    }
108}
109
110pub trait IntegerExt {
111    fn to_ty<'db>(&self, interner: DbInterner<'db>, signed: bool) -> Ty<'db>;
112    fn from_int_ty<C: HasDataLayout>(cx: &C, ity: IntTy) -> Integer;
113    fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: UintTy) -> Integer;
114    fn repr_discr<'db>(
115        interner: DbInterner<'db>,
116        ty: Ty<'db>,
117        repr: &ReprOptions,
118        min: i128,
119        max: i128,
120    ) -> (Integer, bool);
121}
122
123impl IntegerExt for Integer {
124    #[inline]
125    fn to_ty<'db>(&self, interner: DbInterner<'db>, signed: bool) -> Ty<'db> {
126        use Integer::*;
127        let types = interner.default_types();
128        match (*self, signed) {
129            (I8, false) => types.types.u8,
130            (I16, false) => types.types.u16,
131            (I32, false) => types.types.u32,
132            (I64, false) => types.types.u64,
133            (I128, false) => types.types.u128,
134            (I8, true) => types.types.i8,
135            (I16, true) => types.types.i16,
136            (I32, true) => types.types.i32,
137            (I64, true) => types.types.i64,
138            (I128, true) => types.types.i128,
139        }
140    }
141
142    fn from_int_ty<C: HasDataLayout>(cx: &C, ity: IntTy) -> Integer {
143        use Integer::*;
144        match ity {
145            IntTy::I8 => I8,
146            IntTy::I16 => I16,
147            IntTy::I32 => I32,
148            IntTy::I64 => I64,
149            IntTy::I128 => I128,
150            IntTy::Isize => cx.data_layout().ptr_sized_integer(),
151        }
152    }
153    fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: UintTy) -> Integer {
154        use Integer::*;
155        match ity {
156            UintTy::U8 => I8,
157            UintTy::U16 => I16,
158            UintTy::U32 => I32,
159            UintTy::U64 => I64,
160            UintTy::U128 => I128,
161            UintTy::Usize => cx.data_layout().ptr_sized_integer(),
162        }
163    }
164
165    /// Finds the appropriate Integer type and signedness for the given
166    /// signed discriminant range and `#[repr]` attribute.
167    /// N.B.: `u128` values above `i128::MAX` will be treated as signed, but
168    /// that shouldn't affect anything, other than maybe debuginfo.
169    fn repr_discr<'db>(
170        interner: DbInterner<'db>,
171        ty: Ty<'db>,
172        repr: &ReprOptions,
173        min: i128,
174        max: i128,
175    ) -> (Integer, bool) {
176        // Theoretically, negative values could be larger in unsigned representation
177        // than the unsigned representation of the signed minimum. However, if there
178        // are any negative values, the only valid unsigned representation is u128
179        // which can fit all i128 values, so the result remains unaffected.
180        let unsigned_fit = Integer::fit_unsigned(std::cmp::max(min as u128, max as u128));
181        let signed_fit = std::cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
182
183        if let Some(ity) = repr.int {
184            let discr = Integer::from_attr(&interner, ity);
185            let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
186            if discr < fit {
187                panic!(
188                    "Integer::repr_discr: `#[repr]` hint too small for \
189                      discriminant range of enum `{ty:?}`"
190                )
191            }
192            return (discr, ity.is_signed());
193        }
194
195        let at_least = if repr.c() {
196            // This is usually I32, however it can be different on some platforms,
197            // notably hexagon and arm-none/thumb-none
198            interner.data_layout().c_enum_min_size
199        } else {
200            // repr(Rust) enums try to be as small as possible
201            Integer::I8
202        };
203
204        // If there are no negative values, we can use the unsigned fit.
205        if min >= 0 {
206            (std::cmp::max(unsigned_fit, at_least), false)
207        } else {
208            (std::cmp::max(signed_fit, at_least), true)
209        }
210    }
211}
212
213pub trait FloatExt {
214    fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
215    fn from_float_ty(fty: FloatTy) -> Self;
216}
217
218impl FloatExt for Float {
219    #[inline]
220    fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> {
221        use Float::*;
222        let types = interner.default_types();
223        match *self {
224            F16 => types.types.f16,
225            F32 => types.types.f32,
226            F64 => types.types.f64,
227            F128 => types.types.f128,
228        }
229    }
230
231    fn from_float_ty(fty: FloatTy) -> Self {
232        use Float::*;
233        match fty {
234            FloatTy::F16 => F16,
235            FloatTy::F32 => F32,
236            FloatTy::F64 => F64,
237            FloatTy::F128 => F128,
238        }
239    }
240}
241
242pub trait PrimitiveExt {
243    fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
244    fn to_int_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
245}
246
247impl PrimitiveExt for Primitive {
248    #[inline]
249    fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> {
250        match *self {
251            Primitive::Int(i, signed) => i.to_ty(interner, signed),
252            Primitive::Float(f) => f.to_ty(interner),
253            Primitive::Pointer(_) => interner.default_types().types.mut_unit_ptr,
254        }
255    }
256
257    /// Return an *integer* type matching this primitive.
258    /// Useful in particular when dealing with enum discriminants.
259    #[inline]
260    fn to_int_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> {
261        match *self {
262            Primitive::Int(i, signed) => i.to_ty(interner, signed),
263            Primitive::Pointer(_) => {
264                let signed = false;
265                interner.data_layout().ptr_sized_integer().to_ty(interner, signed)
266            }
267            Primitive::Float(_) => panic!("floats do not have an int type"),
268        }
269    }
270}
271
272impl<'db> HasDataLayout for DbInterner<'db> {
273    fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
274        unimplemented!()
275    }
276}
277
278pub trait CoroutineArgsExt<'db> {
279    fn discr_ty(&self, interner: DbInterner<'db>) -> Ty<'db>;
280}
281
282impl<'db> CoroutineArgsExt<'db> for CoroutineArgs<DbInterner<'db>> {
283    /// The type of the state discriminant used in the coroutine type.
284    #[inline]
285    fn discr_ty(&self, interner: DbInterner<'db>) -> Ty<'db> {
286        interner.default_types().types.u32
287    }
288}
289
290/// Finds the max universe present
291pub struct MaxUniverse {
292    max_universe: UniverseIndex,
293}
294
295impl Default for MaxUniverse {
296    fn default() -> Self {
297        Self::new()
298    }
299}
300
301impl MaxUniverse {
302    pub fn new() -> Self {
303        MaxUniverse { max_universe: UniverseIndex::ROOT }
304    }
305
306    pub fn max_universe(self) -> UniverseIndex {
307        self.max_universe
308    }
309}
310
311impl<'db> TypeVisitor<DbInterner<'db>> for MaxUniverse {
312    type Result = ();
313
314    fn visit_ty(&mut self, t: Ty<'db>) {
315        if let TyKind::Placeholder(placeholder) = t.kind() {
316            self.max_universe = UniverseIndex::from_u32(
317                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
318            );
319        }
320
321        t.super_visit_with(self)
322    }
323
324    fn visit_const(&mut self, c: Const<'db>) {
325        if let ConstKind::Placeholder(placeholder) = c.kind() {
326            self.max_universe = UniverseIndex::from_u32(
327                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
328            );
329        }
330
331        c.super_visit_with(self)
332    }
333
334    fn visit_region(&mut self, r: Region<'db>) {
335        if let RegionKind::RePlaceholder(placeholder) = r.kind() {
336            self.max_universe = UniverseIndex::from_u32(
337                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
338            );
339        }
340    }
341}
342
343pub struct BottomUpFolder<'db, F, G, H>
344where
345    F: FnMut(Ty<'db>) -> Ty<'db>,
346    G: FnMut(Region<'db>) -> Region<'db>,
347    H: FnMut(Const<'db>) -> Const<'db>,
348{
349    pub interner: DbInterner<'db>,
350    pub ty_op: F,
351    pub lt_op: G,
352    pub ct_op: H,
353}
354
355impl<'db, F, G, H> TypeFolder<DbInterner<'db>> for BottomUpFolder<'db, F, G, H>
356where
357    F: FnMut(Ty<'db>) -> Ty<'db>,
358    G: FnMut(Region<'db>) -> Region<'db>,
359    H: FnMut(Const<'db>) -> Const<'db>,
360{
361    fn cx(&self) -> DbInterner<'db> {
362        self.interner
363    }
364
365    fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
366        let t = ty.super_fold_with(self);
367        (self.ty_op)(t)
368    }
369
370    fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
371        // This one is a little different, because `super_fold_with` is not
372        // implemented on non-recursive `Region`.
373        (self.lt_op)(r)
374    }
375
376    fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
377        let ct = ct.super_fold_with(self);
378        (self.ct_op)(ct)
379    }
380}
381
382// FIXME(next-trait-solver): uplift
383pub fn sizedness_constraint_for_ty<'db>(
384    interner: DbInterner<'db>,
385    sizedness: SizedTraitKind,
386    ty: Ty<'db>,
387) -> Option<Ty<'db>> {
388    use rustc_type_ir::TyKind::*;
389
390    match ty.kind() {
391        // these are always sized
392        Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
393        | FnPtr(..) | Array(..) | Closure(..) | CoroutineClosure(..) | Coroutine(..)
394        | CoroutineWitness(..) | Never => None,
395
396        // these are never sized
397        Str | Slice(..) | Dynamic(_, _) => match sizedness {
398            // Never `Sized`
399            SizedTraitKind::Sized => Some(ty),
400            // Always `MetaSized`
401            SizedTraitKind::MetaSized => None,
402        },
403
404        // Maybe `Sized` or `MetaSized`
405        Param(..) | Alias(..) | Error(_) => Some(ty),
406
407        // We cannot instantiate the binder, so just return the *original* type back,
408        // but only if the inner type has a sized constraint. Thus we skip the binder,
409        // but don't actually use the result from `sized_constraint_for_ty`.
410        UnsafeBinder(inner_ty) => {
411            sizedness_constraint_for_ty(interner, sizedness, inner_ty.skip_binder()).map(|_| ty)
412        }
413
414        // Never `MetaSized` or `Sized`
415        Foreign(..) => Some(ty),
416
417        // Recursive cases
418        Pat(ty, _) => sizedness_constraint_for_ty(interner, sizedness, ty),
419
420        Tuple(tys) => tys
421            .into_iter()
422            .next_back()
423            .and_then(|ty| sizedness_constraint_for_ty(interner, sizedness, ty)),
424
425        Adt(adt, args) => {
426            if crate::representability::representability(interner.db, adt.def_id())
427                == Representability::Infinite
428            {
429                return None;
430            }
431
432            adt.struct_tail_ty(interner).and_then(|tail_ty| {
433                let tail_ty = tail_ty.instantiate(interner, args).skip_norm_wip();
434                sizedness_constraint_for_ty(interner, sizedness, tail_ty)
435            })
436        }
437
438        Placeholder(..) | Bound(..) | Infer(..) => {
439            panic!("unexpected type `{ty:?}` in sizedness_constraint_for_ty")
440        }
441    }
442}
443
444pub fn apply_args_to_binder<'db, T: TypeFoldable<DbInterner<'db>>>(
445    b: Binder<'db, T>,
446    args: GenericArgs<'db>,
447    interner: DbInterner<'db>,
448) -> T {
449    let types = &mut |ty: BoundTy<'db>| args.as_slice()[ty.var.index()].expect_ty();
450    let regions =
451        &mut |region: BoundRegion<'db>| args.as_slice()[region.var.index()].expect_region();
452    let consts = &mut |const_: BoundConst<'db>| args.as_slice()[const_.var.index()].expect_const();
453    let mut instantiate = BoundVarReplacer::new(interner, FnMutDelegate { types, regions, consts });
454    b.skip_binder().fold_with(&mut instantiate)
455}
456
457pub fn explicit_item_bounds<'db>(
458    interner: DbInterner<'db>,
459    def_id: SolverDefId<'db>,
460) -> EarlyBinder<'db, impl DoubleEndedIterator<Item = Clause<'db>> + ExactSizeIterator> {
461    let db = interner.db();
462    let clauses = match def_id {
463        SolverDefId::TypeAliasId(type_alias) => crate::lower::type_alias_bounds(db, type_alias),
464        SolverDefId::InternedOpaqueTyId(id) => id.predicates(db),
465        _ => panic!("Unexpected GenericDefId"),
466    };
467    clauses.map_bound(|clauses| clauses.iter().copied())
468}
469
470pub fn explicit_item_self_bounds<'db>(
471    interner: DbInterner<'db>,
472    def_id: SolverDefId<'db>,
473) -> EarlyBinder<'db, impl DoubleEndedIterator<Item = Clause<'db>> + ExactSizeIterator> {
474    let db = interner.db();
475    let clauses = match def_id {
476        SolverDefId::TypeAliasId(type_alias) => {
477            crate::lower::type_alias_self_bounds(db, type_alias)
478        }
479        SolverDefId::InternedOpaqueTyId(id) => id.self_predicates(db),
480        _ => panic!("Unexpected GenericDefId"),
481    };
482    clauses.map_bound(|clauses| clauses.iter().copied())
483}
484
485pub struct ContainsTypeErrors;
486
487impl<'db> TypeVisitor<DbInterner<'db>> for ContainsTypeErrors {
488    type Result = ControlFlow<()>;
489
490    fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result {
491        match t.kind() {
492            rustc_type_ir::TyKind::Error(_) => ControlFlow::Break(()),
493            _ => t.super_visit_with(self),
494        }
495    }
496}
497
498/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came.
499pub struct PlaceholderReplacer<'a, 'db> {
500    infcx: &'a InferCtxt<'db>,
501    mapped_regions: FxIndexMap<PlaceholderRegion<'db>, BoundRegion<'db>>,
502    mapped_types: FxIndexMap<PlaceholderType<'db>, BoundTy<'db>>,
503    mapped_consts: FxIndexMap<PlaceholderConst<'db>, BoundConst<'db>>,
504    universe_indices: &'a [Option<UniverseIndex>],
505    current_index: DebruijnIndex,
506}
507
508impl<'a, 'db> PlaceholderReplacer<'a, 'db> {
509    pub fn replace_placeholders<T: TypeFoldable<DbInterner<'db>>>(
510        infcx: &'a InferCtxt<'db>,
511        mapped_regions: FxIndexMap<PlaceholderRegion<'db>, BoundRegion<'db>>,
512        mapped_types: FxIndexMap<PlaceholderType<'db>, BoundTy<'db>>,
513        mapped_consts: FxIndexMap<PlaceholderConst<'db>, BoundConst<'db>>,
514        universe_indices: &'a [Option<UniverseIndex>],
515        value: T,
516    ) -> T {
517        let mut replacer = PlaceholderReplacer {
518            infcx,
519            mapped_regions,
520            mapped_types,
521            mapped_consts,
522            universe_indices,
523            current_index: INNERMOST,
524        };
525        value.fold_with(&mut replacer)
526    }
527}
528
529impl<'db> TypeFolder<DbInterner<'db>> for PlaceholderReplacer<'_, 'db> {
530    fn cx(&self) -> DbInterner<'db> {
531        self.infcx.interner
532    }
533
534    fn fold_binder<T: TypeFoldable<DbInterner<'db>>>(
535        &mut self,
536        t: Binder<'db, T>,
537    ) -> Binder<'db, T> {
538        if !t.has_placeholders() && !t.has_infer() {
539            return t;
540        }
541        self.current_index.shift_in(1);
542        let t = t.super_fold_with(self);
543        self.current_index.shift_out(1);
544        t
545    }
546
547    fn fold_region(&mut self, r0: Region<'db>) -> Region<'db> {
548        let r1 = match r0.kind() {
549            RegionKind::ReVar(vid) => self
550                .infcx
551                .inner
552                .borrow_mut()
553                .unwrap_region_constraints()
554                .opportunistic_resolve_var(self.infcx.interner, vid),
555            _ => r0,
556        };
557
558        let r2 = match r1.kind() {
559            RegionKind::RePlaceholder(p) => {
560                let replace_var = self.mapped_regions.get(&p);
561                match replace_var {
562                    Some(replace_var) => {
563                        let index = self
564                            .universe_indices
565                            .iter()
566                            .position(|u| matches!(u, Some(pu) if *pu == p.universe))
567                            .unwrap_or_else(|| panic!("Unexpected placeholder universe."));
568                        let db = DebruijnIndex::from_usize(
569                            self.universe_indices.len() - index + self.current_index.as_usize() - 1,
570                        );
571                        Region::new_bound(self.cx(), db, *replace_var)
572                    }
573                    None => r1,
574                }
575            }
576            _ => r1,
577        };
578
579        tracing::debug!(?r0, ?r1, ?r2, "fold_region");
580
581        r2
582    }
583
584    fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
585        let ty = self.infcx.shallow_resolve(ty);
586        match ty.kind() {
587            TyKind::Placeholder(p) => {
588                let replace_var = self.mapped_types.get(&p);
589                match replace_var {
590                    Some(replace_var) => {
591                        let index = self
592                            .universe_indices
593                            .iter()
594                            .position(|u| matches!(u, Some(pu) if *pu == p.universe))
595                            .unwrap_or_else(|| panic!("Unexpected placeholder universe."));
596                        let db = DebruijnIndex::from_usize(
597                            self.universe_indices.len() - index + self.current_index.as_usize() - 1,
598                        );
599                        Ty::new_bound(self.infcx.interner, db, *replace_var)
600                    }
601                    None => {
602                        if ty.has_infer() {
603                            ty.super_fold_with(self)
604                        } else {
605                            ty
606                        }
607                    }
608                }
609            }
610
611            _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self),
612            _ => ty,
613        }
614    }
615
616    fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
617        let ct = self.infcx.shallow_resolve_const(ct);
618        if let ConstKind::Placeholder(p) = ct.kind() {
619            let replace_var = self.mapped_consts.get(&p);
620            match replace_var {
621                Some(replace_var) => {
622                    let index = self
623                        .universe_indices
624                        .iter()
625                        .position(|u| matches!(u, Some(pu) if *pu == p.universe))
626                        .unwrap_or_else(|| panic!("Unexpected placeholder universe."));
627                    let db = DebruijnIndex::from_usize(
628                        self.universe_indices.len() - index + self.current_index.as_usize() - 1,
629                    );
630                    Const::new_bound(self.infcx.interner, db, *replace_var)
631                }
632                None => {
633                    if ct.has_infer() {
634                        ct.super_fold_with(self)
635                    } else {
636                        ct
637                    }
638                }
639            }
640        } else {
641            ct.super_fold_with(self)
642        }
643    }
644}
645
646pub fn sizedness_fast_path<'db>(
647    tcx: DbInterner<'db>,
648    predicate: Predicate<'db>,
649    param_env: ParamEnv<'db>,
650) -> bool {
651    // Proving `Sized`/`MetaSized`, very often on "obviously sized" types like
652    // `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to
653    // canonicalize and all that for such cases.
654    if let PredicateKind::Clause(ClauseKind::Trait(trait_pred)) = predicate.kind().skip_binder()
655        && trait_pred.polarity == PredicatePolarity::Positive
656    {
657        let sizedness = match tcx.as_trait_lang_item(trait_pred.def_id()) {
658            Some(SolverTraitLangItem::Sized) => SizedTraitKind::Sized,
659            Some(SolverTraitLangItem::MetaSized) => SizedTraitKind::MetaSized,
660            _ => return false,
661        };
662
663        // FIXME(sized_hierarchy): this temporarily reverts the `sized_hierarchy` feature
664        // while a proper fix for `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs`
665        // is pending a proper fix
666        if matches!(sizedness, SizedTraitKind::MetaSized) {
667            return true;
668        }
669
670        if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) {
671            tracing::debug!("fast path -- trivial sizedness");
672            return true;
673        }
674
675        if matches!(trait_pred.self_ty().kind(), TyKind::Param(_) | TyKind::Placeholder(_)) {
676            for clause in param_env.caller_bounds().iter() {
677                if let ClauseKind::Trait(clause_pred) = clause.kind().skip_binder()
678                    && clause_pred.polarity == PredicatePolarity::Positive
679                    && clause_pred.self_ty() == trait_pred.self_ty()
680                    && (clause_pred.def_id() == trait_pred.def_id()
681                        || (sizedness == SizedTraitKind::MetaSized
682                            && tcx.is_trait_lang_item(
683                                clause_pred.def_id(),
684                                SolverTraitLangItem::Sized,
685                            )))
686                {
687                    return true;
688                }
689            }
690        }
691    }
692
693    false
694}
695
696/// Casts a trait reference into a reference to one of its super
697/// traits; returns `None` if `target_trait_def_id` is not a
698/// supertrait.
699pub(crate) fn upcast_choices<'db>(
700    interner: DbInterner<'db>,
701    source_trait_ref: PolyTraitRef<'db>,
702    target_trait_def_id: TraitId,
703) -> Vec<PolyTraitRef<'db>> {
704    if source_trait_ref.def_id().0 == target_trait_def_id {
705        return vec![source_trait_ref]; // Shortcut the most common case.
706    }
707
708    elaborate::supertraits(interner, source_trait_ref)
709        .filter(|r| r.def_id().0 == target_trait_def_id)
710        .collect()
711}
712
713#[inline]
714pub(crate) fn clauses_as_obligations<'db>(
715    clauses: impl IntoIterator<Item = Clause<'db>>,
716    cause: ObligationCause,
717    param_env: ParamEnv<'db>,
718) -> impl Iterator<Item = PredicateObligation<'db>> {
719    clauses.into_iter().map(move |clause| Obligation {
720        cause,
721        param_env,
722        predicate: clause.as_predicate(),
723        recursion_depth: 0,
724    })
725}