Skip to content

Commit 7de3dea

Browse files
committed
Auto merge of #53175 - matthewjasper:more-return-stuff, r=nikomatsakis
[NLL] Returns are interesting for free regions Based on #53088 - creating now to get feedback. Closes #51175 * Make assigning to the return type interesting. * Use "returning this value" instead of "return" in error messages. * Prefer one of the explanations that we have a name for to a generic interesting cause in some cases. * Treat causes that involve the destination of a call like assignments.
2 parents d5b6b95 + a19db49 commit 7de3dea

File tree

83 files changed

+235
-176
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+235
-176
lines changed

src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs

+48-11
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId;
1414
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
1515
use rustc::infer::InferCtxt;
1616
use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKind};
17-
use rustc::ty::RegionVid;
17+
use rustc::ty::{TyCtxt, RegionVid};
1818
use rustc_data_structures::indexed_vec::IndexVec;
1919
use rustc_errors::Diagnostic;
2020
use std::collections::VecDeque;
@@ -42,7 +42,7 @@ impl fmt::Display for ConstraintCategory {
4242
// Must end with a space. Allows for empty names to be provided.
4343
match self {
4444
ConstraintCategory::Assignment => write!(f, "assignment "),
45-
ConstraintCategory::Return => write!(f, "return "),
45+
ConstraintCategory::Return => write!(f, "returning this value "),
4646
ConstraintCategory::Cast => write!(f, "cast "),
4747
ConstraintCategory::CallArgument => write!(f, "argument "),
4848
_ => write!(f, ""),
@@ -67,6 +67,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
6767
fn best_blame_constraint(
6868
&self,
6969
mir: &Mir<'tcx>,
70+
tcx: TyCtxt<'_, '_, 'tcx>,
7071
from_region: RegionVid,
7172
target_test: impl Fn(RegionVid) -> bool,
7273
) -> (ConstraintCategory, Span, RegionVid) {
@@ -92,7 +93,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
9293
// Classify each of the constraints along the path.
9394
let mut categorized_path: Vec<(ConstraintCategory, Span)> = path
9495
.iter()
95-
.map(|&index| self.classify_constraint(index, mir))
96+
.map(|&index| self.classify_constraint(index, mir, tcx))
9697
.collect();
9798
debug!(
9899
"best_blame_constraint: categorized_path={:#?}",
@@ -123,13 +124,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
123124
let constraint = &self.constraints[path[i]];
124125

125126
let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
126-
if constraint_sup_scc == target_scc {
127-
return false;
128-
}
129127

130128
match categorized_path[i].0 {
131129
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,
133136
}
134137
});
135138
if let Some(i) = best_choice {
@@ -231,6 +234,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
231234
&self,
232235
index: ConstraintIndex,
233236
mir: &Mir<'tcx>,
237+
tcx: TyCtxt<'_, '_, 'tcx>,
234238
) -> (ConstraintCategory, Span) {
235239
let constraint = self.constraints[index];
236240
debug!("classify_constraint: constraint={:?}", constraint);
@@ -254,7 +258,34 @@ impl<'tcx> RegionInferenceContext<'tcx> {
254258
debug!("classify_constraint: terminator.kind={:?}", terminator.kind);
255259
match terminator.kind {
256260
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+
}
258289
_ => ConstraintCategory::Other,
259290
}
260291
} else {
@@ -304,7 +335,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
304335
) {
305336
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
306337

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+
);
308344

309345
// Check if we can use one of the "nice region errors".
310346
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> {
417453
diag.span_label(span, format!(
418454
"{} was supposed to return data with lifetime `{}` but it is returning \
419455
data with lifetime `{}`",
420-
mir_def_name, fr_name, outlived_fr_name,
456+
mir_def_name, outlived_fr_name, fr_name
421457
));
422458
},
423459
_ => {
@@ -446,10 +482,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
446482
crate fn find_outlives_blame_span(
447483
&self,
448484
mir: &Mir<'tcx>,
485+
tcx: TyCtxt<'_, '_, 'tcx>,
449486
fr1: RegionVid,
450487
fr2: RegionVid,
451488
) -> 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);
453490
span
454491
}
455492
}

src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
587587
infcx.extract_type_name(&return_ty)
588588
});
589589

590-
let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir");
590+
let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir");
591591

592592
let (return_span, mir_description) = if let hir::ExprKind::Closure(_, _, _, span, gen_move)
593593
= tcx.hir.expect_expr(mir_node_id).node

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
10401040
longer_fr, shorter_fr,
10411041
);
10421042

1043-
let blame_span = self.find_outlives_blame_span(mir, longer_fr, shorter_fr);
1043+
let blame_span = self.find_outlives_blame_span(mir, infcx.tcx, longer_fr, shorter_fr);
10441044

10451045
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
10461046
// Shrink `fr` until we find a non-local region (if we do).
@@ -1128,7 +1128,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11281128
};
11291129

11301130
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
1131-
let span = self.find_outlives_blame_span(mir, longer_fr, error_region);
1131+
let span = self.find_outlives_blame_span(mir, infcx.tcx, longer_fr, error_region);
11321132

11331133
// Obviously, this error message is far from satisfactory.
11341134
// At present, though, it only appears in unit tests --

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -877,8 +877,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
877877
// they are not caused by the user, but rather artifacts
878878
// of lowering. Assignments to other sorts of places *are* interesting
879879
// though.
880-
let is_temp = if let Place::Local(l) = place {
881-
!mir.local_decls[*l].is_user_variable.is_some()
880+
let is_temp = if let Place::Local(l) = *place {
881+
l != RETURN_PLACE &&
882+
!mir.local_decls[l].is_user_variable.is_some()
882883
} else {
883884
false
884885
};
@@ -1119,7 +1120,19 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
11191120
match *destination {
11201121
Some((ref dest, _target_block)) => {
11211122
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
1122-
let locations = term_location.interesting();
1123+
let is_temp = if let Place::Local(l) = *dest {
1124+
l != RETURN_PLACE &&
1125+
!mir.local_decls[l].is_user_variable.is_some()
1126+
} else {
1127+
false
1128+
};
1129+
1130+
let locations = if is_temp {
1131+
term_location.boring()
1132+
} else {
1133+
term_location.interesting()
1134+
};
1135+
11231136
if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) {
11241137
span_mirbug!(
11251138
self,

src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ LL | fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
1818
| |
1919
| lifetime `'a` defined here
2020
LL | let a = bar(foo, y);
21-
| ^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
21+
| ^^^^^^^^^^^ assignment requires that `'b` must outlive `'a`
2222

2323
error: unsatisfied lifetime constraints
2424
--> $DIR/project-fn-ret-contravariant.rs:54:12
@@ -29,7 +29,7 @@ LL | fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
2929
| lifetime `'a` defined here
3030
LL | let a = bar(foo, y);
3131
LL | let b = bar(foo, x);
32-
| ^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
32+
| ^^^^^^^^^^^ assignment requires that `'a` must outlive `'b`
3333

3434
error: aborting due to 2 previous errors
3535

src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ warning: not reporting region error due to nll
44
LL | bar(foo, x) //[transmute]~ ERROR E0495
55
| ^^^
66

7-
error: borrowed data escapes outside of function
7+
error: unsatisfied lifetime constraints
88
--> $DIR/project-fn-ret-contravariant.rs:48:4
99
|
1010
LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
11-
| - `x` is a reference that is only valid in the function body
11+
| -- lifetime `'a` defined here
1212
LL | bar(foo, x) //[transmute]~ ERROR E0495
13-
| ^^^^^^^^^^^ `x` escapes the function body here
13+
| ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
1414

1515
error: aborting due to previous error
1616

src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
1818
| |
1919
| lifetime `'a` defined here
2020
LL | let a = bar(foo, y); //[krisskross]~ ERROR E0623
21-
| ^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
21+
| ^^^^^^^^^^^ assignment requires that `'b` must outlive `'a`
2222

2323
error: unsatisfied lifetime constraints
2424
--> $DIR/project-fn-ret-invariant.rs:64:12
@@ -29,7 +29,7 @@ LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
2929
| lifetime `'a` defined here
3030
LL | let a = bar(foo, y); //[krisskross]~ ERROR E0623
3131
LL | let b = bar(foo, x);
32-
| ^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
32+
| ^^^^^^^^^^^ assignment requires that `'a` must outlive `'b`
3333

3434
error: aborting due to 2 previous errors
3535

src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ warning: not reporting region error due to nll
44
LL | bar(foo, x) //[transmute]~ ERROR E0495
55
| ^^^
66

7-
error: borrowed data escapes outside of function
7+
error: unsatisfied lifetime constraints
88
--> $DIR/project-fn-ret-invariant.rs:58:4
99
|
1010
LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
11-
| - `x` is a reference that is only valid in the function body
11+
| -- lifetime `'a` defined here
1212
...
1313
LL | bar(foo, x) //[transmute]~ ERROR E0495
14-
| ^^^^^^^^^^^ `x` escapes the function body here
14+
| ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
1515

1616
error: aborting due to previous error
1717

src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ LL | | //[mir]~^ ERROR cannot borrow `x` as mutable more than
3535
LL | | *y = 1;
3636
LL | | drop(y);
3737
LL | | }
38-
| |_________________^ requires that `'1` must outlive `'2`
38+
| |_________________^ returning this value requires that `'1` must outlive `'2`
3939
|
4040
= note: closure implements `FnMut`, so references to captured variables can't escape the closure
4141

src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ LL | | //[mir]~^ ERROR cannot borrow `x` as mutable more than
3535
LL | | *y = 1;
3636
LL | | drop(y);
3737
LL | | }
38-
| |_________________^ requires that `'1` must outlive `'2`
38+
| |_________________^ returning this value requires that `'1` must outlive `'2`
3939
|
4040
= note: closure implements `FnMut`, so references to captured variables can't escape the closure
4141

src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ LL | S { pointer: &mut *p.pointer }
55
| ^^^^^^^^^^^^^^^
66

77
error: unsatisfied lifetime constraints
8-
--> $DIR/borrowck-reborrow-from-shorter-lived-andmut.rs:19:18
8+
--> $DIR/borrowck-reborrow-from-shorter-lived-andmut.rs:19:5
99
|
1010
LL | fn copy_borrowed_ptr<'a,'b>(p: &'a mut S<'b>) -> S<'b> {
1111
| -- -- lifetime `'b` defined here
1212
| |
1313
| lifetime `'a` defined here
1414
LL | S { pointer: &mut *p.pointer }
15-
| ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
1616

1717
error: aborting due to previous error
1818

src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495
55
| ^^^^^^
66

77
error: unsatisfied lifetime constraints
8-
--> $DIR/E0621-does-not-trigger-for-closures.rs:25:26
8+
--> $DIR/E0621-does-not-trigger-for-closures.rs:25:45
99
|
1010
LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495
11-
| -- ^^^^^ requires that `'1` must outlive `'2`
11+
| -- ^ returning this value requires that `'1` must outlive `'2`
1212
| ||
1313
| |return type of closure is &'2 i32
1414
| has type `&'1 i32`

src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ error: unsatisfied lifetime constraints
4040
--> $DIR/must_outlive_least_region_or_bound.rs:16:44
4141
|
4242
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
43-
| -- lifetime `'a` defined here ^ return requires that `'a` must outlive `'static`
43+
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
4444

4545
error: unsatisfied lifetime constraints
4646
--> $DIR/must_outlive_least_region_or_bound.rs:22:69
4747
|
4848
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
49-
| -- lifetime `'a` defined here ^ return requires that `'a` must outlive `'static`
49+
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
5050

5151
error: unsatisfied lifetime constraints
5252
--> $DIR/must_outlive_least_region_or_bound.rs:29:5
@@ -57,7 +57,7 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
5757
| lifetime `'a` defined here
5858
LL | //~^ ERROR lifetime mismatch
5959
LL | move |_| println!("{}", y)
60-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
60+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
6161

6262
error[E0310]: the parameter type `T` may not live long enough
6363
--> $DIR/must_outlive_least_region_or_bound.rs:34:5

src/test/ui/in-band-lifetimes/mismatched.nll.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ error: unsatisfied lifetime constraints
2222
--> $DIR/mismatched.rs:16:46
2323
|
2424
LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } //~ ERROR lifetime mismatch
25-
| -- -- ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
25+
| -- -- ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
2626
| | |
2727
| | lifetime `'b` defined here
2828
| lifetime `'a` defined here

src/test/ui/issues/issue-14285.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ LL | B(a) //~ ERROR 22:5: 22:9: explicit lifetime required in the type of
55
| ^
66

77
error[E0621]: explicit lifetime required in the type of `a`
8-
--> $DIR/issue-14285.rs:22:7
8+
--> $DIR/issue-14285.rs:22:5
99
|
1010
LL | fn foo<'a>(a: &Foo) -> B<'a> {
1111
| ---- help: add explicit lifetime `'a` to the type of `a`: `&'a (dyn Foo + 'a)`
1212
LL | B(a) //~ ERROR 22:5: 22:9: explicit lifetime required in the type of `a` [E0621]
13-
| ^ lifetime `'a` required
13+
| ^^^^ lifetime `'a` required
1414

1515
error: aborting due to previous error
1616

src/test/ui/issues/issue-15034.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ LL | Parser { lexer: lexer }
55
| ^^^^^^
66

77
error[E0621]: explicit lifetime required in the type of `lexer`
8-
--> $DIR/issue-15034.rs:27:25
8+
--> $DIR/issue-15034.rs:27:9
99
|
1010
LL | pub fn new(lexer: &'a mut Lexer) -> Parser<'a> {
1111
| ------------- help: add explicit lifetime `'a` to the type of `lexer`: `&'a mut Lexer<'a>`
1212
LL | Parser { lexer: lexer }
13-
| ^^^^^ lifetime `'a` required
13+
| ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
1414

1515
error: aborting due to previous error
1616

src/test/ui/issues/issue-3154.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ LL | thing{ x: x } //~ ERROR 16:5: 16:18: explicit lifetime required in the
1111
| ^^^^^
1212

1313
error[E0621]: explicit lifetime required in the type of `x`
14-
--> $DIR/issue-3154.rs:16:15
14+
--> $DIR/issue-3154.rs:16:5
1515
|
1616
LL | fn thing<'a,Q>(x: &Q) -> thing<'a,Q> {
1717
| -- help: add explicit lifetime `'a` to the type of `x`: `&'a Q`
1818
LL | thing{ x: x } //~ ERROR 16:5: 16:18: explicit lifetime required in the type of `x` [E0621]
19-
| ^ lifetime `'a` required
19+
| ^^^^^^^^^^^^^ lifetime `'a` required
2020

2121
error: aborting due to previous error
2222

0 commit comments

Comments
 (0)