8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- //! This file defines
12
-
11
+ //! This file handles the relationships between free regions --
12
+ //! meaning lifetime parameters. Ordinarily, free regions are
13
+ //! unrelated to one another, but they can be related vai implied or
14
+ //! explicit bounds. In that case, we track the bounds using the
15
+ //! `TransitiveRelation` type and use that to decide when one free
16
+ //! region outlives another and so forth.
17
+
18
+ use middle:: ty:: { self , FreeRegion , Region } ;
13
19
use middle:: wf:: ImpliedBound ;
14
- use middle:: ty:: { self , FreeRegion } ;
15
- use util:: common:: can_reach;
16
- use util:: nodemap:: { FnvHashMap , FnvHashSet } ;
20
+ use rustc_data_structures:: transitive_relation:: TransitiveRelation ;
17
21
18
22
#[ derive( Clone ) ]
19
23
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 >
24
+ // Stores the relation `a < b`, where `a` and `b` are regions.
25
+ relation : TransitiveRelation < Region >
26
26
}
27
27
28
28
impl FreeRegionMap {
29
29
pub fn new ( ) -> FreeRegionMap {
30
- FreeRegionMap { map : FnvHashMap ( ) , statics : FnvHashSet ( ) }
30
+ FreeRegionMap { relation : TransitiveRelation :: new ( ) }
31
31
}
32
32
33
33
pub fn relate_free_regions_from_implied_bounds < ' tcx > ( & mut self ,
@@ -84,22 +84,38 @@ impl FreeRegionMap {
84
84
}
85
85
86
86
fn relate_to_static ( & mut self , sup : FreeRegion ) {
87
- self . statics . insert ( sup) ;
87
+ self . relation . add ( ty :: ReStatic , ty :: ReFree ( sup) ) ;
88
88
}
89
89
90
90
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
- }
91
+ self . relation . add ( ty:: ReFree ( sub) , ty:: ReFree ( sup) )
95
92
}
96
93
97
94
/// Determines whether two free regions have a subregion relationship
98
95
/// by walking the graph encoded in `map`. Note that
99
96
/// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
100
97
/// (that is, the user can give two different names to the same lifetime).
101
98
pub fn sub_free_region ( & self , sub : FreeRegion , sup : FreeRegion ) -> bool {
102
- can_reach ( & self . map , sub, sup) || self . is_static ( & sup)
99
+ let result = sub == sup || {
100
+ let sub = ty:: ReFree ( sub) ;
101
+ let sup = ty:: ReFree ( sup) ;
102
+ self . relation . contains ( & sub, & sup) || self . relation . contains ( & ty:: ReStatic , & sup)
103
+ } ;
104
+ debug ! ( "sub_free_region(sub={:?}, sup={:?}) = {:?}" , sub, sup, result) ;
105
+ result
106
+ }
107
+
108
+ pub fn lub_free_regions ( & self , fr_a : FreeRegion , fr_b : FreeRegion ) -> Region {
109
+ let r_a = ty:: ReFree ( fr_a) ;
110
+ let r_b = ty:: ReFree ( fr_b) ;
111
+ let result = if fr_a == fr_b { r_a } else {
112
+ match self . relation . postdom_upper_bound ( & r_a, & r_b) {
113
+ None => ty:: ReStatic ,
114
+ Some ( r) => * r,
115
+ }
116
+ } ;
117
+ debug ! ( "lub_free_regions(fr_a={:?}, fr_b={:?}) = {:?}" , fr_a, fr_b, result) ;
118
+ result
103
119
}
104
120
105
121
/// Determines whether one region is a subregion of another. This is intended to run *after
@@ -109,10 +125,7 @@ impl FreeRegionMap {
109
125
sub_region : ty:: Region ,
110
126
super_region : ty:: Region )
111
127
-> bool {
112
- debug ! ( "is_subregion_of(sub_region={:?}, super_region={:?})" ,
113
- sub_region, super_region) ;
114
-
115
- sub_region == super_region || {
128
+ let result = sub_region == super_region || {
116
129
match ( sub_region, super_region) {
117
130
( ty:: ReEmpty , _) |
118
131
( _, ty:: ReStatic ) =>
@@ -121,23 +134,47 @@ impl FreeRegionMap {
121
134
( ty:: ReScope ( sub_scope) , ty:: ReScope ( super_scope) ) =>
122
135
tcx. region_maps . is_subscope_of ( sub_scope, super_scope) ,
123
136
124
- ( ty:: ReScope ( sub_scope) , ty:: ReFree ( ref fr) ) =>
125
- tcx. region_maps . is_subscope_of ( sub_scope, fr. scope . to_code_extent ( ) ) ,
137
+ ( ty:: ReScope ( sub_scope) , ty:: ReFree ( fr) ) =>
138
+ tcx. region_maps . is_subscope_of ( sub_scope, fr. scope . to_code_extent ( ) ) ||
139
+ self . is_static ( fr) ,
126
140
127
141
( ty:: ReFree ( sub_fr) , ty:: ReFree ( super_fr) ) =>
128
142
self . sub_free_region ( sub_fr, super_fr) ,
129
143
130
- ( ty:: ReStatic , ty:: ReFree ( ref sup_fr) ) => self . is_static ( sup_fr) ,
144
+ ( ty:: ReStatic , ty:: ReFree ( sup_fr) ) =>
145
+ self . is_static ( sup_fr) ,
131
146
132
147
_ =>
133
148
false ,
134
149
}
135
- }
150
+ } ;
151
+ debug ! ( "is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}" ,
152
+ sub_region, super_region, result) ;
153
+ result
136
154
}
137
155
138
156
/// Determines whether this free-region is required to be 'static
139
- pub fn is_static ( & self , super_region : & ty:: FreeRegion ) -> bool {
157
+ pub fn is_static ( & self , super_region : ty:: FreeRegion ) -> bool {
140
158
debug ! ( "is_static(super_region={:?})" , super_region) ;
141
- self . statics . iter ( ) . any ( |s| can_reach ( & self . map , * s , * super_region) )
159
+ self . relation . contains ( & ty :: ReStatic , & ty :: ReFree ( super_region) )
142
160
}
143
161
}
162
+
163
+ #[ cfg( test) ]
164
+ fn free_region ( index : u32 ) -> FreeRegion {
165
+ use middle:: region:: DestructionScopeData ;
166
+ FreeRegion { scope : DestructionScopeData :: new ( 0 ) ,
167
+ bound_region : ty:: BoundRegion :: BrAnon ( index) }
168
+ }
169
+
170
+ #[ test]
171
+ fn lub ( ) {
172
+ // a very VERY basic test, but see the tests in
173
+ // TransitiveRelation, which are much more thorough.
174
+ let frs: Vec < _ > = ( 0 ..3 ) . map ( |i| free_region ( i) ) . collect ( ) ;
175
+ let mut map = FreeRegionMap :: new ( ) ;
176
+ map. relate_free_regions ( frs[ 0 ] , frs[ 2 ] ) ;
177
+ map. relate_free_regions ( frs[ 1 ] , frs[ 2 ] ) ;
178
+ assert_eq ! ( map. lub_free_regions( frs[ 0 ] , frs[ 1 ] ) , ty:: ReFree ( frs[ 2 ] ) ) ;
179
+ }
180
+
0 commit comments