about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-05-28 12:38:39 -0400
committerNiko Matsakis <niko@alum.mit.edu>2018-05-28 19:47:05 -0400
commit7e15e0baffac2a4d613ae0340a98b04307f3c123 (patch)
tree2bd003ccef1cdf50746833356799b2e83ce1afd6
parent8f15d1ea255a8d0bddd6194aefe5cfee0434e0a1 (diff)
downloadrust-7e15e0baffac2a4d613ae0340a98b04307f3c123.tar.gz
rust-7e15e0baffac2a4d613ae0340a98b04307f3c123.zip
remove use of depth from `TyS` and replace with a debruijn index
Co-authored-by: csmoe <35686186+csmoe@users.noreply.github.com>
-rw-r--r--src/librustc/ty/context.rs4
-rw-r--r--src/librustc/ty/flags.rs36
-rw-r--r--src/librustc/ty/fold.rs37
-rw-r--r--src/librustc/ty/mod.rs23
-rw-r--r--src/librustc/ty/sty.rs4
-rw-r--r--src/librustc_typeck/check/closure.rs4
6 files changed, 74 insertions, 34 deletions
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 2b2da6f842b..f2bdb77ad35 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -181,7 +181,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
             let ty_struct = TyS {
                 sty: st,
                 flags: flags.flags,
-                region_depth: flags.depth,
+                outer_exclusive_binder: flags.outer_exclusive_binder,
             };
 
             // Make sure we don't end up with inference
