@@ -17,6 +17,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
17
17
use rustc_data_structures:: fx:: FxHashSet ;
18
18
use std:: collections:: BTreeSet ;
19
19
use std:: fmt;
20
+ use syntax_pos:: Span ;
20
21
21
22
pub struct RegionInferenceContext < ' tcx > {
22
23
/// Contains the definition for every region variable. Region
@@ -70,10 +71,11 @@ struct Region {
70
71
71
72
impl fmt:: Debug for Region {
72
73
fn fmt ( & self , formatter : & mut fmt:: Formatter ) -> Result < ( ) , fmt:: Error > {
73
- formatter. debug_set ( )
74
- . entries ( & self . points )
75
- . entries ( & self . free_regions )
76
- . finish ( )
74
+ formatter
75
+ . debug_set ( )
76
+ . entries ( & self . points )
77
+ . entries ( & self . free_regions )
78
+ . finish ( )
77
79
}
78
80
}
79
81
@@ -93,8 +95,16 @@ impl Region {
93
95
94
96
#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
95
97
pub struct Constraint {
96
- sub : RegionIndex ,
98
+ /// Where did this constraint arise?
99
+ span : Span ,
100
+
101
+ /// The region SUP must outlive SUB...
97
102
sup : RegionIndex ,
103
+
104
+ /// Region that must be outlived.
105
+ sub : RegionIndex ,
106
+
107
+ /// At this location.
98
108
point : Location ,
99
109
}
100
110
@@ -210,56 +220,116 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
210
220
pub ( super ) fn add_live_point ( & mut self , v : RegionIndex , point : Location ) {
211
221
debug ! ( "add_live_point({:?}, {:?})" , v, point) ;
212
222
let definition = & mut self . definitions [ v] ;
213
- definition. value . add_point ( point) ;
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
+ }
214
230
}
215
231
216
232
/// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
217
- pub ( super ) fn add_outlives ( & mut self , sup : RegionIndex , sub : RegionIndex , point : Location ) {
233
+ pub ( super ) fn add_outlives (
234
+ & mut self ,
235
+ span : Span ,
236
+ sup : RegionIndex ,
237
+ sub : RegionIndex ,
238
+ point : Location ,
239
+ ) {
218
240
debug ! ( "add_outlives({:?}: {:?} @ {:?}" , sup, sub, point) ;
219
- self . constraints . push ( Constraint { sup, sub, point } ) ;
241
+ self . constraints . push ( Constraint {
242
+ span,
243
+ sup,
244
+ sub,
245
+ point,
246
+ } ) ;
220
247
}
221
248
222
249
/// Perform region inference.
223
250
pub ( super ) fn solve ( & mut self , infcx : & InferCtxt < ' a , ' gcx , ' tcx > , mir : & Mir < ' tcx > ) {
224
- self . propagate_constraints ( infcx, mir) ;
251
+ let errors = self . propagate_constraints ( mir) ;
252
+
253
+ // worst error msg ever
254
+ for ( fr1, span, fr2) in errors {
255
+ infcx. tcx . sess . span_err (
256
+ span,
257
+ & format ! (
258
+ "free region `{}` does not outlive `{}`" ,
259
+ self . definitions[ fr1] . name. unwrap( ) ,
260
+ self . definitions[ fr2] . name. unwrap( )
261
+ ) ,
262
+ ) ;
263
+ }
225
264
}
226
265
227
266
/// Propagate the region constraints: this will grow the values
228
267
/// for each region variable until all the constraints are
229
268
/// satisfied. Note that some values may grow **too** large to be
230
269
/// feasible, but we check this later.
231
- fn propagate_constraints ( & mut self , infcx : & InferCtxt < ' a , ' gcx , ' tcx > , mir : & Mir < ' tcx > ) {
270
+ fn propagate_constraints (
271
+ & mut self ,
272
+ mir : & Mir < ' tcx > ,
273
+ ) -> Vec < ( RegionIndex , Span , RegionIndex ) > {
232
274
let mut changed = true ;
233
- let mut dfs = Dfs :: new ( infcx, mir) ;
275
+ let mut dfs = Dfs :: new ( mir) ;
276
+ let mut error_regions = FxHashSet ( ) ;
277
+ let mut errors = vec ! [ ] ;
234
278
while changed {
235
279
changed = false ;
236
280
for constraint in & self . constraints {
281
+ debug ! ( "constraint: {:?}" , constraint) ;
237
282
let sub = & self . definitions [ constraint. sub ] . value . clone ( ) ;
238
283
let sup_def = & mut self . definitions [ constraint. sup ] ;
239
- debug ! ( "constraint: {:?}" , constraint ) ;
284
+
240
285
debug ! ( " sub (before): {:?}" , sub) ;
241
286
debug ! ( " sup (before): {:?}" , sup_def. value) ;
242
287
243
- if dfs. copy ( sub, & mut sup_def. value , constraint. point ) {
244
- changed = true ;
288
+ if !sup_def. constant {
289
+ // If this is not a constant, then grow the value as needed to
290
+ // accommodate the outlives constraint.
291
+
292
+ if dfs. copy ( sub, & mut sup_def. value , constraint. point ) {
293
+ changed = true ;
294
+ }
295
+
296
+ debug ! ( " sup (after) : {:?}" , sup_def. value) ;
297
+ debug ! ( " changed : {:?}" , changed) ;
298
+ } else {
299
+ // If this is a constant, check whether it *would
300
+ // have* to grow in order for the constraint to be
301
+ // satisfied. If so, create an error.
302
+
303
+ let mut sup_value = sup_def. value . clone ( ) ;
304
+ if dfs. copy ( sub, & mut sup_value, constraint. point ) {
305
+ // Constant values start out with the entire
306
+ // CFG, so it must be some new free region
307
+ // that was added. Find one.
308
+ let & new_region = sup_value
309
+ . free_regions
310
+ . difference ( & sup_def. value . free_regions )
311
+ . next ( )
312
+ . unwrap ( ) ;
313
+ debug ! ( " new_region : {:?}" , new_region) ;
314
+ if error_regions. insert ( constraint. sup ) {
315
+ errors. push ( ( constraint. sup , constraint. span , new_region) ) ;
316
+ }
317
+ }
245
318
}
246
-
247
- debug ! ( " sup (after) : {:?}" , sup_def. value) ;
248
- debug ! ( " changed : {:?}" , changed) ;
249
319
}
250
320
debug ! ( "\n " ) ;
251
321
}
322
+ errors
252
323
}
253
324
}
254
325
255
- struct Dfs < ' a , ' gcx : ' tcx + ' a , ' tcx : ' a > {
256
- #[ allow( dead_code) ] infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
326
+ struct Dfs < ' a , ' tcx : ' a > {
257
327
mir : & ' a Mir < ' tcx > ,
258
328
}
259
329
260
- impl < ' a , ' gcx : ' tcx , ' tcx : ' a > Dfs < ' a , ' gcx , ' tcx > {
261
- fn new ( infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > , mir : & ' a Mir < ' tcx > ) -> Self {
262
- Self { infcx , mir }
330
+ impl < ' a , ' tcx > Dfs < ' a , ' tcx > {
331
+ fn new ( mir : & ' a Mir < ' tcx > ) -> Self {
332
+ Self { mir }
263
333
}
264
334
265
335
fn copy (
@@ -316,7 +386,10 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> Dfs<'a, 'gcx, 'tcx> {
316
386
// over any skolemized end points in the `from_region`
317
387
// and make sure they are included in the `to_region`.
318
388
319
- to_region. free_regions . extend ( & from_region. free_regions ) ;
389
+ debug ! ( " dfs: free_regions={:?}" , from_region. free_regions) ;
390
+ for & fr in & from_region. free_regions {
391
+ changed |= to_region. free_regions . insert ( fr) ;
392
+ }
320
393
} else {
321
394
stack. extend ( successor_points) ;
322
395
}
0 commit comments