88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
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 } ;
1319use 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 ;
1721
1822#[ derive( Clone ) ]
1923pub 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 >
2626}
2727
2828impl FreeRegionMap {
2929 pub fn new ( ) -> FreeRegionMap {
30- FreeRegionMap { map : FnvHashMap ( ) , statics : FnvHashSet ( ) }
30+ FreeRegionMap { relation : TransitiveRelation :: new ( ) }
3131 }
3232
3333 pub fn relate_free_regions_from_implied_bounds < ' tcx > ( & mut self ,
@@ -84,22 +84,38 @@ impl FreeRegionMap {
8484 }
8585
8686 fn relate_to_static ( & mut self , sup : FreeRegion ) {
87- self . statics . insert ( sup) ;
87+ self . relation . add ( ty :: ReStatic , ty :: ReFree ( sup) ) ;
8888 }
8989
9090 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) )
9592 }
9693
9794 /// Determines whether two free regions have a subregion relationship
9895 /// by walking the graph encoded in `map`. Note that
9996 /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
10097 /// (that is, the user can give two different names to the same lifetime).
10198 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
103119 }
104120
105121 /// Determines whether one region is a subregion of another. This is intended to run *after
@@ -109,10 +125,7 @@ impl FreeRegionMap {
109125 sub_region : ty:: Region ,
110126 super_region : ty:: Region )
111127 -> 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 || {
116129 match ( sub_region, super_region) {
117130 ( ty:: ReEmpty , _) |
118131 ( _, ty:: ReStatic ) =>
@@ -121,23 +134,47 @@ impl FreeRegionMap {
121134 ( ty:: ReScope ( sub_scope) , ty:: ReScope ( super_scope) ) =>
122135 tcx. region_maps . is_subscope_of ( sub_scope, super_scope) ,
123136
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) ,
126140
127141 ( ty:: ReFree ( sub_fr) , ty:: ReFree ( super_fr) ) =>
128142 self . sub_free_region ( sub_fr, super_fr) ,
129143
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) ,
131146
132147 _ =>
133148 false ,
134149 }
135- }
150+ } ;
151+ debug ! ( "is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}" ,
152+ sub_region, super_region, result) ;
153+ result
136154 }
137155
138156 /// 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 {
140158 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) )
142160 }
143161}
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