Skip to content

Commit 39b9bea

Browse files
author
Ariel Ben-Yehuda
committed
Skip useless recursion in freshening and late-bound-region substitutio
Before: 581.72user 4.75system 7:42.74elapsed 126%CPU (0avgtext+0avgdata 1176224maxresident)k llvm took 359.183 After: 550.63user 5.09system 7:20.28elapsed 126%CPU (0avgtext+0avgdata 1165516maxresident)k llvm took 354.801
1 parent 717e883 commit 39b9bea

File tree

6 files changed

+129
-76
lines changed

6 files changed

+129
-76
lines changed

src/librustc/middle/infer/freshen.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
104104
}
105105

106106
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
107+
if !ty::type_needs_infer(t) && !ty::type_has_erasable_regions(t) {
108+
return t;
109+
}
110+
107111
let tcx = self.infcx.tcx;
108112

109113
match t.sty {

src/librustc/middle/infer/higher_ranked/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
530530
* details.
531531
*/
532532

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

src/librustc/middle/infer/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ use middle::free_region::FreeRegionMap;
2626
use middle::subst;
2727
use middle::subst::Substs;
2828
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
29-
use middle::ty::replace_late_bound_regions;
3029
use middle::ty::{self, Ty};
31-
use middle::ty_fold::{TypeFolder, TypeFoldable};
30+
use middle::ty_fold::{self, TypeFolder, TypeFoldable};
3231
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
3332
use rustc_data_structures::unify::{self, UnificationTable};
3433
use std::cell::{RefCell};
@@ -1038,7 +1037,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10381037
-> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
10391038
where T : TypeFoldable<'tcx> + Repr<'tcx>
10401039
{
1041-
ty::replace_late_bound_regions(
1040+
ty_fold::replace_late_bound_regions(
10421041
self.tcx,
10431042
value,
10441043
|br| self.next_region_var(LateBoundRegion(span, br, lbrct)))

src/librustc/middle/ty.rs

Lines changed: 31 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -806,29 +806,31 @@ impl<'tcx> ctxt<'tcx> {
806806
// recursing over the type itself.
807807
bitflags! {
808808
flags TypeFlags: u32 {
809-
const HAS_PARAMS = 1 << 0,
810-
const HAS_SELF = 1 << 1,
811-
const HAS_TY_INFER = 1 << 2,
812-
const HAS_RE_INFER = 1 << 3,
813-
const HAS_RE_LATE_BOUND = 1 << 4,
814-
const HAS_REGIONS = 1 << 5,
815-
const HAS_TY_ERR = 1 << 6,
816-
const HAS_PROJECTION = 1 << 7,
817-
const HAS_TY_CLOSURE = 1 << 8,
818-
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
819-
TypeFlags::HAS_SELF.bits |
820-
TypeFlags::HAS_REGIONS.bits,
809+
const HAS_PARAMS = 1 << 0,
810+
const HAS_SELF = 1 << 1,
811+
const HAS_TY_INFER = 1 << 2,
812+
const HAS_RE_INFER = 1 << 3,
813+
const HAS_RE_EARLY_BOUND = 1 << 4,
814+
const HAS_FREE_REGIONS = 1 << 5,
815+
const HAS_TY_ERR = 1 << 6,
816+
const HAS_PROJECTION = 1 << 7,
817+
const HAS_TY_CLOSURE = 1 << 8,
818+
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
819+
TypeFlags::HAS_SELF.bits |
820+
TypeFlags::HAS_RE_EARLY_BOUND.bits,
821821

822822
// Flags representing the nominal content of a type,
823-
// computed by FlagsComputetion
823+
// computed by FlagsComputation. If you add a new nominal
824+
// flag, it should be added here too.
824825
const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits |
825826
TypeFlags::HAS_SELF.bits |
826827
TypeFlags::HAS_TY_INFER.bits |
827828
TypeFlags::HAS_RE_INFER.bits |
828-
TypeFlags::HAS_RE_LATE_BOUND.bits |
829-
TypeFlags::HAS_REGIONS.bits |
829+
TypeFlags::HAS_RE_EARLY_BOUND.bits |
830+
TypeFlags::HAS_FREE_REGIONS.bits |
830831
TypeFlags::HAS_TY_ERR.bits |
831-
TypeFlags::HAS_PROJECTION.bits,
832+
TypeFlags::HAS_PROJECTION.bits |
833+
TypeFlags::HAS_TY_CLOSURE.bits,
832834

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

993-
pub fn type_has_late_bound_regions(ty: Ty) -> bool {
994-
ty.flags.get().intersects(TypeFlags::HAS_RE_LATE_BOUND)
995+
pub fn type_has_erasable_regions(ty: Ty) -> bool {
996+
ty.flags.get().intersects(TypeFlags::HAS_RE_EARLY_BOUND |
997+
TypeFlags::HAS_RE_INFER |
998+
TypeFlags::HAS_FREE_REGIONS)
995999
}
9961000

9971001
/// An "escaping region" is a bound region whose binder is not part of `t`.
@@ -2987,7 +2991,7 @@ impl FlagComputation {
29872991
for projection_bound in &bounds.projection_bounds {
29882992
let mut proj_computation = FlagComputation::new();
29892993
proj_computation.add_projection_predicate(&projection_bound.0);
2990-
computation.add_bound_computation(&proj_computation);
2994+
self.add_bound_computation(&proj_computation);
29912995
}
29922996
self.add_bound_computation(&computation);
29932997

@@ -3041,14 +3045,12 @@ impl FlagComputation {
30413045
}
30423046

30433047
fn add_region(&mut self, r: Region) {
3044-
self.add_flags(TypeFlags::HAS_REGIONS);
30453048
match r {
30463049
ty::ReInfer(_) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
3047-
ty::ReLateBound(debruijn, _) => {
3048-
self.add_flags(TypeFlags::HAS_RE_LATE_BOUND);
3049-
self.add_depth(debruijn.depth);
3050-
}
3051-
_ => { }
3050+
ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
3051+
ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
3052+
ty::ReStatic => {}
3053+
_ => { self.add_flags(TypeFlags::HAS_FREE_REGIONS); }
30523054
}
30533055
}
30543056

@@ -6994,7 +6996,7 @@ pub fn liberate_late_bound_regions<'tcx, T>(
69946996
-> T
69956997
where T : TypeFoldable<'tcx> + Repr<'tcx>
69966998
{
6997-
replace_late_bound_regions(
6999+
ty_fold::replace_late_bound_regions(
69987000
tcx, value,
69997001
|br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0
70007002
}
@@ -7005,7 +7007,7 @@ pub fn count_late_bound_regions<'tcx, T>(
70057007
-> usize
70067008
where T : TypeFoldable<'tcx> + Repr<'tcx>
70077009
{
7008-
let (_, skol_map) = replace_late_bound_regions(tcx, value, |_| ty::ReStatic);
7010+
let (_, skol_map) = ty_fold::replace_late_bound_regions(tcx, value, |_| ty::ReStatic);
70097011
skol_map.len()
70107012
}
70117013

@@ -7063,7 +7065,7 @@ pub fn erase_late_bound_regions<'tcx, T>(
70637065
-> T
70647066
where T : TypeFoldable<'tcx> + Repr<'tcx>
70657067
{
7066-
replace_late_bound_regions(tcx, value, |_| ty::ReStatic).0
7068+
ty_fold::replace_late_bound_regions(tcx, value, |_| ty::ReStatic).0
70677069
}
70687070

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

7090-
/// Replaces the late-bound-regions in `value` that are bound by `value`.
7091-
pub fn replace_late_bound_regions<'tcx, T, F>(
7092-
tcx: &ty::ctxt<'tcx>,
7093-
binder: &Binder<T>,
7094-
mut mapf: F)
7095-
-> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
7096-
where T : TypeFoldable<'tcx> + Repr<'tcx>,
7097-
F : FnMut(BoundRegion) -> ty::Region,
7098-
{
7099-
debug!("replace_late_bound_regions({})", binder.repr(tcx));
7100-
7101-
let mut map = FnvHashMap();
7102-
7103-
// Note: fold the field `0`, not the binder, so that late-bound
7104-
// regions bound by `binder` are considered free.
7105-
let value = ty_fold::fold_regions(tcx, &binder.0, |region, current_depth| {
7106-
debug!("region={}", region.repr(tcx));
7107-
match region {
7108-
ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => {
7109-
let region = *map.entry(br).or_insert_with(|| mapf(br));
7110-
7111-
if let ty::ReLateBound(debruijn1, br) = region {
7112-
// If the callback returns a late-bound region,
7113-
// that region should always use depth 1. Then we
7114-
// adjust it to the correct depth.
7115-
assert_eq!(debruijn1.depth, 1);
7116-
ty::ReLateBound(debruijn, br)
7117-
} else {
7118-
region
7119-
}
7120-
}
7121-
_ => {
7122-
region
7123-
}
7124-
}
7125-
});
7126-
7127-
debug!("resulting map: {:?} value: {:?}", map, value.repr(tcx));
7128-
(value, map)
7129-
}
7130-
71317092
impl DebruijnIndex {
71327093
pub fn new(depth: u32) -> DebruijnIndex {
71337094
assert!(depth > 0);

src/librustc/middle/ty_fold.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use std::rc::Rc;
4242
use syntax::abi;
4343
use syntax::ast;
4444
use syntax::owned_slice::OwnedSlice;
45+
use util::nodemap::FnvHashMap;
4546
use util::ppaux::Repr;
4647

4748
///////////////////////////////////////////////////////////////////////////
@@ -841,6 +842,86 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
841842
}
842843
}
843844

845+
///////////////////////////////////////////////////////////////////////////
846+
// Late-bound region replacer
847+
848+
// Replaces the escaping regions in a type.
849+
850+
struct RegionReplacer<'a, 'tcx: 'a> {
851+
tcx: &'a ty::ctxt<'tcx>,
852+
current_depth: u32,
853+
fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region + 'a),
854+
map: FnvHashMap<ty::BoundRegion, ty::Region>
855+
}
856+
857+
impl<'a, 'tcx> RegionReplacer<'a, 'tcx> {
858+
fn new<F>(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionReplacer<'a, 'tcx>
859+
where F : FnMut(ty::BoundRegion) -> ty::Region
860+
{
861+
RegionReplacer {
862+
tcx: tcx,
863+
current_depth: 1,
864+
fld_r: fld_r,
865+
map: FnvHashMap()
866+
}
867+
}
868+
}
869+
870+
pub fn replace_late_bound_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
871+
value: &ty::Binder<T>,
872+
mut f: F)
873+
-> (T, FnvHashMap<ty::BoundRegion, ty::Region>)
874+
where F : FnMut(ty::BoundRegion) -> ty::Region,
875+
T : TypeFoldable<'tcx> + Repr<'tcx>,
876+
{
877+
debug!("replace_late_bound_regions({})", value.repr(tcx));
878+
let mut replacer = RegionReplacer::new(tcx, &mut f);
879+
let result = value.skip_binder().fold_with(&mut replacer);
880+
(result, replacer.map)
881+
}
882+
883+
impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx>
884+
{
885+
fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
886+
887+
fn enter_region_binder(&mut self) {
888+
self.current_depth += 1;
889+
}
890+
891+
fn exit_region_binder(&mut self) {
892+
self.current_depth -= 1;
893+
}
894+
895+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
896+
if !ty::type_escapes_depth(t, self.current_depth-1) {
897+
return t;
898+
}
899+
900+
super_fold_ty(self, t)
901+
}
902+
903+
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
904+
match r {
905+
ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
906+
debug!("RegionReplacer.fold_region({}) folding region (current_depth={})",
907+
r.repr(self.tcx()), self.current_depth);
908+
let fld_r = &mut self.fld_r;
909+
let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
910+
if let ty::ReLateBound(debruijn1, br) = region {
911+
// If the callback returns a late-bound region,
912+
// that region should always use depth 1. Then we
913+
// adjust it to the correct depth.
914+
assert_eq!(debruijn1.depth, 1);
915+
ty::ReLateBound(debruijn, br)
916+
} else {
917+
region
918+
}
919+
}
920+
r => r
921+
}
922+
}
923+
}
924+
844925
///////////////////////////////////////////////////////////////////////////
845926
// Region eraser
846927
//
@@ -861,6 +942,14 @@ pub fn erase_regions<'tcx, T: TypeFoldable<'tcx>>(tcx: &ty::ctxt<'tcx>, t: T) ->
861942
impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
862943
fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
863944

945+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
946+
if !ty::type_has_erasable_regions(t) {
947+
return t;
948+
}
949+
950+
super_fold_ty(self, t)
951+
}
952+
864953
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
865954
// because whether or not a region is bound affects subtyping,
866955
// we can't erase the bound/free distinction, but we can

src/librustc/util/ppaux.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use middle::ty::{ty_param, ty_ptr, ty_rptr, ty_tup};
2424
use middle::ty::ty_closure;
2525
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
2626
use middle::ty;
27-
use middle::ty_fold::TypeFoldable;
27+
use middle::ty_fold::{self, TypeFoldable};
2828

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

0 commit comments

Comments
 (0)