Skip to content

Commit 4b1d3b7

Browse files
committed
rewrite free_region/region_inference to use newly minted
`TransitiveRelation`
1 parent 5e126e4 commit 4b1d3b7

File tree

2 files changed

+61
-59
lines changed

2 files changed

+61
-59
lines changed

src/librustc/middle/free_region.rs

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,18 @@
1010

1111
//! This file defines
1212
13+
use middle::ty::{self, FreeRegion, Region};
1314
use middle::wf::ImpliedBound;
14-
use middle::ty::{self, FreeRegion};
15-
use util::common::can_reach;
16-
use util::nodemap::{FnvHashMap, FnvHashSet};
15+
use rustc_data_structures::transitive_relation::TransitiveRelation;
1716

1817
#[derive(Clone)]
1918
pub struct FreeRegionMap {
20-
/// `map` maps from a free region `a` to a list of
21-
/// free regions `bs` such that `a <= b for all b in bs`
22-
map: FnvHashMap<FreeRegion, Vec<FreeRegion>>,
23-
/// regions that are required to outlive (and therefore be
24-
/// equal to) 'static.
25-
statics: FnvHashSet<FreeRegion>
19+
relation: TransitiveRelation<Region>
2620
}
2721

2822
impl FreeRegionMap {
2923
pub fn new() -> FreeRegionMap {
30-
FreeRegionMap { map: FnvHashMap(), statics: FnvHashSet() }
24+
FreeRegionMap { relation: TransitiveRelation::new() }
3125
}
3226

3327
pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self,
@@ -84,22 +78,38 @@ impl FreeRegionMap {
8478
}
8579

8680
fn relate_to_static(&mut self, sup: FreeRegion) {
87-
self.statics.insert(sup);
81+
self.relation.add(ty::ReStatic, ty::ReFree(sup));
8882
}
8983

9084
fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
91-
let mut sups = self.map.entry(sub).or_insert(Vec::new());
92-
if !sups.contains(&sup) {
93-
sups.push(sup);
94-
}
85+
self.relation.add(ty::ReFree(sub), ty::ReFree(sup))
9586
}
9687

9788
/// Determines whether two free regions have a subregion relationship
9889
/// by walking the graph encoded in `map`. Note that
9990
/// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
10091
/// (that is, the user can give two different names to the same lifetime).
10192
pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
102-
can_reach(&self.map, sub, sup) || self.is_static(&sup)
93+
let result = sub == sup || {
94+
let sub = ty::ReFree(sub);
95+
let sup = ty::ReFree(sup);
96+
self.relation.contains(&sub, &sup) || self.relation.contains(&sup, &ty::ReStatic)
97+
};
98+
debug!("sub_free_region(sub={:?}, sup={:?}) = {:?}", sub, sup, result);
99+
result
100+
}
101+
102+
pub fn lub_free_regions(&self, fr_a: FreeRegion, fr_b: FreeRegion) -> Region {
103+
let r_a = ty::ReFree(fr_a);
104+
let r_b = ty::ReFree(fr_b);
105+
let result = if fr_a == fr_b { r_a } else {
106+
match self.relation.best_upper_bound(&r_a, &r_b) {
107+
None => ty::ReStatic,
108+
Some(r) => *r,
109+
}
110+
};
111+
debug!("lub_free_regions(fr_a={:?}, fr_b={:?}) = {:?}", fr_a, fr_b, result);
112+
result
103113
}
104114

105115
/// Determines whether one region is a subregion of another. This is intended to run *after
@@ -109,10 +119,7 @@ impl FreeRegionMap {
109119
sub_region: ty::Region,
110120
super_region: ty::Region)
111121
-> bool {
112-
debug!("is_subregion_of(sub_region={:?}, super_region={:?})",
113-
sub_region, super_region);
114-
115-
sub_region == super_region || {
122+
let result = sub_region == super_region || {
116123
match (sub_region, super_region) {
117124
(ty::ReEmpty, _) |
118125
(_, ty::ReStatic) =>
@@ -121,23 +128,47 @@ impl FreeRegionMap {
121128
(ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
122129
tcx.region_maps.is_subscope_of(sub_scope, super_scope),
123130

124-
(ty::ReScope(sub_scope), ty::ReFree(ref fr)) =>
125-
tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()),
131+
(ty::ReScope(sub_scope), ty::ReFree(fr)) =>
132+
tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()) ||
133+
self.is_static(fr),
126134

127135
(ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
128136
self.sub_free_region(sub_fr, super_fr),
129137

130-
(ty::ReStatic, ty::ReFree(ref sup_fr)) => self.is_static(sup_fr),
138+
(ty::ReStatic, ty::ReFree(sup_fr)) =>
139+
self.is_static(sup_fr),
131140

132141
_ =>
133142
false,
134143
}
135-
}
144+
};
145+
debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}",
146+
sub_region, super_region, result);
147+
result
136148
}
137149

