diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2018-05-25 09:58:29 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2018-05-28 19:47:03 -0400 |
| commit | 9c5a45044af4dd6b7d539b57be120ef158da9c84 (patch) | |
| tree | 67b10f880347e33878cca48b2bba48d3d904246d | |
| parent | 69ab6f2995cf445df7016f89f54220e7438f4f37 (diff) | |
| download | rust-9c5a45044af4dd6b7d539b57be120ef158da9c84.tar.gz rust-9c5a45044af4dd6b7d539b57be120ef158da9c84.zip | |
port `fold_regions` and friends to use debruijn indices directly
They no longer talk about plain integers. Co-authored-by: csmoe <35686186+csmoe@users.noreply.github.com>
| -rw-r--r-- | src/librustc/infer/higher_ranked/mod.rs | 8 | ||||
| -rw-r--r-- | src/librustc/ty/fold.rs | 108 | ||||
| -rw-r--r-- | src/librustc/ty/sty.rs | 56 | ||||
| -rw-r--r-- | src/librustc_typeck/check/generator_interior.rs | 3 |
4 files changed, 125 insertions, 50 deletions
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index acd5c44c1a4..47fc8d96b55 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -473,7 +473,7 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, _ => true }); - fldr(region, ty::DebruijnIndex::new(current_depth)) + fldr(region, current_depth) }) } @@ -734,7 +734,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // trait checking, and all of the skolemized regions // appear inside predicates, which always have // binders, so this assert is satisfied. - assert!(current_depth > 1); + assert!(current_depth > ty::DebruijnIndex::INNERMOST); // since leak-check passed, this skolemized region // should only have incoming edges from variables @@ -750,7 +750,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { r, br); self.tcx.mk_region(ty::ReLateBound( - ty::DebruijnIndex::new(current_depth - 1), br.clone())) + current_depth.shifted_out(1), + br.clone(), + )) } } }); diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 4cd12bfe5f4..df8fd102cc5 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -66,6 +66,15 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn has_regions_escaping_depth(&self, depth: u32) -> bool { self.visit_with(&mut HasEscapingRegionsVisitor { depth: depth }) } + + /// True if `self` has any late-bound regions that are either + /// bound by `binder` or bound by some binder outside of `binder`. + /// If `binder` is `ty::DebruijnIndex::INNERMOST`, this indicates whether + /// there are any late-bound regions that appear free. + fn has_regions_bound_by_or_escaping(&self, binder: ty::DebruijnIndex) -> bool { + self.has_regions_escaping_depth(binder.depth - 1) + } + fn has_escaping_regions(&self) -> bool { self.has_regions_escaping_depth(0) } @@ -207,7 +216,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { let mut have_bound_regions = false; self.fold_regions(value, &mut have_bound_regions, |r, d| { - region_set.insert(self.mk_region(r.from_depth(d))); + region_set.insert(self.mk_region(r.shifted_out_to_binder(d))); r }); have_bound_regions @@ -216,13 +225,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Folds the escaping and free regions in `value` using `f`, and /// sets `skipped_regions` to true if any late-bound region was found /// and skipped. - pub fn fold_regions<T,F>(self, + pub fn fold_regions<T>( + self, value: &T, skipped_regions: &mut bool, - mut f: F) - -> T - where F : FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx>, - T : TypeFoldable<'tcx>, + mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, + ) -> T + where + T : TypeFoldable<'tcx>, { value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)) } @@ -277,21 +287,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub struct RegionFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, skipped_regions: &'a mut bool, - current_depth: u32, - fld_r: &'a mut (dyn FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx> + 'a), + + /// Stores the index of a binder *just outside* the stuff we have + /// visited. So this begins as INNERMOST; when we pass through a + /// binder, it is incremented (via `shift_in`). + current_index: ty::DebruijnIndex, + + /// Callback invokes for each free region. The `DebruijnIndex` + /// points to the binder *just outside* the ones we have passed + /// through. + fold_region_fn: &'a mut (dyn FnMut( + ty::Region<'tcx>, + ty::DebruijnIndex, + ) -> ty::Region<'tcx> + 'a), } impl<'a, 'gcx, 'tcx> RegionFolder<'a, 'gcx, 'tcx> { - pub fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - skipped_regions: &'a mut bool, - fld_r: &'a mut F) -> RegionFolder<'a, 'gcx, 'tcx> - where F : FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx> - { + pub fn new( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + skipped_regions: &'a mut bool, + fold_region_fn: &'a mut dyn FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, + ) -> RegionFolder<'a, 'gcx, 'tcx> { RegionFolder { tcx, skipped_regions, - current_depth: 1, - fld_r, + current_index: ty::DebruijnIndex::INNERMOST, + fold_region_fn, } } } @@ -300,24 +321,24 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> { - self.current_depth += 1; + self.current_index.shift_in(1); let t = t.super_fold_with(self); - self.current_depth -= 1; + self.current_index.shift_out(1); t } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { - ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => { - debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})", - r, self.current_depth); + ty::ReLateBound(debruijn, _) if debruijn < self.current_index => { + debug!("RegionFolder.fold_region({:?}) skipped bound region (current index={:?})", + r, self.current_index); *self.skipped_regions = true; r } _ => { - debug!("RegionFolder.fold_region({:?}) folding free region (current_depth={})", - r, self.current_depth); - (self.fld_r)(r, self.current_depth) + debug!("RegionFolder.fold_region({:?}) folding free region (current_index={:?})", + r, self.current_index); + (self.fold_region_fn)(r, self.current_index) } } } @@ -330,7 +351,11 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> { struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, - current_depth: u32, + + /// As with `RegionFolder`, represents the index of a binder *just outside* + /// the ones we have visited. + current_index: ty::DebruijnIndex, + fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>> } @@ -372,20 +397,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }).0 } - /// Flattens two binding levels into one. So `for<'a> for<'b> Foo` + /// Flattens multiple binding levels into one. So `for<'a> for<'b> Foo` /// becomes `for<'a,'b> Foo`. pub fn flatten_late_bound_regions<T>(self, bound2_value: &Binder<Binder<T>>) -> Binder<T> where T: TypeFoldable<'tcx> { let bound0_value = bound2_value.skip_binder().skip_binder(); - let value = self.fold_regions(bound0_value, &mut false, - |region, current_depth| { + let value = self.fold_regions(bound0_value, &mut false, |region, current_depth| { match *region { - ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => { - // should be true if no escaping regions from bound2_value - assert!(debruijn.depth - current_depth <= 1); - self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br)) + ty::ReLateBound(debruijn, br) => { + // We assume no regions bound *outside* of the + // binders in `bound2_value` (nmatsakis added in + // the course of this PR; seems like a reasonable + // sanity check though). + assert!(debruijn == current_depth); + self.mk_region(ty::ReLateBound(current_depth, br)) } _ => { region @@ -446,7 +473,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let mut counter = 0; Binder::bind(self.replace_late_bound_regions(sig, |_| { counter += 1; - self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter))) + self.mk_region(ty::ReLateBound(ty::DebruijnIndex::INNERMOST, ty::BrAnon(counter))) }).0) } } @@ -458,7 +485,7 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { { RegionReplacer { tcx, - current_depth: 1, + current_index: ty::DebruijnIndex::INNERMOST, fld_r, map: BTreeMap::default() } @@ -469,14 +496,14 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> { - self.current_depth += 1; + self.current_index.shift_in(1); let t = t.super_fold_with(self); - self.current_depth -= 1; + self.current_index.shift_out(1); t } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.has_regions_escaping_depth(self.current_depth-1) { + if !t.has_regions_bound_by_or_escaping(self.current_index) { return t; } @@ -485,14 +512,15 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { - ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => { + ty::ReLateBound(debruijn, br) if debruijn == self.current_index => { let fld_r = &mut self.fld_r; let region = *self.map.entry(br).or_insert_with(|| fld_r(br)); if let ty::ReLateBound(debruijn1, br) = *region { // If the callback returns a late-bound region, - // that region should always use depth 1. Then we - // adjust it to the correct depth. - assert_eq!(debruijn1.depth, 1); + // that region should always use the INNERMOST + // debruijn index. Then we adjust it to the + // correct depth. + assert_eq!(debruijn1, ty::DebruijnIndex::INNERMOST); self.tcx.mk_region(ty::ReLateBound(debruijn, br)) } else { region diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 59178604996..7e45d8a2269 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1259,6 +1259,8 @@ impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { } impl DebruijnIndex { + pub const INNERMOST: DebruijnIndex = DebruijnIndex { depth: 1 }; + pub fn new(depth: u32) -> DebruijnIndex { assert!(depth > 0); DebruijnIndex { depth: depth } @@ -1296,6 +1298,30 @@ impl DebruijnIndex { pub fn shift_out(&mut self, amount: u32) { *self = self.shifted_out(amount); } + + /// Adjusts any Debruijn Indices so as to make `to_binder` the + /// innermost binder. That is, if we have something bound at `to_binder`, + /// it will now be bound at INNERMOST. This is an appropriate thing to do + /// when moving a region out from inside binders: + /// + /// ``` + /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) + /// // Binder: D3 D2 D1 ^^ + /// ``` + /// + /// Here, the region `'a` would have the debruijn index D3, + /// because it is the bound 3 binders out. However, if we wanted + /// to refer to that region `'a` in the second argument (the `_`), + /// those two binders would not be in scope. In that case, we + /// might invoke `shift_out_to_binder(D3)`. This would adjust the + /// debruijn index of `'a` to D1 (the innermost binder). + /// + /// If we invoke `shift_out_to_binder` and the region is in fact + /// bound by one of the binders we are shifting out of, that is an + /// error (and should fail an assertion failure). + pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self { + self.shifted_out(to_binder.depth - Self::INNERMOST.depth) + } } /// Region utilities @@ -1314,12 +1340,32 @@ impl RegionKind { } } - /// Returns the depth of `self` from the (1-based) binding level `depth` - pub fn from_depth(&self, depth: u32) -> RegionKind { + /// Adjusts any Debruijn Indices so as to make `to_binder` the + /// innermost binder. That is, if we have something bound at `to_binder`, + /// it will now be bound at INNERMOST. This is an appropriate thing to do + /// when moving a region out from inside binders: + /// + /// ``` + /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) + /// // Binder: D3 D2 D1 ^^ + /// ``` + /// + /// Here, the region `'a` would have the debruijn index D3, + /// because it is the bound 3 binders out. However, if we wanted + /// to refer to that region `'a` in the second argument (the `_`), + /// those two binders would not be in scope. In that case, we + /// might invoke `shift_out_to_binder(D3)`. This would adjust the + /// debruijn index of `'a` to D1 (the innermost binder). + /// + /// If we invoke `shift_out_to_binder` and the region is in fact + /// bound by one of the binders we are shifting out of, that is an + /// error (and should fail an assertion failure). + pub fn shifted_out_to_binder(&self, to_binder: ty::DebruijnIndex) -> RegionKind { match *self { - ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex { - depth: debruijn.depth - (depth - 1) - }, r), + ty::ReLateBound(debruijn, r) => ty::ReLateBound( + debruijn.shifted_out_to_binder(to_binder), + r, + ), r => r } } diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index b3d2a09a72c..e234e2f0192 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -125,8 +125,7 @@ pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, let mut counter = 0; let type_list = fcx.tcx.fold_regions(&type_list, &mut false, |_, current_depth| { counter += 1; - fcx.tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(current_depth), - ty::BrAnon(counter))) + fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter))) }); let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind(type_list)); |
