10
10
11
11
//! This file defines
12
12
13
+ use middle:: ty:: { self , FreeRegion , Region } ;
13
14
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 ;
17
16
18
17
#[ derive( Clone ) ]
19
18
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 >
26
20
}
27
21
28
22
impl FreeRegionMap {
29
23
pub fn new ( ) -> FreeRegionMap {
30
- FreeRegionMap { map : FnvHashMap ( ) , statics : FnvHashSet ( ) }
24
+ FreeRegionMap { relation : TransitiveRelation :: new ( ) }
31
25
}
32
26
33
27
pub fn relate_free_regions_from_implied_bounds < ' tcx > ( & mut self ,
@@ -84,22 +78,38 @@ impl FreeRegionMap {
84
78
}
85
79
86
80
fn relate_to_static ( & mut self , sup : FreeRegion ) {
87
- self . statics . insert ( sup) ;
81
+ self . relation . add ( ty :: ReStatic , ty :: ReFree ( sup) ) ;
88
82
}
89
83
90
84
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) )
95
86
}
96
87
97
88
/// Determines whether two free regions have a subregion relationship
98
89
/// by walking the graph encoded in `map`. Note that
99
90
/// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
100
91
/// (that is, the user can give two different names to the same lifetime).
101
92
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
103
113
}
104
114
105
115
/// Determines whether one region is a subregion of another. This is intended to run *after
@@ -109,10 +119,7 @@ impl FreeRegionMap {
109
119
sub_region : ty:: Region ,
110
120
super_region : ty:: Region )
111
121
-> 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 || {
116
123
match ( sub_region, super_region) {
117
124
( ty:: ReEmpty , _) |
118
125
( _, ty:: ReStatic ) =>
@@ -121,23 +128,47 @@ impl FreeRegionMap {
121
128
( ty:: ReScope ( sub_scope) , ty:: ReScope ( super_scope) ) =>
122
129
tcx. region_maps . is_subscope_of ( sub_scope, super_scope) ,
123
130
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) ,
126
134
127
135
( ty:: ReFree ( sub_fr) , ty:: ReFree ( super_fr) ) =>
128
136
self . sub_free_region ( sub_fr, super_fr) ,
129
137
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) ,
131
140
132
141
_ =>
133
142
false ,
134
143
}
135
- }
144
+ } ;
145
+ debug ! ( "is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}" ,
146
+ sub_region, super_region, result) ;
147
+ result
136
148
}
137
149
138
150
/// 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 {
140
152
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) )
142
154
}
143
155
}
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
+
0 commit comments