10
10
11
11
use infer:: outlives:: free_region_map:: FreeRegionMap ;
12
12
use infer:: { GenericKind , InferCtxt } ;
13
- use traits:: query:: outlives_bounds:: { self , OutlivesBound } ;
14
- use ty:: { self , Ty } ;
15
-
13
+ use rustc_data_structures:: fx:: FxHashMap ;
16
14
use syntax:: ast;
17
15
use syntax_pos:: Span ;
16
+ use traits:: query:: outlives_bounds:: { self , OutlivesBound } ;
17
+ use ty:: { self , Ty } ;
18
18
19
19
/// The `OutlivesEnvironment` collects information about what outlives
20
20
/// what in a given type-checking setting. For example, if we have a
@@ -39,15 +39,51 @@ use syntax_pos::Span;
39
39
pub struct OutlivesEnvironment < ' tcx > {
40
40
param_env : ty:: ParamEnv < ' tcx > ,
41
41
free_region_map : FreeRegionMap < ' tcx > ,
42
- region_bound_pairs : Vec < ( ty:: Region < ' tcx > , GenericKind < ' tcx > ) > ,
42
+
43
+ // Contains, for each body B that we are checking (that is, the fn
44
+ // item, but also any nested closures), the set of implied region
45
+ // bounds that are in scope in that particular body.
46
+ //
47
+ // Example:
48
+ //
49
+ // ```
50
+ // fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) {
51
+ // bar(x, y, |y: &'b T| { .. } // body B1)
52
+ // } // body B0
53
+ // ```
54
+ //
55
+ // Here, for body B0, the list would be `[T: 'a]`, because we
56
+ // infer that `T` must outlive `'a` from the implied bounds on the
57
+ // fn declaration.
58
+ //
59
+ // For the body B1, the list would be `[T: 'a, T: 'b]`, because we
60
+ // also can see that -- within the closure body! -- `T` must
61
+ // outlive `'b`. This is not necessarily true outside the closure
62
+ // body, since the closure may never be called.
63
+ //
64
+ // We collect this map as we descend the tree. We then use the
65
+ // results when proving outlives obligations like `T: 'x` later
66
+ // (e.g., if `T: 'x` must be proven within the body B1, then we
67
+ // know it is true if either `'a: 'x` or `'b: 'x`).
68
+ region_bound_pairs_map : FxHashMap < ast:: NodeId , RegionBoundPairs < ' tcx > > ,
69
+
70
+ // Used to compute `region_bound_pairs_map`: contains the set of
71
+ // in-scope region-bound pairs thus far.
72
+ region_bound_pairs_accum : RegionBoundPairs < ' tcx > ,
43
73
}
44
74
75
+ /// "Region-bound pairs" tracks outlives relations that are known to
76
+ /// be true, either because of explicit where clauses like `T: 'a` or
77
+ /// because of implied bounds.
78
+ pub type RegionBoundPairs < ' tcx > = Vec < ( ty:: Region < ' tcx > , GenericKind < ' tcx > ) > ;
79
+
45
80
impl < ' a , ' gcx : ' tcx , ' tcx : ' a > OutlivesEnvironment < ' tcx > {
46
81
pub fn new ( param_env : ty:: ParamEnv < ' tcx > ) -> Self {
47
82
let mut env = OutlivesEnvironment {
48
83
param_env,
49
84
free_region_map : FreeRegionMap :: new ( ) ,
50
- region_bound_pairs : vec ! [ ] ,
85
+ region_bound_pairs_map : FxHashMap :: default ( ) ,
86
+ region_bound_pairs_accum : vec ! [ ] ,
51
87
} ;
52
88
53
89
env. add_outlives_bounds ( None , outlives_bounds:: explicit_outlives_bounds ( param_env) ) ;
@@ -62,7 +98,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
62
98
63
99
/// Borrows current value of the `region_bound_pairs`.
64
100
pub fn region_bound_pairs ( & self ) -> & [ ( ty:: Region < ' tcx > , GenericKind < ' tcx > ) ] {
65
- & self . region_bound_pairs
101
+ & self . region_bound_pairs_accum
66
102
}
67
103
68
104
/// Returns ownership of the `free_region_map`.
@@ -108,12 +144,12 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
108
144
/// similar leaks around givens that seem equally suspicious, to
109
145
/// be honest. --nmatsakis
110
146
pub fn push_snapshot_pre_closure ( & self ) -> usize {
111
- self . region_bound_pairs . len ( )
147
+ self . region_bound_pairs_accum . len ( )
112
148
}
113
149
114
150
/// See `push_snapshot_pre_closure`.
115
151
pub fn pop_snapshot_post_closure ( & mut self , len : usize ) {
116
- self . region_bound_pairs . truncate ( len) ;
152
+ self . region_bound_pairs_accum . truncate ( len) ;
117
153
}
118
154
119
155
/// This method adds "implied bounds" into the outlives environment.
@@ -149,6 +185,15 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
149
185
}
150
186
}
151
187
188
+ /// Save the current set of region-bound pairs under the given `body_id`.
189
+ pub fn save_implied_bounds ( & mut self , body_id : ast:: NodeId ) {
190
+ let old = self . region_bound_pairs_map . insert (
191
+ body_id,
192
+ self . region_bound_pairs_accum . clone ( ) ,
193
+ ) ;
194
+ assert ! ( old. is_none( ) ) ;
195
+ }
196
+
152
197
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
153
198
///
154
199
/// The `infcx` parameter is optional; if the implied bounds may
@@ -174,11 +219,11 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
174
219
. add_given ( r_a, vid_b) ;
175
220
}
176
221
OutlivesBound :: RegionSubParam ( r_a, param_b) => {
177
- self . region_bound_pairs
222
+ self . region_bound_pairs_accum
178
223
. push ( ( r_a, GenericKind :: Param ( param_b) ) ) ;
179
224
}
180
225
OutlivesBound :: RegionSubProjection ( r_a, projection_b) => {
181
- self . region_bound_pairs
226
+ self . region_bound_pairs_accum
182
227
. push ( ( r_a, GenericKind :: Projection ( projection_b) ) ) ;
183
228
}
184
229
OutlivesBound :: RegionSubRegion ( r_a, r_b) => {
0 commit comments