1use 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 pub val: u128,
38 pub ty: Ty<'db>,
39}
40
41impl<'db> Discr<'db> {
42 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 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 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 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 interner.data_layout().c_enum_min_size
199 } else {
200 Integer::I8
202 };
203
204 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 #[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 #[inline]
285 fn discr_ty(&self, interner: DbInterner<'db>) -> Ty<'db> {
286 interner.default_types().types.u32
287 }
288}
289
290pub 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 (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
382pub 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 Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
393 | FnPtr(..) | Array(..) | Closure(..) | CoroutineClosure(..) | Coroutine(..)
394 | CoroutineWitness(..) | Never => None,
395
396 Str | Slice(..) | Dynamic(_, _) => match sizedness {
398 SizedTraitKind::Sized => Some(ty),
400 SizedTraitKind::MetaSized => None,
402 },
403
404 Param(..) | Alias(..) | Error(_) => Some(ty),
406
407 UnsafeBinder(inner_ty) => {
411 sizedness_constraint_for_ty(interner, sizedness, inner_ty.skip_binder()).map(|_| ty)
412 }
413
414 Foreign(..) => Some(ty),
416
417 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
498pub 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 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 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
696pub(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]; }
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}