Navigation Menu

Skip to content

Commit

Permalink
Fix lifetime elision region accounting
Browse files Browse the repository at this point in the history
This merges accumulate_regions_in_type with ty_fold::collect_regions.
Fixes #26638
  • Loading branch information
Ariel Ben-Yehuda committed Jun 29, 2015
1 parent a1110bc commit bf164bc
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 179 deletions.
15 changes: 7 additions & 8 deletions src/librustc/middle/infer/higher_ranked/mod.rs
Expand Up @@ -359,7 +359,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
where T: TypeFoldable<'tcx>,
F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
{
unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| {
ty_fold::fold_regions(tcx, unbound_value, &mut false, |region, current_depth| {
// we should only be encountering "escaping" late-bound regions here,
// because the ones at the current level should have been replaced
// with fresh variables
Expand All @@ -369,7 +369,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
});

fldr(region, ty::DebruijnIndex::new(current_depth))
}))
})
}

impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
Expand Down Expand Up @@ -437,11 +437,10 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
let escaping_types =
self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot);

let escaping_region_vars: FnvHashSet<_> =
escaping_types
.iter()
.flat_map(|&t| ty_fold::collect_regions(self.tcx, &t))
.collect();
let mut escaping_region_vars = FnvHashSet();
for ty in &escaping_types {
ty_fold::collect_regions(self.tcx, ty, &mut escaping_region_vars);
}

region_vars.retain(|&region_vid| {
let r = ty::ReInfer(ty::ReVar(region_vid));
Expand Down Expand Up @@ -649,7 +648,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
// binder is that we encountered in `value`. The caller is
// responsible for ensuring that (a) `value` contains at least one
// binder and (b) that binder is the one we want to use.
let result = ty_fold::fold_regions(infcx.tcx, &value, |r, current_depth| {
let result = ty_fold::fold_regions(infcx.tcx, &value, &mut false, |r, current_depth| {
match inv_skol_map.get(&r) {
None => r,
Some(br) => {
Expand Down
67 changes: 12 additions & 55 deletions src/librustc/middle/ty.rs
Expand Up @@ -1713,6 +1713,16 @@ impl Region {
_ => false,
}
}

/// Returns the depth of `self` from the (1-based) binding level `depth`
pub fn from_depth(&self, depth: u32) -> Region {
match *self {
ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex {
depth: debruijn.depth - (depth - 1)
}, r),
r => r
}
}
}

#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
Expand Down Expand Up @@ -6783,60 +6793,6 @@ pub enum ExplicitSelfCategory {
ByBoxExplicitSelfCategory,
}

impl<'tcx> TyS<'tcx> {
/// Pushes all the lifetimes in the given type onto the given list. A
/// "lifetime in a type" is a lifetime specified by a reference or a lifetime
/// in a list of type substitutions. This does *not* traverse into nominal
/// types, nor does it resolve fictitious types.
pub fn accumulate_lifetimes_in_type(&self, accumulator: &mut Vec<ty::Region>) {
for ty in self.walk() {
match ty.sty {
TyRef(region, _) => {
accumulator.push(*region)
}
TyTrait(ref t) => {
accumulator.push_all(t.principal.0.substs.regions().as_slice());
}
TyEnum(_, substs) |
TyStruct(_, substs) => {
accum_substs(accumulator, substs);
}
TyClosure(_, substs) => {
accum_substs(accumulator, substs);
}
TyBool |
TyChar |
TyInt(_) |
TyUint(_) |
TyFloat(_) |
TyBox(_) |
TyStr |
TyArray(_, _) |
TySlice(_) |
TyRawPtr(_) |
TyBareFn(..) |
TyTuple(_) |
TyProjection(_) |
TyParam(_) |
TyInfer(_) |
TyError => {
}
}
}

fn accum_substs(accumulator: &mut Vec<Region>, substs: &Substs) {
match substs.regions {
subst::ErasedRegions => {}
subst::NonerasedRegions(ref regions) => {
for region in regions {
accumulator.push(*region)
}
}
}
}
}
}

/// A free variable referred to in a function.
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct Freevar {
Expand Down Expand Up @@ -6917,7 +6873,8 @@ impl<'tcx> ctxt<'tcx> {
where T: TypeFoldable<'tcx>
{
let bound0_value = bound2_value.skip_binder().skip_binder();
let value = ty_fold::fold_regions(self, bound0_value, |region, current_depth| {
let value = ty_fold::fold_regions(self, 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
Expand Down
30 changes: 22 additions & 8 deletions src/librustc/middle/ty_fold.rs
Expand Up @@ -44,7 +44,7 @@ use std::rc::Rc;
use syntax::abi;
use syntax::ast;
use syntax::owned_slice::OwnedSlice;
use util::nodemap::FnvHashMap;
use util::nodemap::{FnvHashMap, FnvHashSet};

///////////////////////////////////////////////////////////////////////////
// Two generic traits
Expand Down Expand Up @@ -783,38 +783,51 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where

pub struct RegionFolder<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
skipped_regions: &'a mut bool,
current_depth: u32,
fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a),
}

impl<'a, 'tcx> RegionFolder<'a, 'tcx> {
pub fn new<F>(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionFolder<'a, 'tcx>
pub fn new<F>(tcx: &'a ty::ctxt<'tcx>,
skipped_regions: &'a mut bool,
fld_r: &'a mut F) -> RegionFolder<'a, 'tcx>
where F : FnMut(ty::Region, u32) -> ty::Region
{
RegionFolder {
tcx: tcx,
skipped_regions: skipped_regions,
current_depth: 1,
fld_r: fld_r,
}
}
}

pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec<ty::Region>
/// Collects the free and escaping regions in `value` into `region_set`. Returns
/// whether any late-bound regions were skipped
pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>,
value: &T,
region_set: &mut FnvHashSet<ty::Region>) -> bool
where T : TypeFoldable<'tcx>
{
let mut vec = Vec::new();
fold_regions(tcx, value, |r, _| { vec.push(r); r });
vec
let mut have_bound_regions = false;
fold_regions(tcx, value, &mut have_bound_regions,
|r, d| { region_set.insert(r.from_depth(d)); r });
have_bound_regions
}

/// 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<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
value: &T,
skipped_regions: &mut bool,
mut f: F)
-> T
where F : FnMut(ty::Region, u32) -> ty::Region,
T : TypeFoldable<'tcx>,
{
value.fold_with(&mut RegionFolder::new(tcx, &mut f))
value.fold_with(&mut RegionFolder::new(tcx, skipped_regions, &mut f))
}

impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
Expand All @@ -834,6 +847,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => {
debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})",
r, self.current_depth);
*self.skipped_regions = true;
r
}
_ => {
Expand Down Expand Up @@ -989,7 +1003,7 @@ pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>>(tcx: &ty::ctxt<'tcx>,
debug!("shift_regions(value={:?}, amount={})",
value, amount);

value.fold_with(&mut RegionFolder::new(tcx, &mut |region, _current_depth| {
value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| {
shift_region(region, amount)
}))
}
1 change: 1 addition & 0 deletions src/librustc/middle/ty_walk.rs
Expand Up @@ -9,6 +9,7 @@
// except according to those terms.

//! An iterator over the type substructure.
//! WARNING: this does not keep track of the region depth.

use middle::ty::{self, Ty};
use std::iter::Iterator;
Expand Down

0 comments on commit bf164bc

Please sign in to comment.