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

Skip useless recursion in freshening and late-bound-region substitution #26055

Merged
merged 1 commit into from
Jun 10, 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
4 changes: 4 additions & 0 deletions src/librustc/middle/infer/freshen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
}

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !ty::type_needs_infer(t) && !ty::type_has_erasable_regions(t) {
return t;
}

let tcx = self.infcx.tcx;

match t.sty {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/infer/higher_ranked/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
* details.
*/

let (result, map) = ty::replace_late_bound_regions(infcx.tcx, binder, |br| {
let (result, map) = ty_fold::replace_late_bound_regions(infcx.tcx, binder, |br| {
infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot)
});

Expand Down
5 changes: 2 additions & 3 deletions src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ use middle::free_region::FreeRegionMap;
use middle::subst;
use middle::subst::Substs;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
use middle::ty::replace_late_bound_regions;
use middle::ty::{self, Ty};
use middle::ty_fold::{TypeFolder, TypeFoldable};
use middle::ty_fold::{self, TypeFolder, TypeFoldable};
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use rustc_data_structures::unify::{self, UnificationTable};
use std::cell::{RefCell};
Expand Down Expand Up @@ -1038,7 +1037,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
ty::replace_late_bound_regions(
ty_fold::replace_late_bound_regions(
self.tcx,
value,
|br| self.next_region_var(LateBoundRegion(span, br, lbrct)))
Expand Down
101 changes: 31 additions & 70 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,29 +806,31 @@ impl<'tcx> ctxt<'tcx> {
// recursing over the type itself.
bitflags! {
flags TypeFlags: u32 {
const HAS_PARAMS = 1 << 0,
const HAS_SELF = 1 << 1,
const HAS_TY_INFER = 1 << 2,
const HAS_RE_INFER = 1 << 3,
const HAS_RE_LATE_BOUND = 1 << 4,
const HAS_REGIONS = 1 << 5,
const HAS_TY_ERR = 1 << 6,
const HAS_PROJECTION = 1 << 7,
const HAS_TY_CLOSURE = 1 << 8,
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_REGIONS.bits,
const HAS_PARAMS = 1 << 0,
const HAS_SELF = 1 << 1,
const HAS_TY_INFER = 1 << 2,
const HAS_RE_INFER = 1 << 3,
const HAS_RE_EARLY_BOUND = 1 << 4,
const HAS_FREE_REGIONS = 1 << 5,
const HAS_TY_ERR = 1 << 6,
const HAS_PROJECTION = 1 << 7,
const HAS_TY_CLOSURE = 1 << 8,
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_RE_EARLY_BOUND.bits,

// Flags representing the nominal content of a type,
// computed by FlagsComputetion
// computed by FlagsComputation. If you add a new nominal
// flag, it should be added here too.
const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_TY_INFER.bits |
TypeFlags::HAS_RE_INFER.bits |
TypeFlags::HAS_RE_LATE_BOUND.bits |
TypeFlags::HAS_REGIONS.bits |
TypeFlags::HAS_RE_EARLY_BOUND.bits |
TypeFlags::HAS_FREE_REGIONS.bits |
TypeFlags::HAS_TY_ERR.bits |
TypeFlags::HAS_PROJECTION.bits,
TypeFlags::HAS_PROJECTION.bits |
TypeFlags::HAS_TY_CLOSURE.bits,

// Caches for type_is_sized, type_moves_by_default
const SIZEDNESS_CACHED = 1 << 16,
Expand Down Expand Up @@ -990,8 +992,10 @@ pub fn type_has_ty_closure(ty: Ty) -> bool {
ty.flags.get().intersects(TypeFlags::HAS_TY_CLOSURE)
}

pub fn type_has_late_bound_regions(ty: Ty) -> bool {
ty.flags.get().intersects(TypeFlags::HAS_RE_LATE_BOUND)
pub fn type_has_erasable_regions(ty: Ty) -> bool {
ty.flags.get().intersects(TypeFlags::HAS_RE_EARLY_BOUND |
TypeFlags::HAS_RE_INFER |
TypeFlags::HAS_FREE_REGIONS)
}

/// An "escaping region" is a bound region whose binder is not part of `t`.
Expand Down Expand Up @@ -2987,7 +2991,7 @@ impl FlagComputation {
for projection_bound in &bounds.projection_bounds {
let mut proj_computation = FlagComputation::new();
proj_computation.add_projection_predicate(&projection_bound.0);
computation.add_bound_computation(&proj_computation);
self.add_bound_computation(&proj_computation);
}
self.add_bound_computation(&computation);

Expand Down Expand Up @@ -3041,14 +3045,12 @@ impl FlagComputation {
}

fn add_region(&mut self, r: Region) {
self.add_flags(TypeFlags::HAS_REGIONS);
match r {
ty::ReInfer(_) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
ty::ReLateBound(debruijn, _) => {
self.add_flags(TypeFlags::HAS_RE_LATE_BOUND);
self.add_depth(debruijn.depth);
}
_ => { }
ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
ty::ReStatic => {}
_ => { self.add_flags(TypeFlags::HAS_FREE_REGIONS); }
}
}

Expand Down Expand Up @@ -6994,7 +6996,7 @@ pub fn liberate_late_bound_regions<'tcx, T>(
-> T
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
replace_late_bound_regions(
ty_fold::replace_late_bound_regions(
tcx, value,
|br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0
}
Expand All @@ -7005,7 +7007,7 @@ pub fn count_late_bound_regions<'tcx, T>(
-> usize
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
let (_, skol_map) = replace_late_bound_regions(tcx, value, |_| ty::ReStatic);
let (_, skol_map) = ty_fold::replace_late_bound_regions(tcx, value, |_| ty::ReStatic);
skol_map.len()
}

Expand Down Expand Up @@ -7063,7 +7065,7 @@ pub fn erase_late_bound_regions<'tcx, T>(
-> T
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
replace_late_bound_regions(tcx, value, |_| ty::ReStatic).0
ty_fold::replace_late_bound_regions(tcx, value, |_| ty::ReStatic).0
}

/// Rewrite any late-bound regions so that they are anonymous. Region numbers are
Expand All @@ -7081,53 +7083,12 @@ pub fn anonymize_late_bound_regions<'tcx, T>(
where T : TypeFoldable<'tcx> + Repr<'tcx>,
{
let mut counter = 0;
ty::Binder(replace_late_bound_regions(tcx, sig, |_| {
ty::Binder(ty_fold::replace_late_bound_regions(tcx, sig, |_| {
counter += 1;
ReLateBound(ty::DebruijnIndex::new(1), BrAnon(counter))
}).0)
}

/// Replaces the late-bound-regions in `value` that are bound by `value`.
pub fn replace_late_bound_regions<'tcx, T, F>(
tcx: &ty::ctxt<'tcx>,
binder: &Binder<T>,
mut mapf: F)
-> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
where T : TypeFoldable<'tcx> + Repr<'tcx>,
F : FnMut(BoundRegion) -> ty::Region,
{
debug!("replace_late_bound_regions({})", binder.repr(tcx));

let mut map = FnvHashMap();

// Note: fold the field `0`, not the binder, so that late-bound
// regions bound by `binder` are considered free.
let value = ty_fold::fold_regions(tcx, &binder.0, |region, current_depth| {
debug!("region={}", region.repr(tcx));
match region {
ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => {
let region = *map.entry(br).or_insert_with(|| mapf(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);
ty::ReLateBound(debruijn, br)
} else {
region
}
}
_ => {
region
}
}
});

debug!("resulting map: {:?} value: {:?}", map, value.repr(tcx));
(value, map)
}

impl DebruijnIndex {
pub fn new(depth: u32) -> DebruijnIndex {
assert!(depth > 0);
Expand Down
89 changes: 89 additions & 0 deletions src/librustc/middle/ty_fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use std::rc::Rc;
use syntax::abi;
use syntax::ast;
use syntax::owned_slice::OwnedSlice;
use util::nodemap::FnvHashMap;
use util::ppaux::Repr;

///////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -841,6 +842,86 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
}
}

///////////////////////////////////////////////////////////////////////////
// Late-bound region replacer

// Replaces the escaping regions in a type.

struct RegionReplacer<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
current_depth: u32,
fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region + 'a),
map: FnvHashMap<ty::BoundRegion, ty::Region>
}

impl<'a, 'tcx> RegionReplacer<'a, 'tcx> {
fn new<F>(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionReplacer<'a, 'tcx>
where F : FnMut(ty::BoundRegion) -> ty::Region
{
RegionReplacer {
tcx: tcx,
current_depth: 1,
fld_r: fld_r,
map: FnvHashMap()
}
}
}

pub fn replace_late_bound_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
value: &ty::Binder<T>,
mut f: F)
-> (T, FnvHashMap<ty::BoundRegion, ty::Region>)
where F : FnMut(ty::BoundRegion) -> ty::Region,
T : TypeFoldable<'tcx> + Repr<'tcx>,
{
debug!("replace_late_bound_regions({})", value.repr(tcx));
let mut replacer = RegionReplacer::new(tcx, &mut f);
let result = value.skip_binder().fold_with(&mut replacer);
(result, replacer.map)
}

impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx>
{
fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }

fn enter_region_binder(&mut self) {
self.current_depth += 1;
}

fn exit_region_binder(&mut self) {
self.current_depth -= 1;
}

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !ty::type_escapes_depth(t, self.current_depth-1) {
return t;
}

super_fold_ty(self, t)
}

fn fold_region(&mut self, r: ty::Region) -> ty::Region {
match r {
ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
debug!("RegionReplacer.fold_region({}) folding region (current_depth={})",
r.repr(self.tcx()), self.current_depth);
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);
ty::ReLateBound(debruijn, br)
} else {
region
}
}
r => r
}
}
}

///////////////////////////////////////////////////////////////////////////
// Region eraser
//
Expand All @@ -861,6 +942,14 @@ pub fn erase_regions<'tcx, T: TypeFoldable<'tcx>>(tcx: &ty::ctxt<'tcx>, t: T) ->
impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !ty::type_has_erasable_regions(t) {
return t;
}

super_fold_ty(self, t)
}

fn fold_region(&mut self, r: ty::Region) -> ty::Region {
// because whether or not a region is bound affects subtyping,
// we can't erase the bound/free distinction, but we can
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use middle::ty::{ty_param, ty_ptr, ty_rptr, ty_tup};
use middle::ty::ty_closure;
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
use middle::ty;
use middle::ty_fold::TypeFoldable;
use middle::ty_fold::{self, TypeFoldable};

use std::collections::HashMap;
use std::collections::hash_state::HashState;
Expand Down Expand Up @@ -1301,7 +1301,7 @@ impl<'tcx, T> UserString<'tcx> for ty::Binder<T>
// the output. We'll probably want to tweak this over time to
// decide just how much information to give.
let mut names = Vec::new();
let (unbound_value, _) = ty::replace_late_bound_regions(tcx, self, |br| {
let (unbound_value, _) = ty_fold::replace_late_bound_regions(tcx, self, |br| {
ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
ty::BrNamed(_, name) => {
names.push(token::get_name(name));
Expand Down