Skip to content

Commit

Permalink
remove use of depth from TyS and replace with a debruijn index
Browse files Browse the repository at this point in the history
Co-authored-by: csmoe <35686186+csmoe@users.noreply.github.com>
  • Loading branch information
nikomatsakis and csmoe committed May 28, 2018
1 parent 8f15d1e commit 7e15e0b
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 34 deletions.
4 changes: 2 additions & 2 deletions src/librustc/ty/context.rs
Expand Up @@ -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
Expand All @@ -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
Expand Down
36 changes: 24 additions & 12 deletions src/librustc/ty/flags.rs
Expand Up @@ -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 {
Expand All @@ -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
Expand All @@ -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
}
}

Expand Down Expand Up @@ -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]) {
Expand All @@ -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);
}
}

Expand Down
37 changes: 24 additions & 13 deletions src/librustc/ty/fold.rs
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
}
}

Expand Down
23 changes: 20 additions & 3 deletions src/librustc/ty/mod.rs
Expand Up @@ -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> {
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ty/sty.rs
Expand Up @@ -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,
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_typeck/check/closure.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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(),
Expand Down

0 comments on commit 7e15e0b

Please sign in to comment.