@@ -28,7 +28,7 @@ mod var_name;
28
28
/// Constraints that are considered interesting can be categorized to
29
29
/// determine why they are interesting. Order of variants indicates
30
30
/// sort order of the category, thereby influencing diagnostic output.
31
- #[ derive( Debug , Eq , PartialEq , PartialOrd , Ord ) ]
31
+ #[ derive( Copy , Clone , Debug , Eq , PartialEq , PartialOrd , Ord ) ]
32
32
enum ConstraintCategory {
33
33
Cast ,
34
34
Assignment ,
@@ -43,12 +43,14 @@ enum ConstraintCategory {
43
43
impl fmt:: Display for ConstraintCategory {
44
44
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
45
45
match self {
46
- ConstraintCategory :: Assignment |
47
- ConstraintCategory :: AssignmentToUpvar => write ! ( f, "assignment" ) ,
46
+ ConstraintCategory :: Assignment | ConstraintCategory :: AssignmentToUpvar => {
47
+ write ! ( f, "assignment" )
48
+ }
48
49
ConstraintCategory :: Return => write ! ( f, "return" ) ,
49
50
ConstraintCategory :: Cast => write ! ( f, "cast" ) ,
50
- ConstraintCategory :: CallArgument |
51
- ConstraintCategory :: CallArgumentToUpvar => write ! ( f, "argument" ) ,
51
+ ConstraintCategory :: CallArgument | ConstraintCategory :: CallArgumentToUpvar => {
52
+ write ! ( f, "argument" )
53
+ }
52
54
_ => write ! ( f, "free region" ) ,
53
55
}
54
56
}
@@ -62,6 +64,43 @@ enum Trace {
62
64
}
63
65
64
66
impl < ' tcx > RegionInferenceContext < ' tcx > {
67
+ /// Tries to find the best constraint to blame for the fact that
68
+ /// `R: from_region`, where `R` is some region that meets
69
+ /// `target_test`. This works by following the constraint graph,
70
+ /// creating a constraint path that forces `R` to outlive
71
+ /// `from_region`, and then finding the best choices within that
72
+ /// path to blame.
73
+ fn best_blame_constraint (
74
+ & self ,
75
+ mir : & Mir < ' tcx > ,
76
+ from_region : RegionVid ,
77
+ target_test : impl Fn ( RegionVid ) -> bool ,
78
+ ) -> ( ConstraintCategory , Span ) {
79
+ debug ! ( "best_blame_constraint(from_region={:?})" , from_region) ;
80
+
81
+ // Find all paths
82
+ let path = self
83
+ . find_constraint_paths_between_regions ( from_region, target_test)
84
+ . unwrap ( ) ;
85
+ debug ! ( "best_blame_constraint: path={:#?}" , path) ;
86
+
87
+ // Classify each of the constraints along the path.
88
+ let mut categorized_path: Vec < ( ConstraintCategory , Span ) > = path
89
+ . iter ( )
90
+ . map ( |& index| self . classify_constraint ( index, mir) )
91
+ . collect ( ) ;
92
+ debug ! (
93
+ "best_blame_constraint: categorized_path={:?}" ,
94
+ categorized_path
95
+ ) ;
96
+
97
+ // Find what appears to be the most interesting path to report to the user.
98
+ categorized_path. sort_by ( |p0, p1| p0. 0 . cmp ( & p1. 0 ) ) ;
99
+ debug ! ( "best_blame_constraint: sorted_path={:?}" , categorized_path) ;
100
+
101
+ * categorized_path. first ( ) . unwrap ( )
102
+ }
103
+
65
104
/// Walks the graph of constraints (where `'a: 'b` is considered
66
105
/// an edge `'a -> 'b`) to find all paths from `from_region` to
67
106
/// `to_region`. The paths are accumulated into the vector
@@ -89,7 +128,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
89
128
let mut p = r;
90
129
loop {
91
130
match context[ p] {
92
- Trace :: NotVisited => bug ! ( "found unvisited region {:?} on path to {:?}" , p, r) ,
131
+ Trace :: NotVisited => {
132
+ bug ! ( "found unvisited region {:?} on path to {:?}" , p, r)
133
+ }
93
134
Trace :: FromConstraint ( c) => {
94
135
result. push ( c) ;
95
136
p = self . constraints [ c] . sup ;
@@ -139,19 +180,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
139
180
& self ,
140
181
index : ConstraintIndex ,
141
182
mir : & Mir < ' tcx > ,
142
- _infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
143
183
) -> ( ConstraintCategory , Span ) {
144
184
let constraint = self . constraints [ index] ;
145
185
debug ! ( "classify_constraint: constraint={:?}" , constraint) ;
146
186
let span = constraint. locations . span ( mir) ;
147
- let location = constraint. locations . from_location ( ) . unwrap_or ( Location :: START ) ;
187
+ let location = constraint
188
+ . locations
189
+ . from_location ( )
190
+ . unwrap_or ( Location :: START ) ;
148
191
149
192
if !self . constraint_is_interesting ( index) {
150
193
return ( ConstraintCategory :: Boring , span) ;
151
194
}
152
195
153
196
let data = & mir[ location. block ] ;
154
- debug ! ( "classify_constraint: location={:?} data={:?}" , location, data) ;
197
+ debug ! (
198
+ "classify_constraint: location={:?} data={:?}" ,
199
+ location, data
200
+ ) ;
155
201
let category = if location. statement_index == data. statements . len ( ) {
156
202
if let Some ( ref terminator) = data. terminator {
157
203
debug ! ( "classify_constraint: terminator.kind={:?}" , terminator. kind) ;
@@ -174,8 +220,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
174
220
} else {
175
221
match rvalue {
176
222
Rvalue :: Cast ( ..) => ConstraintCategory :: Cast ,
177
- Rvalue :: Use ( ..) |
178
- Rvalue :: Aggregate ( ..) => ConstraintCategory :: Assignment ,
223
+ Rvalue :: Use ( ..) | Rvalue :: Aggregate ( ..) => {
224
+ ConstraintCategory :: Assignment
225
+ }
179
226
_ => ConstraintCategory :: Other ,
180
227
}
181
228
}
@@ -206,27 +253,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
206
253
) {
207
254
debug ! ( "report_error(fr={:?}, outlived_fr={:?})" , fr, outlived_fr) ;
208
255
209
- // Find all paths
210
- let path = self . find_constraint_paths_between_regions ( fr, |r| r == outlived_fr) . unwrap ( ) ;
211
- debug ! ( "report_error: path={:#?}" , path) ;
212
-
213
- // Classify each of the constraints along the path.
214
- let mut categorized_path: Vec < ( ConstraintCategory , Span ) > = path. iter ( )
215
- . map ( |& index| self . classify_constraint ( index, mir, infcx) )
216
- . collect ( ) ;
217
- debug ! ( "report_error: categorized_path={:?}" , categorized_path) ;
218
-
219
- // Find what appears to be the most interesting path to report to the user.
220
- categorized_path. sort_by ( |p0, p1| p0. 0 . cmp ( & p1. 0 ) ) ;
221
- debug ! ( "report_error: sorted_path={:?}" , categorized_path) ;
222
-
223
- // Get a span
224
- let ( category, span) = categorized_path. first ( ) . unwrap ( ) ;
256
+ let ( category, span) = self . best_blame_constraint ( mir, fr, |r| r == outlived_fr) ;
225
257
226
258
// Check if we can use one of the "nice region errors".
227
259
if let ( Some ( f) , Some ( o) ) = ( self . to_error_region ( fr) , self . to_error_region ( outlived_fr) ) {
228
260
let tables = infcx. tcx . typeck_tables_of ( mir_def_id) ;
229
- let nice = NiceRegionError :: new_from_span ( infcx. tcx , * span, o, f, Some ( tables) ) ;
261
+ let nice = NiceRegionError :: new_from_span ( infcx. tcx , span, o, f, Some ( tables) ) ;
230
262
if let Some ( _error_reported) = nice. try_report ( ) {
231
263
return ;
232
264
}
@@ -237,22 +269,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
237
269
self . universal_regions . is_local_free_region ( fr) ,
238
270
self . universal_regions . is_local_free_region ( outlived_fr) ,
239
271
) {
240
- ( ConstraintCategory :: Assignment , true , false ) =>
241
- & ConstraintCategory :: AssignmentToUpvar ,
242
- ( ConstraintCategory :: CallArgument , true , false ) =>
243
- & ConstraintCategory :: CallArgumentToUpvar ,
272
+ ( ConstraintCategory :: Assignment , true , false ) => ConstraintCategory :: AssignmentToUpvar ,
273
+ ( ConstraintCategory :: CallArgument , true , false ) => {
274
+ ConstraintCategory :: CallArgumentToUpvar
275
+ }
244
276
( category, _, _) => category,
245
277
} ;
246
278
247
279
debug ! ( "report_error: category={:?}" , category) ;
248
280
match category {
249
- ConstraintCategory :: AssignmentToUpvar |
250
- ConstraintCategory :: CallArgumentToUpvar =>
251
- self . report_closure_error (
252
- mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer) ,
253
- _ =>
254
- self . report_general_error (
255
- mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer) ,
281
+ ConstraintCategory :: AssignmentToUpvar | ConstraintCategory :: CallArgumentToUpvar => self
282
+ . report_closure_error (
283
+ mir,
284
+ infcx,
285
+ mir_def_id,
286
+ fr,
287
+ outlived_fr,
288
+ category,
289
+ span,
290
+ errors_buffer,
291
+ ) ,
292
+ _ => self . report_general_error (
293
+ mir,
294
+ infcx,
295
+ mir_def_id,
296
+ fr,
297
+ outlived_fr,
298
+ category,
299
+ span,
300
+ errors_buffer,
301
+ ) ,
256
302
}
257
303
}
258
304
@@ -263,23 +309,31 @@ impl<'tcx> RegionInferenceContext<'tcx> {
263
309
mir_def_id : DefId ,
264
310
fr : RegionVid ,
265
311
outlived_fr : RegionVid ,
266
- category : & ConstraintCategory ,
267
- span : & Span ,
312
+ category : ConstraintCategory ,
313
+ span : Span ,
268
314
errors_buffer : & mut Vec < Diagnostic > ,
269
315
) {
270
- let fr_name_and_span = self . get_var_name_and_span_for_region (
271
- infcx. tcx , mir, fr) ;
272
- let outlived_fr_name_and_span = self . get_var_name_and_span_for_region (
273
- infcx. tcx , mir, outlived_fr) ;
316
+ let fr_name_and_span = self . get_var_name_and_span_for_region ( infcx. tcx , mir, fr) ;
317
+ let outlived_fr_name_and_span =
318
+ self . get_var_name_and_span_for_region ( infcx. tcx , mir, outlived_fr) ;
274
319
275
320
if fr_name_and_span. is_none ( ) && outlived_fr_name_and_span. is_none ( ) {
276
321
return self . report_general_error (
277
- mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer) ;
322
+ mir,
323
+ infcx,
324
+ mir_def_id,
325
+ fr,
326
+ outlived_fr,
327
+ category,
328
+ span,
329
+ errors_buffer,
330
+ ) ;
278
331
}
279
332
280
- let mut diag = infcx. tcx . sess . struct_span_err (
281
- * span, & format ! ( "borrowed data escapes outside of closure" ) ,
282
- ) ;
333
+ let mut diag = infcx
334
+ . tcx
335
+ . sess
336
+ . struct_span_err ( span, & format ! ( "borrowed data escapes outside of closure" ) ) ;
283
337
284
338
if let Some ( ( outlived_fr_name, outlived_fr_span) ) = outlived_fr_name_and_span {
285
339
if let Some ( name) = outlived_fr_name {
@@ -294,10 +348,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
294
348
if let Some ( name) = fr_name {
295
349
diag. span_label (
296
350
fr_span,
297
- format ! ( "`{}` is a reference that is only valid in the closure body" , name) ,
351
+ format ! (
352
+ "`{}` is a reference that is only valid in the closure body" ,
353
+ name
354
+ ) ,
298
355
) ;
299
356
300
- diag. span_label ( * span, format ! ( "`{}` escapes the closure body here" , name) ) ;
357
+ diag. span_label ( span, format ! ( "`{}` escapes the closure body here" , name) ) ;
301
358
}
302
359
}
303
360
@@ -311,24 +368,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
311
368
mir_def_id : DefId ,
312
369
fr : RegionVid ,
313
370
outlived_fr : RegionVid ,
314
- category : & ConstraintCategory ,
315
- span : & Span ,
371
+ category : ConstraintCategory ,
372
+ span : Span ,
316
373
errors_buffer : & mut Vec < Diagnostic > ,
317
374
) {
318
375
let mut diag = infcx. tcx . sess . struct_span_err (
319
- * span, & format ! ( "unsatisfied lifetime constraints" ) , // FIXME
376
+ span,
377
+ & format ! ( "unsatisfied lifetime constraints" ) , // FIXME
320
378
) ;
321
379
322
380
let counter = & mut 1 ;
323
- let fr_name = self . give_region_a_name (
324
- infcx. tcx , mir, mir_def_id, fr, counter, & mut diag) ;
325
- let outlived_fr_name = self . give_region_a_name (
326
- infcx. tcx , mir, mir_def_id, outlived_fr, counter, & mut diag) ;
327
-
328
- diag. span_label ( * span, format ! (
329
- "{} requires that `{}` must outlive `{}`" ,
330
- category, fr_name, outlived_fr_name,
331
- ) ) ;
381
+ let fr_name = self . give_region_a_name ( infcx. tcx , mir, mir_def_id, fr, counter, & mut diag) ;
382
+ let outlived_fr_name =
383
+ self . give_region_a_name ( infcx. tcx , mir, mir_def_id, outlived_fr, counter, & mut diag) ;
384
+
385
+ diag. span_label (
386
+ span,
387
+ format ! (
388
+ "{} requires that `{}` must outlive `{}`" ,
389
+ category, fr_name, outlived_fr_name,
390
+ ) ,
391
+ ) ;
332
392
333
393
diag. buffer ( errors_buffer) ;
334
394
}
0 commit comments