138150
/// Determines whether this free-region is required to be 'static
139-
pub fn is_static(&self, super_region: &ty::FreeRegion) -> bool {
151+
pub fn is_static(&self, super_region: ty::FreeRegion) -> bool {
140152
debug!("is_static(super_region={:?})", super_region);
141-
self.statics.iter().any(|s| can_reach(&self.map, *s, *super_region))
153+
self.relation.contains(&ty::ReStatic, &ty::ReFree(super_region))
142154
}
143155
}
156+
157+
#[cfg(test)]
158+
fn free_region(index: u32) -> FreeRegion {
159+
use middle::region::DestructionScopeData;
160+
FreeRegion { scope: DestructionScopeData::new(0),
161+
bound_region: ty::BoundRegion::BrAnon(index) }
162+
}
163+
164+
#[test]
165+
fn lub() {
166+
// a very VERY basic test, but see the tests in
167+
// TransitiveRelation, which are much more thorough.
168+
let frs: Vec<_> = (0..3).map(|i| free_region(i)).collect();
169+
let mut map = FreeRegionMap::new();
170+
map.relate_free_regions(frs[0], frs[2]);
171+
map.relate_free_regions(frs[1], frs[2]);
172+
assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2]));
173+
}
174+

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

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -812,8 +812,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
812812
ReScope(self.tcx.region_maps.nearest_common_ancestor(a_id, b_id))
813813
}
814814

815-
(ReFree(ref a_fr), ReFree(ref b_fr)) => {
816-
self.lub_free_regions(free_regions, a_fr, b_fr)
815+
(ReFree(a_fr), ReFree(b_fr)) => {
816+
free_regions.lub_free_regions(a_fr, b_fr)
817817
}
818818

819819
// For these types, we cannot define any additional
@@ -825,35 +825,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
825825
}
826826
}
827827

828-
/// Computes a region that encloses both free region arguments. Guarantee that if the same two
829-
/// regions are given as argument, in any order, a consistent result is returned.
830-
fn lub_free_regions(&self,
831-
free_regions: &FreeRegionMap,
832-
a: &FreeRegion,
833-
b: &FreeRegion)
834-
-> ty::Region
835-
{
836-
return match a.cmp(b) {
837-
Less => helper(self, free_regions, a, b),
838-
Greater => helper(self, free_regions, b, a),
839-
Equal => ty::ReFree(*a)
840-
};
841-
842-
fn helper(_this: &RegionVarBindings,
843-
free_regions: &FreeRegionMap,
844-
a: &FreeRegion,
845-
b: &FreeRegion) -> ty::Region
846-
{
847-
if free_regions.sub_free_region(*a, *b) {
848-
ty::ReFree(*b)
849-
} else if free_regions.sub_free_region(*b, *a) {
850-
ty::ReFree(*a)
851-
} else {
852-
ty::ReStatic
853-
}
854-
}
855-
}
856-
857828
fn glb_concrete_regions(&self,
858829
free_regions: &FreeRegionMap,
859830
a: Region,
@@ -892,8 +863,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
892863
b));
893864
}
894865

895-
(ReFree(ref fr), ReScope(s_id)) |
896-
(ReScope(s_id), ReFree(ref fr)) => {
866+
(ReFree(fr), ReScope(s_id)) |
867+
(ReScope(s_id), ReFree(fr)) => {
897868
let s = ReScope(s_id);
898869
// Free region is something "at least as big as
899870
// `fr.scope_id`." If we find that the scope `fr.scope_id` is bigger

0 commit comments

Comments
 (0)