@@ -26,6 +26,16 @@ pub struct RegionInferenceContext<'tcx> {
26
26
/// from as well as its final inferred value.
27
27
definitions : IndexVec < RegionIndex , RegionDefinition < ' tcx > > ,
28
28
29
+ /// The liveness constraints added to each region. For most
30
+ /// regions, these start out empty and steadily grow, though for
31
+ /// each free region R they start out containing the entire CFG
32
+ /// and `end(R)`.
33
+ liveness_constraints : IndexVec < RegionIndex , Region > ,
34
+
35
+ /// The final inferred values of the inference variables; `None`
36
+ /// until `solve` is invoked.
37
+ inferred_values : Option < IndexVec < RegionIndex , Region > > ,
38
+
29
39
/// The indices of all "free regions" in scope. These are the
30
40
/// lifetime parameters (anonymous and named) declared in the
31
41
/// function signature:
@@ -50,11 +60,6 @@ struct RegionDefinition<'tcx> {
50
60
/// If true, this is a constant region which cannot grow larger.
51
61
/// This is used for named regions as well as `'static`.
52
62
constant : bool ,
53
-
54
- /// The current value of this inference variable. This starts out
55
- /// empty, but grows as we add constraints. The final value is
56
- /// determined when `solve()` is executed.
57
- value : Region ,
58
63
}
59
64
60
65
/// The value of an individual region variable. Region variables
@@ -122,6 +127,8 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
122
127
definitions : ( 0 ..num_region_variables)
123
128
. map ( |_| RegionDefinition :: default ( ) )
124
129
. collect ( ) ,
130
+ liveness_constraints : IndexVec :: from_elem_n ( Region :: default ( ) , num_region_variables) ,
131
+ inferred_values : None ,
125
132
constraints : Vec :: new ( ) ,
126
133
free_regions : Vec :: new ( ) ,
127
134
} ;
@@ -168,33 +175,31 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
168
175
169
176
// Add all nodes in the CFG to `definition.value`.
170
177
for ( block, block_data) in mir. basic_blocks ( ) . iter_enumerated ( ) {
171
- let definition = & mut self . definitions [ variable] ;
178
+ let liveness_constraint = & mut self . liveness_constraints [ variable] ;
172
179
for statement_index in 0 ..block_data. statements . len ( ) + 1 {
173
180
let location = Location {
174
181
block,
175
182
statement_index,
176
183
} ;
177
- definition . value . add_point ( location) ;
184
+ liveness_constraint . add_point ( location) ;
178
185
}
179
186
}
180
187
181
188
// Add `end(X)` into the set for X.
182
- self . definitions [ variable] . value . add_free_region ( variable) ;
189
+ self . liveness_constraints [ variable] . add_free_region ( variable) ;
183
190
184
191
// Go through each region Y that outlives X (i.e., where
185
192
// Y: X is true). Add `end(X)` into the set for `Y`.
186
193
for superregion in free_region_map. regions_that_outlive ( & free_region) {
187
194
let superregion_index = RegionIndex :: new ( indices[ superregion] ) ;
188
- self . definitions [ superregion_index]
189
- . value
190
- . add_free_region ( variable) ;
195
+ self . liveness_constraints [ superregion_index] . add_free_region ( variable) ;
191
196
}
192
197
193
198
debug ! (
194
199
"init_free_regions: region variable for `{:?}` is `{:?}` with value `{:?}`" ,
195
200
free_region,
196
201
variable,
197
- self . definitions [ variable] . value
202
+ self . liveness_constraints [ variable] ,
198
203
) ;
199
204
}
200
205
}
@@ -208,25 +213,25 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
208
213
///
209
214
/// Until `solve()` executes, this value is not particularly meaningful.
210
215
pub fn region_contains_point ( & self , r : RegionIndex , p : Location ) -> bool {
211
- self . definitions [ r] . value . contains_point ( p)
216
+ let inferred_values = self . inferred_values
217
+ . as_ref ( )
218
+ . expect ( "region values not yet inferred" ) ;
219
+ inferred_values[ r] . contains_point ( p)
212
220
}
213
221
214
222
/// Returns access to the value of `r` for debugging purposes.
215
223
pub ( super ) fn region_value ( & self , r : RegionIndex ) -> & fmt:: Debug {
216
- & self . definitions [ r] . value
224
+ let inferred_values = self . inferred_values
225
+ . as_ref ( )
226
+ . expect ( "region values not yet inferred" ) ;
227
+ & inferred_values[ r]
217
228
}
218
229
219
230
/// Indicates that the region variable `v` is live at the point `point`.
220
231
pub ( super ) fn add_live_point ( & mut self , v : RegionIndex , point : Location ) {
221
232
debug ! ( "add_live_point({:?}, {:?})" , v, point) ;
222
- let definition = & mut self . definitions [ v] ;
223
- if !definition. constant {
224
- definition. value . add_point ( point) ;
225
- } else {
226
- // Constants are used for free regions, which already
227
- // contain all the points in the control-flow graph.
228
- assert ! ( definition. value. contains_point( point) ) ;
229
- }
233
+ assert ! ( self . inferred_values. is_none( ) , "values already inferred" ) ;
234
+ self . liveness_constraints [ v] . add_point ( point) ;
230
235
}
231
236
232
237
/// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
@@ -238,6 +243,7 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
238
243
point : Location ,
239
244
) {
240
245
debug ! ( "add_outlives({:?}: {:?} @ {:?}" , sup, sub, point) ;
246
+ assert ! ( self . inferred_values. is_none( ) , "values already inferred" ) ;
241
247
self . constraints . push ( Constraint {
242
248
span,
243
249
sup,
@@ -248,6 +254,7 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
248
254
249
255
/// Perform region inference.
250
256
pub ( super ) fn solve ( & mut self , infcx : & InferCtxt < ' a , ' gcx , ' tcx > , mir : & Mir < ' tcx > ) {
257
+ assert ! ( self . inferred_values. is_none( ) , "values already inferred" ) ;
251
258
let errors = self . propagate_constraints ( mir) ;
252
259
253
260
// worst error msg ever
@@ -267,47 +274,49 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
267
274
/// for each region variable until all the constraints are
268
275
/// satisfied. Note that some values may grow **too** large to be
269
276
/// feasible, but we check this later.
270
- fn propagate_constraints (
271
- & mut self ,
272
- mir : & Mir < ' tcx > ,
273
- ) -> Vec < ( RegionIndex , Span , RegionIndex ) > {
277
+ fn propagate_constraints ( & mut self , mir : & Mir < ' tcx > ) -> Vec < ( RegionIndex , Span , RegionIndex ) > {
274
278
let mut changed = true ;
275
279
let mut dfs = Dfs :: new ( mir) ;
276
280
let mut error_regions = FxHashSet ( ) ;
277
281
let mut errors = vec ! [ ] ;
282
+
283
+ // The initial values for each region are derived from the liveness
284
+ // constraints we have accumulated.
285
+ let mut inferred_values = self . liveness_constraints . clone ( ) ;
286
+
278
287
while changed {
279
288
changed = false ;
280
289
for constraint in & self . constraints {
281
290
debug ! ( "constraint: {:?}" , constraint) ;
282
- let sub = & self . definitions [ constraint. sub ] . value . clone ( ) ;
283
- let sup_def = & mut self . definitions [ constraint. sup ] ;
291
+ let sub = & inferred_values [ constraint. sub ] . clone ( ) ;
292
+ let sup_value = & mut inferred_values [ constraint. sup ] ;
284
293
285
294
debug ! ( " sub (before): {:?}" , sub) ;
286
- debug ! ( " sup (before): {:?}" , sup_def . value ) ;
295
+ debug ! ( " sup (before): {:?}" , sup_value ) ;
287
296
288
- if !sup_def . constant {
297
+ if !self . definitions [ constraint . sup ] . constant {
289
298
// If this is not a constant, then grow the value as needed to
290
299
// accommodate the outlives constraint.
291
300
292
- if dfs. copy ( sub, & mut sup_def . value , constraint. point ) {
301
+ if dfs. copy ( sub, sup_value , constraint. point ) {
293
302
changed = true ;
294
303
}
295
304
296
- debug ! ( " sup (after) : {:?}" , sup_def . value ) ;
305
+ debug ! ( " sup (after) : {:?}" , sup_value ) ;
297
306
debug ! ( " changed : {:?}" , changed) ;
298
307
} else {
299
308
// If this is a constant, check whether it *would
300
309
// have* to grow in order for the constraint to be
301
310
// satisfied. If so, create an error.
302
311
303
- let mut sup_value = sup_def . value . clone ( ) ;
304
- if dfs. copy ( sub, & mut sup_value, constraint. point ) {
312
+ let mut sup_value = & mut sup_value . clone ( ) ;
313
+ if dfs. copy ( sub, sup_value, constraint. point ) {
305
314
// Constant values start out with the entire
306
315
// CFG, so it must be some new free region
307
316
// that was added. Find one.
308
317
let & new_region = sup_value
309
318
. free_regions
310
- . difference ( & sup_def . value . free_regions )
319
+ . difference ( & sup_value . free_regions )
311
320
. next ( )
312
321
. unwrap ( ) ;
313
322
debug ! ( " new_region : {:?}" , new_region) ;
@@ -319,6 +328,8 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
319
328
}
320
329
debug ! ( "\n " ) ;
321
330
}
331
+
332
+ self . inferred_values = Some ( inferred_values) ;
322
333
errors
323
334
}
324
335
}
0 commit comments