Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audit all uses of ty_walk #26667

Merged
merged 5 commits into from
Jun 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions src/librustc/middle/infer/higher_ranked/mod.rs
Original file line number Diff line number Diff line change
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
24 changes: 12 additions & 12 deletions src/librustc/middle/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,16 +421,18 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
// regions. If there are, we will call this obligation an
// error. Eventually we should be able to support some
// cases here, I imagine (e.g., `for<'a> int : 'a`).
if selcx.tcx().count_late_bound_regions(binder) != 0 {
errors.push(
FulfillmentError::new(
obligation.clone(),
CodeSelectionError(Unimplemented)));
} else {
let ty::OutlivesPredicate(t_a, r_b) = binder.0;
register_region_obligation(t_a, r_b,
obligation.cause.clone(),
region_obligations);
match selcx.tcx().no_late_bound_regions(binder) {
None => {
errors.push(
FulfillmentError::new(
obligation.clone(),
CodeSelectionError(Unimplemented)))
}
Some(ty::OutlivesPredicate(t_a, r_b)) => {
register_region_obligation(t_a, r_b,
obligation.cause.clone(),
region_obligations);
}
}
true
}
Expand Down Expand Up @@ -501,5 +503,3 @@ impl<'tcx> FulfilledPredicates<'tcx> {
!self.set.insert(p.clone())
}
}


106 changes: 36 additions & 70 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
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 @@ -6897,27 +6853,15 @@ impl<'tcx> ctxt<'tcx> {
|br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0
}

pub fn count_late_bound_regions<T>(&self, value: &Binder<T>) -> usize
where T : TypeFoldable<'tcx>
{
let (_, skol_map) = ty_fold::replace_late_bound_regions(self, value, |_| ty::ReStatic);
skol_map.len()
}

pub fn binds_late_bound_regions<T>(&self, value: &Binder<T>) -> bool
where T : TypeFoldable<'tcx>
{
self.count_late_bound_regions(value) > 0
}

/// Flattens two 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 = 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 All @@ -6933,9 +6877,9 @@ impl<'tcx> ctxt<'tcx> {
}

pub fn no_late_bound_regions<T>(&self, value: &Binder<T>) -> Option<T>
where T : TypeFoldable<'tcx>
where T : TypeFoldable<'tcx> + RegionEscape
{
if self.binds_late_bound_regions(value) {
if value.0.has_escaping_regions() {
None
} else {
Some(value.0.clone())
Expand Down Expand Up @@ -7095,6 +7039,19 @@ impl<'tcx> RegionEscape for Substs<'tcx> {
}
}

impl<T:RegionEscape> RegionEscape for Vec<T> {
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
self.iter().any(|t| t.has_regions_escaping_depth(depth))
}
}

impl<'tcx> RegionEscape for FnSig<'tcx> {
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
self.inputs.has_regions_escaping_depth(depth) ||
self.output.has_regions_escaping_depth(depth)
}
}

impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
self.iter_enumerated().any(|(space, _, t)| {
Expand Down Expand Up @@ -7167,6 +7124,15 @@ impl<'tcx,T:RegionEscape> RegionEscape for Binder<T> {
}
}

impl<'tcx> RegionEscape for FnOutput<'tcx> {
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
match *self {
FnConverging(t) => t.has_regions_escaping_depth(depth),
FnDiverging => false
}
}
}

impl<'tcx> RegionEscape for EquatePredicate<'tcx> {
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
Expand Down
30 changes: 22 additions & 8 deletions src/librustc/middle/ty_fold.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading