@@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId;
14
14
use rustc:: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
15
15
use rustc:: infer:: InferCtxt ;
16
16
use rustc:: mir:: { self , Location , Mir , Place , Rvalue , StatementKind , TerminatorKind } ;
17
- use rustc:: ty:: RegionVid ;
17
+ use rustc:: ty:: { TyCtxt , RegionVid } ;
18
18
use rustc_data_structures:: indexed_vec:: IndexVec ;
19
19
use rustc_errors:: Diagnostic ;
20
20
use std:: collections:: VecDeque ;
@@ -42,7 +42,7 @@ impl fmt::Display for ConstraintCategory {
42
42
// Must end with a space. Allows for empty names to be provided.
43
43
match self {
44
44
ConstraintCategory :: Assignment => write ! ( f, "assignment " ) ,
45
- ConstraintCategory :: Return => write ! ( f, "return " ) ,
45
+ ConstraintCategory :: Return => write ! ( f, "returning this value " ) ,
46
46
ConstraintCategory :: Cast => write ! ( f, "cast " ) ,
47
47
ConstraintCategory :: CallArgument => write ! ( f, "argument " ) ,
48
48
_ => write ! ( f, "" ) ,
@@ -67,6 +67,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
67
67
fn best_blame_constraint (
68
68
& self ,
69
69
mir : & Mir < ' tcx > ,
70
+ tcx : TyCtxt < ' _ , ' _ , ' tcx > ,
70
71
from_region : RegionVid ,
71
72
target_test : impl Fn ( RegionVid ) -> bool ,
72
73
) -> ( ConstraintCategory , Span , RegionVid ) {
@@ -92,7 +93,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
92
93
// Classify each of the constraints along the path.
93
94
let mut categorized_path: Vec < ( ConstraintCategory , Span ) > = path
94
95
. iter ( )
95
- . map ( |& index| self . classify_constraint ( index, mir) )
96
+ . map ( |& index| self . classify_constraint ( index, mir, tcx ) )
96
97
. collect ( ) ;
97
98
debug ! (
98
99
"best_blame_constraint: categorized_path={:#?}" ,
@@ -123,13 +124,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
123
124
let constraint = & self . constraints [ path[ i] ] ;
124
125
125
126
let constraint_sup_scc = self . constraint_sccs . scc ( constraint. sup ) ;
126
- if constraint_sup_scc == target_scc {
127
- return false ;
128
- }
129
127
130
128
match categorized_path[ i] . 0 {
131
129
ConstraintCategory :: Boring => false ,
132
- _ => true ,
130
+ ConstraintCategory :: Other => {
131
+ // other isn't interesting when the two lifetimes
132
+ // are unified.
133
+ constraint_sup_scc != self . constraint_sccs . scc ( constraint. sub )
134
+ }
135
+ _ => constraint_sup_scc != target_scc,
133
136
}
134
137
} ) ;
135
138
if let Some ( i) = best_choice {
@@ -231,6 +234,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
231
234
& self ,
232
235
index : ConstraintIndex ,
233
236
mir : & Mir < ' tcx > ,
237
+ tcx : TyCtxt < ' _ , ' _ , ' tcx > ,
234
238
) -> ( ConstraintCategory , Span ) {
235
239
let constraint = self . constraints [ index] ;
236
240
debug ! ( "classify_constraint: constraint={:?}" , constraint) ;
@@ -254,7 +258,34 @@ impl<'tcx> RegionInferenceContext<'tcx> {
254
258
debug ! ( "classify_constraint: terminator.kind={:?}" , terminator. kind) ;
255
259
match terminator. kind {
256
260
TerminatorKind :: DropAndReplace { .. } => ConstraintCategory :: Assignment ,
257
- TerminatorKind :: Call { .. } => ConstraintCategory :: CallArgument ,
261
+ // Classify calls differently depending on whether or not
262
+ // the sub region appears in the destination type (so the
263
+ // sup region is in the return type). If the return type
264
+ // contains the sub-region, then this is either an
265
+ // assignment or a return, depending on whether we are
266
+ // writing to the RETURN_PLACE or not.
267
+ //
268
+ // The idea here is that the region is being propagated
269
+ // from an input into the output place, so it's a kind of
270
+ // assignment. Otherwise, if the sub-region only appears in
271
+ // the argument types, then use the CallArgument
272
+ // classification.
273
+ TerminatorKind :: Call { destination : Some ( ( ref place, _) ) , .. } => {
274
+ if tcx. any_free_region_meets (
275
+ & place. ty ( mir, tcx) . to_ty ( tcx) ,
276
+ |region| self . to_region_vid ( region) == constraint. sub ,
277
+ ) {
278
+ match place {
279
+ Place :: Local ( mir:: RETURN_PLACE ) => ConstraintCategory :: Return ,
280
+ _ => ConstraintCategory :: Assignment ,
281
+ }
282
+ } else {
283
+ ConstraintCategory :: CallArgument
284
+ }
285
+ }
286
+ TerminatorKind :: Call { destination : None , .. } => {
287
+ ConstraintCategory :: CallArgument
288
+ }
258
289
_ => ConstraintCategory :: Other ,
259
290
}
260
291
} else {
@@ -304,7 +335,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
304
335
) {
305
336
debug ! ( "report_error(fr={:?}, outlived_fr={:?})" , fr, outlived_fr) ;
306
337
307
- let ( category, span, _) = self . best_blame_constraint ( mir, fr, |r| r == outlived_fr) ;
338
+ let ( category, span, _) = self . best_blame_constraint (
339
+ mir,
340
+ infcx. tcx ,
341
+ fr,
342
+ |r| r == outlived_fr
343
+ ) ;
308
344
309
345
// Check if we can use one of the "nice region errors".
310
346
if let ( Some ( f) , Some ( o) ) = ( self . to_error_region ( fr) , self . to_error_region ( outlived_fr) ) {
@@ -417,7 +453,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
417
453
diag. span_label ( span, format ! (
418
454
"{} was supposed to return data with lifetime `{}` but it is returning \
419
455
data with lifetime `{}`",
420
- mir_def_name, fr_name , outlived_fr_name,
456
+ mir_def_name, outlived_fr_name, fr_name
421
457
) ) ;
422
458
} ,
423
459
_ => {
@@ -446,10 +482,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
446
482
crate fn find_outlives_blame_span (
447
483
& self ,
448
484
mir : & Mir < ' tcx > ,
485
+ tcx : TyCtxt < ' _ , ' _ , ' tcx > ,
449
486
fr1 : RegionVid ,
450
487
fr2 : RegionVid ,
451
488
) -> Span {
452
- let ( _, span, _) = self . best_blame_constraint ( mir, fr1, |r| r == fr2) ;
489
+ let ( _, span, _) = self . best_blame_constraint ( mir, tcx , fr1, |r| r == fr2) ;
453
490
span
454
491
}
455
492
}
0 commit comments