@@ -205,7 +205,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
             let ty_struct = TyS {
                 sty: st,
                 flags: flags.flags,
-                region_depth: flags.depth,
+                outer_exclusive_binder: flags.outer_exclusive_binder,
             };
 
             // This is safe because all the types the ty_struct can point to
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index e913f8f568a..ebbdc928b5d 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -16,13 +16,16 @@ use ty::{self, Ty, TypeFlags, TypeFoldable};
 pub struct FlagComputation {
     pub flags: TypeFlags,
 
-    // maximum depth of any bound region that we have seen thus far
-    pub depth: u32,
+    // see `TyS::outer_exclusive_binder` for details
+    pub outer_exclusive_binder: ty::DebruijnIndex,
 }
 
 impl FlagComputation {
     fn new() -> FlagComputation {
-        FlagComputation { flags: TypeFlags::empty(), depth: 0 }
+        FlagComputation {
+            flags: TypeFlags::empty(),
+            outer_exclusive_binder: ty::DebruijnIndex::INNERMOST,
+        }
     }
 
     pub fn for_sty(st: &ty::TypeVariants) -> FlagComputation {
@@ -35,10 +38,17 @@ impl FlagComputation {
         self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
     }
 
-    fn add_depth(&mut self, depth: u32) {
-        if depth > self.depth {
-            self.depth = depth;
-        }
+    /// indicates that `self` refers to something at binding level `binder`
+    fn add_binder(&mut self, binder: ty::DebruijnIndex) {
+        let exclusive_binder = binder.shifted_in(1);
+        self.add_exclusive_binder(exclusive_binder);
+    }
+
+    /// indicates that `self` refers to something *inside* binding
+    /// level `binder` -- not bound by `binder`, but bound by the next
+    /// binder internal to it
+    fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
+        self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
     }
 
     /// Adds the flags/depth from a set of types that appear within the current type, but within a
@@ -49,9 +59,11 @@ impl FlagComputation {
         // The types that contributed to `computation` occurred within
         // a region binder, so subtract one from the region depth
         // within when adding the depth to `self`.
-        let depth = computation.depth;
-        if depth > 0 {
-            self.add_depth(depth - 1);
+        let outer_exclusive_binder = computation.outer_exclusive_binder;
+        if outer_exclusive_binder > ty::DebruijnIndex::INNERMOST {
+            self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
+        } else {
+            // otherwise, this binder captures nothing
         }
     }
 
@@ -194,7 +206,7 @@ impl FlagComputation {
 
     fn add_ty(&mut self, ty: Ty) {
         self.add_flags(ty.flags);
-        self.add_depth(ty.region_depth);
+        self.add_exclusive_binder(ty.outer_exclusive_binder);
     }
 
     fn add_tys(&mut self, tys: &[Ty]) {
@@ -215,7 +227,7 @@ impl FlagComputation {
     fn add_region(&mut self, r: ty::Region) {
         self.add_flags(r.type_flags());
         if let ty::ReLateBound(debruijn, _) = *r {
-            self.add_depth(debruijn.depth);
+            self.add_binder(debruijn);
         }
     }
 
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index f1a7add784e..dea33ca6947 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -63,20 +63,22 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
         self.super_visit_with(visitor)
     }
 
-    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_regions_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
+        self.visit_with(&mut HasEscapingRegionsVisitor { outer_index: binder })
+    }
+
+    /// True if this `self` has any regions that escape `binder` (and
+    /// hence are not bound by it).
+    fn has_regions_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
+        self.has_regions_bound_at_or_above(binder.shifted_in(1))
     }
 
     fn has_escaping_regions(&self) -> bool {
-        self.has_regions_escaping_depth(0)
+        self.has_regions_bound_at_or_above(ty::DebruijnIndex::INNERMOST)
     }
 
     fn has_type_flags(&self, flags: TypeFlags) -> bool {
@@ -523,7 +525,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> {
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if !t.has_regions_bound_by_or_escaping(self.current_index) {
+        if !t.has_regions_bound_at_or_above(self.current_index) {
             return t;
         }
 
@@ -623,23 +625,32 @@ pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 /// represent the scope to which it is attached, etc. An escaping region represents a bound region
 /// for which this processing has not yet been done.
 struct HasEscapingRegionsVisitor {
-    depth: u32,
+    /// Anything bound by `outer_index` or "above" is escaping
+    outer_index: ty::DebruijnIndex,
 }
 
 impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor {
     fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
-        self.depth += 1;
+        self.outer_index.shift_in(1);
         let result = t.super_visit_with(self);
-        self.depth -= 1;
+        self.outer_index.shift_out(1);
         result
     }
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
-        t.region_depth > self.depth
+        // If the outer-exclusive-binder is *strictly greater* than
+        // `outer_index`, that means that `t` contains some content
+        // bound at `outer_index` or above (because
+        // `outer_exclusive_binder` is always 1 higher than the
+        // content in `t`). Therefore, `t` has some escaping regions.
+        t.outer_exclusive_binder > self.outer_index
     }
 
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
-        r.escapes_depth(self.depth)
+        // If the region is bound by `outer_index` or anything outside
+        // of outer index, then it escapes the binders we have
+        // visited.
+        r.bound_at_or_above_binder(self.outer_index)
     }
 }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 775c7c234fd..646c60c139c 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -488,8 +488,24 @@ pub struct TyS<'tcx> {
     pub sty: TypeVariants<'tcx>,
     pub flags: TypeFlags,
 
-    // the maximal depth of any bound regions appearing in this type.
-    region_depth: u32,
+    /// This is a kind of confusing thing: it stores the smallest
+    /// binder such that
+    ///
+    /// (a) the binder itself captures nothing but
+    /// (b) all the late-bound things within the type are captured
+    ///     by some sub-binder.
+    ///
+    /// So, for a type without any late-bound things, like `u32`, this
+    /// will be INNERMOST, because that is the innermost binder that
+    /// captures nothing. But for a type `&'D u32`, where `'D` is a
+    /// late-bound region with debruijn index D, this would be D+1 --
+    /// the binder itself does not capture D, but D is captured by an
+    /// inner binder.
+    ///
+    /// We call this concept an "exclusive" binder D (because all
+    /// debruijn indices within the type are contained within `0..D`
+    /// (exclusive)).
+    outer_exclusive_binder: ty::DebruijnIndex,
 }
 
 impl<'tcx> Ord for TyS<'tcx> {
@@ -560,7 +576,8 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::TyS<'gcx> {
             // The other fields just provide fast access to information that is
             // also contained in `sty`, so no need to hash them.
             flags: _,
-            region_depth: _,
+
+            outer_exclusive_binder: _,
         } = *self;
 
         sty.hash_stable(hcx, hasher);
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 275540b9efe..b03930432a9 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -1332,9 +1332,9 @@ impl RegionKind {
         }
     }
 
-    pub fn escapes_depth(&self, depth: u32) -> bool {
+    pub fn bound_at_or_above_binder(&self, index: DebruijnIndex) -> bool {
         match *self {
-            ty::ReLateBound(debruijn, _) => debruijn.depth > depth,
+            ty::ReLateBound(debruijn, _) => debruijn >= index,
             _ => false,
         }
     }
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index a7cdcae9c07..67245bec7fb 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -19,8 +19,8 @@ use rustc::infer::LateBoundRegionConversionTime;
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::traits::error_reporting::ArgKind;
 use rustc::ty::{self, ToPolyTraitRef, Ty, GenericParamDefKind};
+use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::Substs;
-use rustc::ty::TypeFoldable;
 use std::cmp;
 use std::iter;
 use rustc_target::spec::abi::Abi;
@@ -465,7 +465,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Create a `PolyFnSig`. Note the oddity that late bound
         // regions appearing free in `expected_sig` are now bound up
         // in this binder we are creating.
-        assert!(!expected_sig.sig.has_regions_escaping_depth(1));
+        assert!(!expected_sig.sig.has_regions_bound_above(ty::DebruijnIndex::INNERMOST));
         let bound_sig = ty::Binder::bind(self.tcx.mk_fn_sig(
             expected_sig.sig.inputs().iter().cloned(),
             expected_sig.sig.output(),