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

Lines changed: 48 additions & 11 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 16 additions & 3 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

0 commit comments

Comments
 (0)