Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/next_solver/fold.rs')
-rw-r--r--crates/hir-ty/src/next_solver/fold.rs64
1 files changed, 63 insertions, 1 deletions
diff --git a/crates/hir-ty/src/next_solver/fold.rs b/crates/hir-ty/src/next_solver/fold.rs
index f776b6ecfc..7836419e8b 100644
--- a/crates/hir-ty/src/next_solver/fold.rs
+++ b/crates/hir-ty/src/next_solver/fold.rs
@@ -5,7 +5,7 @@ use rustc_type_ir::{
TypeVisitableExt, inherent::IntoKind,
};
-use crate::next_solver::BoundConst;
+use crate::next_solver::{BoundConst, FxIndexMap};
use super::{
Binder, BoundRegion, BoundTy, Const, ConstKind, DbInterner, Predicate, Region, Ty, TyKind,
@@ -158,3 +158,65 @@ pub fn fold_tys<'db, T: TypeFoldable<DbInterner<'db>>>(
t.fold_with(&mut Folder { interner, callback })
}
+
+impl<'db> DbInterner<'db> {
+ /// Replaces all regions bound by the given `Binder` with the
+ /// results returned by the closure; the closure is expected to
+ /// return a free region (relative to this binder), and hence the
+ /// binder is removed in the return type. The closure is invoked
+ /// once for each unique `BoundRegionKind`; multiple references to the
+ /// same `BoundRegionKind` will reuse the previous result. A map is
+ /// returned at the end with each bound region and the free region
+ /// that replaced it.
+ ///
+ /// # Panics
+ ///
+ /// This method only replaces late bound regions. Any types or
+ /// constants bound by `value` will cause an ICE.
+ pub fn instantiate_bound_regions<T, F>(
+ self,
+ value: Binder<'db, T>,
+ mut fld_r: F,
+ ) -> (T, FxIndexMap<BoundRegion, Region<'db>>)
+ where
+ F: FnMut(BoundRegion) -> Region<'db>,
+ T: TypeFoldable<DbInterner<'db>>,
+ {
+ let mut region_map = FxIndexMap::default();
+ let real_fld_r = |br: BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br));
+ let value = self.instantiate_bound_regions_uncached(value, real_fld_r);
+ (value, region_map)
+ }
+
+ pub fn instantiate_bound_regions_uncached<T, F>(
+ self,
+ value: Binder<'db, T>,
+ mut replace_regions: F,
+ ) -> T
+ where
+ F: FnMut(BoundRegion) -> Region<'db>,
+ T: TypeFoldable<DbInterner<'db>>,
+ {
+ let value = value.skip_binder();
+ if !value.has_escaping_bound_vars() {
+ value
+ } else {
+ let delegate = FnMutDelegate {
+ regions: &mut replace_regions,
+ types: &mut |b| panic!("unexpected bound ty in binder: {b:?}"),
+ consts: &mut |b| panic!("unexpected bound ct in binder: {b:?}"),
+ };
+ let mut replacer = BoundVarReplacer::new(self, delegate);
+ value.fold_with(&mut replacer)
+ }
+ }
+
+ /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also
+ /// method lookup and a few other places where precise region relationships are not required.
+ pub fn instantiate_bound_regions_with_erased<T>(self, value: Binder<'db, T>) -> T
+ where
+ T: TypeFoldable<DbInterner<'db>>,
+ {
+ self.instantiate_bound_regions(value, |_| Region::new_erased(self)).0
+ }
+}