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::next_solver::{
17 BoundConst, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst, PlaceholderRegion,
18 PolyTraitRef,
19 infer::{
20 InferCtxt,
21 traits::{Obligation, ObligationCause, PredicateObligation},
22 },
23};
24
25use super::{
26 Binder, BoundRegion, BoundTy, Clause, ClauseKind, Const, DbInterner, EarlyBinder, GenericArgs,
27 Predicate, PredicateKind, Region, SolverDefId, Ty, TyKind,
28 fold::{BoundVarReplacer, FnMutDelegate},
29};
30
31#[derive(Clone, Debug)]
32pub struct Discr<'db> {
33 pub val: u128,
35 pub ty: Ty<'db>,
36}
37
38impl<'db> Discr<'db> {
39 pub fn wrap_incr(self, interner: DbInterner<'db>) -> Self {
41 self.checked_add(interner, 1).0
42 }
43 pub fn checked_add(self, interner: DbInterner<'db>, n: u128) -> (Self, bool) {
44 let (size, signed) = self.ty.int_size_and_signed(interner);
45 let (val, oflo) = if signed {
46 let min = size.signed_int_min();
47 let max = size.signed_int_max();
48 let val = size.sign_extend(self.val);
49 assert!(n < (i128::MAX as u128));
50 let n = n as i128;
51 let oflo = val > max - n;
52 let val = if oflo { min + (n - (max - val) - 1) } else { val + n };
53 let val = val as u128;
55 let val = size.truncate(val);
56 (val, oflo)
57 } else {
58 let max = size.unsigned_int_max();
59 let val = self.val;
60 let oflo = val > max - n;
61 let val = if oflo { n - (max - val) - 1 } else { val + n };
62 (val, oflo)
63 };
64 (Self { val, ty: self.ty }, oflo)
65 }
66}
67
68pub trait IntegerTypeExt {
69 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
70 fn initial_discriminant<'db>(&self, interner: DbInterner<'db>) -> Discr<'db>;
71 fn disr_incr<'db>(
72 &self,
73 interner: DbInterner<'db>,
74 val: Option<Discr<'db>>,
75 ) -> Option<Discr<'db>>;
76}
77
78impl IntegerTypeExt for IntegerType {
79 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> {
80 match self {
81 IntegerType::Pointer(true) => Ty::new(interner, TyKind::Int(IntTy::Isize)),
82 IntegerType::Pointer(false) => Ty::new(interner, TyKind::Uint(UintTy::Usize)),
83 IntegerType::Fixed(i, s) => i.to_ty(interner, *s),
84 }
85 }
86
87 fn initial_discriminant<'db>(&self, interner: DbInterner<'db>) -> Discr<'db> {
88 Discr { val: 0, ty: self.to_ty(interner) }
89 }
90
91 fn disr_incr<'db>(
92 &self,
93 interner: DbInterner<'db>,
94 val: Option<Discr<'db>>,
95 ) -> Option<Discr<'db>> {
96 if let Some(val) = val {
97 assert_eq!(self.to_ty(interner), val.ty);
98 let (new, oflo) = val.checked_add(interner, 1);
99 if oflo { None } else { Some(new) }
100 } else {
101 Some(self.initial_discriminant(interner))
102 }
103 }
104}
105
106pub trait IntegerExt {
107 fn to_ty<'db>(&self, interner: DbInterner<'db>, signed: bool) -> Ty<'db>;
108 fn from_int_ty<C: HasDataLayout>(cx: &C, ity: IntTy) -> Integer;
109 fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: UintTy) -> Integer;
110 fn repr_discr<'db>(
111 interner: DbInterner<'db>,
112 ty: Ty<'db>,
113 repr: &ReprOptions,
114 min: i128,
115 max: i128,
116 ) -> (Integer, bool);
117}
118
119impl IntegerExt for Integer {
120 #[inline]
121 fn to_ty<'db>(&self, interner: DbInterner<'db>, signed: bool) -> Ty<'db> {
122 use Integer::*;
123 match (*self, signed) {
124 (I8, false) => Ty::new(interner, TyKind::Uint(UintTy::U8)),
125 (I16, false) => Ty::new(interner, TyKind::Uint(UintTy::U16)),
126 (I32, false) => Ty::new(interner, TyKind::Uint(UintTy::U32)),
127 (I64, false) => Ty::new(interner, TyKind::Uint(UintTy::U64)),
128 (I128, false) => Ty::new(interner, TyKind::Uint(UintTy::U128)),
129 (I8, true) => Ty::new(interner, TyKind::Int(IntTy::I8)),
130 (I16, true) => Ty::new(interner, TyKind::Int(IntTy::I16)),
131 (I32, true) => Ty::new(interner, TyKind::Int(IntTy::I32)),
132 (I64, true) => Ty::new(interner, TyKind::Int(IntTy::I64)),
133 (I128, true) => Ty::new(interner, TyKind::Int(IntTy::I128)),
134 }
135 }
136
137 fn from_int_ty<C: HasDataLayout>(cx: &C, ity: IntTy) -> Integer {
138 use Integer::*;
139 match ity {
140 IntTy::I8 => I8,
141 IntTy::I16 => I16,
142 IntTy::I32 => I32,
143 IntTy::I64 => I64,
144 IntTy::I128 => I128,
145 IntTy::Isize => cx.data_layout().ptr_sized_integer(),
146 }
147 }
148 fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: UintTy) -> Integer {
149 use Integer::*;
150 match ity {
151 UintTy::U8 => I8,
152 UintTy::U16 => I16,
153 UintTy::U32 => I32,
154 UintTy::U64 => I64,
155 UintTy::U128 => I128,
156 UintTy::Usize => cx.data_layout().ptr_sized_integer(),
157 }
158 }
159
160 fn repr_discr<'db>(
165 interner: DbInterner<'db>,
166 ty: Ty<'db>,
167 repr: &ReprOptions,
168 min: i128,
169 max: i128,
170 ) -> (Integer, bool) {
171 let unsigned_fit = Integer::fit_unsigned(std::cmp::max(min as u128, max as u128));
176 let signed_fit = std::cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
177
178 if let Some(ity) = repr.int {
179 let discr = Integer::from_attr(&interner, ity);
180 let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
181 if discr < fit {
182 panic!(
183 "Integer::repr_discr: `#[repr]` hint too small for \
184 discriminant range of enum `{ty:?}`"
185 )
186 }
187 return (discr, ity.is_signed());
188 }
189
190 let at_least = if repr.c() {
191 interner.data_layout().c_enum_min_size
194 } else {
195 Integer::I8
197 };
198
199 if min >= 0 {
201 (std::cmp::max(unsigned_fit, at_least), false)
202 } else {
203 (std::cmp::max(signed_fit, at_least), true)
204 }
205 }
206}
207
208pub trait FloatExt {
209 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
210 fn from_float_ty(fty: FloatTy) -> Self;
211}
212
213impl FloatExt for Float {
214 #[inline]
215 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> {
216 use Float::*;
217 match *self {
218 F16 => Ty::new(interner, TyKind::Float(FloatTy::F16)),
219 F32 => Ty::new(interner, TyKind::Float(FloatTy::F32)),
220 F64 => Ty::new(interner, TyKind::Float(FloatTy::F64)),
221 F128 => Ty::new(interner, TyKind::Float(FloatTy::F128)),
222 }
223 }
224
225 fn from_float_ty(fty: FloatTy) -> Self {
226 use Float::*;
227 match fty {
228 FloatTy::F16 => F16,
229 FloatTy::F32 => F32,
230 FloatTy::F64 => F64,
231 FloatTy::F128 => F128,
232 }
233 }
234}
235
236pub trait PrimitiveExt {
237 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
238 fn to_int_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db>;
239}
240
241impl PrimitiveExt for Primitive {
242 #[inline]
243 fn to_ty<'db>(&self, interner: DbInterner<'db>) -> Ty<'db> {
244 match *self {
245 Primitive::Int(i, signed) => i.to_ty(interner, signed),
246 Primitive::Float(f) => f.to_ty(interner),
247 Primitive::Pointer(_) => Ty::new(
248 interner,
249 TyKind::RawPtr(
250 Ty::new(interner, TyKind::Tuple(Default::default())),
251 rustc_ast_ir::Mutability::Mut,
252 ),
253 ),
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 Ty::new(interner, TyKind::Uint(UintTy::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) => adt.struct_tail_ty(interner).and_then(|tail_ty| {
426 let tail_ty = tail_ty.instantiate(interner, args);
427 sizedness_constraint_for_ty(interner, sizedness, tail_ty)
428 }),
429
430 Placeholder(..) | Bound(..) | Infer(..) => {
431 panic!("unexpected type `{ty:?}` in sizedness_constraint_for_ty")
432 }
433 }
434}
435
436pub fn apply_args_to_binder<'db, T: TypeFoldable<DbInterner<'db>>>(
437 b: Binder<'db, T>,
438 args: GenericArgs<'db>,
439 interner: DbInterner<'db>,
440) -> T {
441 let types = &mut |ty: BoundTy| args.as_slice()[ty.var.index()].expect_ty();
442 let regions = &mut |region: BoundRegion| args.as_slice()[region.var.index()].expect_region();
443 let consts = &mut |const_: BoundConst| args.as_slice()[const_.var.index()].expect_const();
444 let mut instantiate = BoundVarReplacer::new(interner, FnMutDelegate { types, regions, consts });
445 b.skip_binder().fold_with(&mut instantiate)
446}
447
448pub fn explicit_item_bounds<'db>(
449 interner: DbInterner<'db>,
450 def_id: SolverDefId,
451) -> EarlyBinder<'db, impl DoubleEndedIterator<Item = Clause<'db>> + ExactSizeIterator> {
452 let db = interner.db();
453 let clauses = match def_id {
454 SolverDefId::TypeAliasId(type_alias) => crate::lower::type_alias_bounds(db, type_alias),
455 SolverDefId::InternedOpaqueTyId(id) => id.predicates(db),
456 _ => panic!("Unexpected GenericDefId"),
457 };
458 clauses.map_bound(|clauses| clauses.iter().copied())
459}
460
461pub struct ContainsTypeErrors;
462
463impl<'db> TypeVisitor<DbInterner<'db>> for ContainsTypeErrors {
464 type Result = ControlFlow<()>;
465
466 fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result {
467 match t.kind() {
468 rustc_type_ir::TyKind::Error(_) => ControlFlow::Break(()),
469 _ => t.super_visit_with(self),
470 }
471 }
472}
473
474pub struct PlaceholderReplacer<'a, 'db> {
476 infcx: &'a InferCtxt<'db>,
477 mapped_regions: FxIndexMap<PlaceholderRegion, BoundRegion>,
478 mapped_types: FxIndexMap<Placeholder<BoundTy>, BoundTy>,
479 mapped_consts: FxIndexMap<PlaceholderConst, BoundConst>,
480 universe_indices: &'a [Option<UniverseIndex>],
481 current_index: DebruijnIndex,
482}
483
484impl<'a, 'db> PlaceholderReplacer<'a, 'db> {
485 pub fn replace_placeholders<T: TypeFoldable<DbInterner<'db>>>(
486 infcx: &'a InferCtxt<'db>,
487 mapped_regions: FxIndexMap<PlaceholderRegion, BoundRegion>,
488 mapped_types: FxIndexMap<Placeholder<BoundTy>, BoundTy>,
489 mapped_consts: FxIndexMap<PlaceholderConst, BoundConst>,
490 universe_indices: &'a [Option<UniverseIndex>],
491 value: T,
492 ) -> T {
493 let mut replacer = PlaceholderReplacer {
494 infcx,
495 mapped_regions,
496 mapped_types,
497 mapped_consts,
498 universe_indices,
499 current_index: INNERMOST,
500 };
501 value.fold_with(&mut replacer)
502 }
503}
504
505impl<'db> TypeFolder<DbInterner<'db>> for PlaceholderReplacer<'_, 'db> {
506 fn cx(&self) -> DbInterner<'db> {
507 self.infcx.interner
508 }
509
510 fn fold_binder<T: TypeFoldable<DbInterner<'db>>>(
511 &mut self,
512 t: Binder<'db, T>,
513 ) -> Binder<'db, T> {
514 if !t.has_placeholders() && !t.has_infer() {
515 return t;
516 }
517 self.current_index.shift_in(1);
518 let t = t.super_fold_with(self);
519 self.current_index.shift_out(1);
520 t
521 }
522
523 fn fold_region(&mut self, r0: Region<'db>) -> Region<'db> {
524 let r1 = match r0.kind() {
525 RegionKind::ReVar(vid) => self
526 .infcx
527 .inner
528 .borrow_mut()
529 .unwrap_region_constraints()
530 .opportunistic_resolve_var(self.infcx.interner, vid),
531 _ => r0,
532 };
533
534 let r2 = match r1.kind() {
535 RegionKind::RePlaceholder(p) => {
536 let replace_var = self.mapped_regions.get(&p);
537 match replace_var {
538 Some(replace_var) => {
539 let index = self
540 .universe_indices
541 .iter()
542 .position(|u| matches!(u, Some(pu) if *pu == p.universe))
543 .unwrap_or_else(|| panic!("Unexpected placeholder universe."));
544 let db = DebruijnIndex::from_usize(
545 self.universe_indices.len() - index + self.current_index.as_usize() - 1,
546 );
547 Region::new_bound(self.cx(), db, *replace_var)
548 }
549 None => r1,
550 }
551 }
552 _ => r1,
553 };
554
555 tracing::debug!(?r0, ?r1, ?r2, "fold_region");
556
557 r2
558 }
559
560 fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
561 let ty = self.infcx.shallow_resolve(ty);
562 match ty.kind() {
563 TyKind::Placeholder(p) => {
564 let replace_var = self.mapped_types.get(&p);
565 match replace_var {
566 Some(replace_var) => {
567 let index = self
568 .universe_indices
569 .iter()
570 .position(|u| matches!(u, Some(pu) if *pu == p.universe))
571 .unwrap_or_else(|| panic!("Unexpected placeholder universe."));
572 let db = DebruijnIndex::from_usize(
573 self.universe_indices.len() - index + self.current_index.as_usize() - 1,
574 );
575 Ty::new_bound(self.infcx.interner, db, *replace_var)
576 }
577 None => {
578 if ty.has_infer() {
579 ty.super_fold_with(self)
580 } else {
581 ty
582 }
583 }
584 }
585 }
586
587 _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self),
588 _ => ty,
589 }
590 }
591
592 fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
593 let ct = self.infcx.shallow_resolve_const(ct);
594 if let ConstKind::Placeholder(p) = ct.kind() {
595 let replace_var = self.mapped_consts.get(&p);
596 match replace_var {
597 Some(replace_var) => {
598 let index = self
599 .universe_indices
600 .iter()
601 .position(|u| matches!(u, Some(pu) if *pu == p.universe))
602 .unwrap_or_else(|| panic!("Unexpected placeholder universe."));
603 let db = DebruijnIndex::from_usize(
604 self.universe_indices.len() - index + self.current_index.as_usize() - 1,
605 );
606 Const::new_bound(self.infcx.interner, db, *replace_var)
607 }
608 None => {
609 if ct.has_infer() {
610 ct.super_fold_with(self)
611 } else {
612 ct
613 }
614 }
615 }
616 } else {
617 ct.super_fold_with(self)
618 }
619 }
620}
621
622pub fn sizedness_fast_path<'db>(
623 tcx: DbInterner<'db>,
624 predicate: Predicate<'db>,
625 param_env: ParamEnv<'db>,
626) -> bool {
627 if let PredicateKind::Clause(ClauseKind::Trait(trait_pred)) = predicate.kind().skip_binder()
631 && trait_pred.polarity == PredicatePolarity::Positive
632 {
633 let sizedness = match tcx.as_trait_lang_item(trait_pred.def_id()) {
634 Some(SolverTraitLangItem::Sized) => SizedTraitKind::Sized,
635 Some(SolverTraitLangItem::MetaSized) => SizedTraitKind::MetaSized,
636 _ => return false,
637 };
638
639 if matches!(sizedness, SizedTraitKind::MetaSized) {
643 return true;
644 }
645
646 if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) {
647 tracing::debug!("fast path -- trivial sizedness");
648 return true;
649 }
650
651 if matches!(trait_pred.self_ty().kind(), TyKind::Param(_) | TyKind::Placeholder(_)) {
652 for clause in param_env.caller_bounds().iter() {
653 if let ClauseKind::Trait(clause_pred) = clause.kind().skip_binder()
654 && clause_pred.polarity == PredicatePolarity::Positive
655 && clause_pred.self_ty() == trait_pred.self_ty()
656 && (clause_pred.def_id() == trait_pred.def_id()
657 || (sizedness == SizedTraitKind::MetaSized
658 && tcx.is_trait_lang_item(
659 clause_pred.def_id(),
660 SolverTraitLangItem::Sized,
661 )))
662 {
663 return true;
664 }
665 }
666 }
667 }
668
669 false
670}
671
672pub(crate) fn upcast_choices<'db>(
676 interner: DbInterner<'db>,
677 source_trait_ref: PolyTraitRef<'db>,
678 target_trait_def_id: TraitId,
679) -> Vec<PolyTraitRef<'db>> {
680 if source_trait_ref.def_id().0 == target_trait_def_id {
681 return vec![source_trait_ref]; }
683
684 elaborate::supertraits(interner, source_trait_ref)
685 .filter(|r| r.def_id().0 == target_trait_def_id)
686 .collect()
687}
688
689#[inline]
690pub(crate) fn clauses_as_obligations<'db>(
691 clauses: impl IntoIterator<Item = Clause<'db>>,
692 cause: ObligationCause,
693 param_env: ParamEnv<'db>,
694) -> impl Iterator<Item = PredicateObligation<'db>> {
695 clauses.into_iter().map(move |clause| Obligation {
696 cause: cause.clone(),
697 param_env,
698 predicate: clause.as_predicate(),
699 recursion_depth: 0,
700 })
701}