Skip to content

Commit 1820da5

Browse files
committed
Move diagnostic logic to its own module
- Move specialized borrow checker diagnostic for bindings escaping its closure to its own module. - Move affected tests to `ui`.
1 parent 1a1afd7 commit 1820da5

18 files changed

+289
-63
lines changed

src/librustc/infer/error_reporting/mod.rs

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ use hir::map as hir_map;
6666
use hir::def_id::DefId;
6767
use middle::region;
6868
use traits::{ObligationCause, ObligationCauseCode};
69-
use ty::{self, Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVariants};
69+
use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants};
7070
use ty::error::TypeError;
7171
use syntax::ast::DUMMY_NODE_ID;
7272
use syntax_pos::{Pos, Span};
@@ -1068,42 +1068,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
10681068
sup_origin: SubregionOrigin<'tcx>,
10691069
sup_region: Region<'tcx>) {
10701070

1071-
// #45983: when trying to assign the contents of an argument to a binding outside of a
1072-
// closure, provide a specific message pointing this out.
1073-
if let (&SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span),
1074-
&RegionKind::ReFree(ref free_region)) = (&sub_origin, sup_region) {
1075-
let hir = &self.tcx.hir;
1076-
if let Some(node_id) = hir.as_local_node_id(free_region.scope) {
1077-
match hir.get(node_id) {
1078-
hir_map::NodeExpr(hir::Expr {
1079-
node: hir::ExprClosure(_, _, _, closure_span, false),
1080-
..
1081-
}) => {
1082-
let sup_sp = sup_origin.span();
1083-
let origin_sp = var_origin.span();
1084-
let mut err = self.tcx.sess.struct_span_err(
1085-
sup_sp,
1086-
"borrowed data cannot be moved outside of its closure");
1087-
err.span_label(sup_sp, "cannot be moved outside of its closure");
1088-
if sup_sp == origin_sp {
1089-
err.span_label(*external_span,
1090-
"borrowed data cannot be moved into here...");
1091-
err.span_label(*closure_span,
1092-
"...because it cannot outlive this closure");
1093-
} else {
1094-
err.span_label(*closure_span,
1095-
"borrowed data cannot outlive this closure");
1096-
err.span_label(origin_sp,
1097-
"cannot infer an appropriate lifetime");
1098-
}
1099-
err.emit();
1100-
return;
1101-
}
1102-
_ => {}
1103-
}
1104-
}
1105-
}
1106-
11071071
let mut err = self.report_inference_failure(var_origin);
11081072

11091073
self.tcx.note_and_explain_region(region_scope_tree, &mut err,

src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
5353
///
5454
/// It will later be extended to trait objects.
5555
pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
56-
let NiceRegionError { span, sub, sup, .. } = *self;
56+
let (span, sub, sup) = self.get_regions();
5757

5858
// Determine whether the sub and sup consist of both anonymous (elided) regions.
5959
let anon_reg_sup = self.is_suitable_region(sup)?;

src/librustc/infer/error_reporting/nice_region_error/mod.rs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,46 +18,64 @@ use util::common::ErrorReported;
1818
mod different_lifetimes;
1919
mod find_anon_type;
2020
mod named_anon_conflict;
21+
mod outlives_closure;
2122
mod util;
2223

2324
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
2425
pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
25-
let (span, sub, sup) = match *error {
26-
ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
27-
SubSupConflict(_, ref origin, sub, _, sup) => (origin.span(), sub, sup),
28-
_ => return false, // inapplicable
29-
};
26+
match *error {
27+
ConcreteFailure(..) | SubSupConflict(..) => {}
28+
_ => return false, // inapplicable
29+
}
3030

3131
if let Some(tables) = self.in_progress_tables {
3232
let tables = tables.borrow();
33-
NiceRegionError::new(self.tcx, span, sub, sup, Some(&tables)).try_report().is_some()
33+
NiceRegionError::new(self.tcx, error.clone(), Some(&tables)).try_report().is_some()
3434
} else {
35-
NiceRegionError::new(self.tcx, span, sub, sup, None).try_report().is_some()
35+
NiceRegionError::new(self.tcx, error.clone(), None).try_report().is_some()
3636
}
3737
}
3838
}
3939

4040
pub struct NiceRegionError<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
4141
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
42-
span: Span,
43-
sub: ty::Region<'tcx>,
44-
sup: ty::Region<'tcx>,
42+
error: Option<RegionResolutionError<'tcx>>,
43+
regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
4544
tables: Option<&'cx ty::TypeckTables<'tcx>>,
4645
}
4746

4847
impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
4948
pub fn new(
49+
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
50+
error: RegionResolutionError<'tcx>,
51+
tables: Option<&'cx ty::TypeckTables<'tcx>>,
52+
) -> Self {
53+
Self { tcx, error: Some(error), regions: None, tables }
54+
}
55+
56+
pub fn new_from_span(
5057
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
5158
span: Span,
5259
sub: ty::Region<'tcx>,
5360
sup: ty::Region<'tcx>,
5461
tables: Option<&'cx ty::TypeckTables<'tcx>>,
5562
) -> Self {
56-
Self { tcx, span, sub, sup, tables }
63+
Self { tcx, error: None, regions: Some((span, sub, sup)), tables }
5764
}
5865

5966
pub fn try_report(&self) -> Option<ErrorReported> {
6067
self.try_report_named_anon_conflict()
6168
.or_else(|| self.try_report_anon_anon_conflict())
69+
.or_else(|| self.try_report_outlives_closure())
70+
}
71+
72+
pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
73+
match (&self.error, self.regions) {
74+
(&Some(ConcreteFailure(ref origin, sub, sup)), None) => (origin.span(), sub, sup),
75+
(&Some(SubSupConflict(_, ref origin, sub, _, sup)), None) => (origin.span(), sub, sup),
76+
(None, Some((span, sub, sup))) => (span, sub, sup),
77+
(Some(_), Some(_)) => panic!("incorrectly built NiceRegionError"),
78+
_ => panic!("trying to report on an incorrect lifetime failure"),
79+
}
6280
}
6381
}

src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
1818
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
1919
/// an anonymous region, emit an descriptive diagnostic error.
2020
pub(super) fn try_report_named_anon_conflict(&self) -> Option<ErrorReported> {
21-
let NiceRegionError { span, sub, sup, .. } = *self;
21+
let (span, sub, sup) = self.get_regions();
2222

2323
debug!(
2424
"try_report_named_anon_conflict(sub={:?}, sup={:?})",
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Error Reporting for Anonymous Region Lifetime Errors
12+
//! where both the regions are anonymous.
13+
14+
use infer::error_reporting::nice_region_error::NiceRegionError;
15+
use infer::SubregionOrigin;
16+
use ty::RegionKind;
17+
use hir::{Expr, ExprClosure};
18+
use hir::map::NodeExpr;
19+
use util::common::ErrorReported;
20+
use infer::lexical_region_resolve::RegionResolutionError::SubSupConflict;
21+
22+
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
23+
/// Print the error message for lifetime errors when binding excapes a closure.
24+
///
25+
/// Consider a case where we have
26+
///
27+
/// ```no_run
28+
/// fn with_int<F>(f: F) where F: FnOnce(&isize) {
29+
/// let x = 3;
30+
/// f(&x);
31+
/// }
32+
/// fn main() {
33+
/// let mut x = None;
34+
/// with_int(|y| x = Some(y));
35+
/// }
36+
/// ```
37+
///
38+
/// the output will be
39+
///
40+
/// ```text
41+
/// let mut x = None;
42+
/// ----- borrowed data cannot be stored into here...
43+
/// with_int(|y| x = Some(y));
44+
/// --- ^ cannot be stored outside of its closure
45+
/// |
46+
/// ...because it cannot outlive this closure
47+
/// ```
48+
pub(super) fn try_report_outlives_closure(&self) -> Option<ErrorReported> {
49+
if let Some(SubSupConflict(origin,
50+
ref sub_origin,
51+
_,
52+
ref sup_origin,
53+
sup_region)) = self.error {
54+
55+
// #45983: when trying to assign the contents of an argument to a binding outside of a
56+
// closure, provide a specific message pointing this out.
57+
if let (&SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span),
58+
&RegionKind::ReFree(ref free_region)) = (&sub_origin, sup_region) {
59+
let hir = &self.tcx.hir;
60+
if let Some(node_id) = hir.as_local_node_id(free_region.scope) {
61+
match hir.get(node_id) {
62+
NodeExpr(Expr {
63+
node: ExprClosure(_, _, _, closure_span, false),
64+
..
65+
}) => {
66+
let sup_sp = sup_origin.span();
67+
let origin_sp = origin.span();
68+
let mut err = self.tcx.sess.struct_span_err(
69+
sup_sp,
70+
"borrowed data cannot be stored outside of its closure");
71+
err.span_label(sup_sp, "cannot be stored outside of its closure");
72+
if sup_sp == origin_sp {
73+
err.span_label(*external_span,
74+
"borrowed data cannot be stored into here...");
75+
err.span_label(*closure_span,
76+
"...because it cannot outlive this closure");
77+
} else {
78+
err.span_label(*closure_span,
79+
"borrowed data cannot outlive this closure");
80+
err.span_label(origin_sp,
81+
"cannot infer an appropriate lifetime");
82+
}
83+
err.emit();
84+
return Some(ErrorReported);
85+
}
86+
_ => {}
87+
}
88+
}
89+
}
90+
}
91+
None
92+
}
93+
}
94+

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
989989

990990
if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
991991
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
992-
let nice = NiceRegionError::new(infcx.tcx, blame_span, o, f, Some(tables));
992+
let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables));
993993
if let Some(ErrorReported) = nice.try_report() {
994994
return;
995995
}

src/test/ui/borrowck/issue-45983.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ fn give_any<F: for<'r> FnOnce(&'r ())>(f: F) {
1515
fn main() {
1616
let x = None;
1717
give_any(|y| x = Some(y));
18-
//~^ ERROR borrowed data cannot be moved outside of its closure
18+
//~^ ERROR borrowed data cannot be stored outside of its closure
1919
}

src/test/ui/borrowck/issue-45983.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: borrowed data cannot be moved outside of its closure
1+
error: borrowed data cannot be stored outside of its closure
22
--> $DIR/issue-45983.rs:17:27
33
|
44
16 | let x = None;
5-
| - borrowed data cannot be moved into here...
5+
| - borrowed data cannot be stored into here...
66
17 | give_any(|y| x = Some(y));
7-
| --- ^ cannot be moved outside of its closure
7+
| --- ^ cannot be stored outside of its closure
88
| |
99
| ...because it cannot outlive this closure
1010

src/test/compile-fail/issue-7573.rs renamed to src/test/ui/borrowck/issue-7573.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ pub fn remove_package_from_database() {
2929
let push_id = |installed_id: &CrateId| {
3030
//~^ NOTE borrowed data cannot outlive this closure
3131
lines_to_use.push(installed_id);
32-
//~^ ERROR borrowed data cannot be moved outside of its closure
33-
//~| NOTE cannot be moved outside of its closure
32+
//~^ ERROR borrowed data cannot be stored outside of its closure
33+
//~| NOTE cannot be stored outside of its closure
3434
};
3535
list_database(push_id);
3636

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: borrowed data cannot be stored outside of its closure
2+
--> $DIR/issue-7573.rs:31:27
3+
|
4+
27 | let mut lines_to_use: Vec<&CrateId> = Vec::new();
5+
| - cannot infer an appropriate lifetime
6+
28 | //~^ NOTE cannot infer an appropriate lifetime
7+
29 | let push_id = |installed_id: &CrateId| {
8+
| ------------------------ borrowed data cannot outlive this closure
9+
30 | //~^ NOTE borrowed data cannot outlive this closure
10+
31 | lines_to_use.push(installed_id);
11+
| ^^^^^^^^^^^^ cannot be stored outside of its closure
12+
13+
error: aborting due to previous error
14+

src/test/compile-fail/regions-escape-bound-fn-2.rs renamed to src/test/ui/borrowck/regions-escape-bound-fn-2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ fn with_int<F>(f: F) where F: FnOnce(&isize) {
1616
fn main() {
1717
let mut x = None;
1818
with_int(|y| x = Some(y));
19-
//~^ ERROR borrowed data cannot be moved outside of its closure
19+
//~^ ERROR borrowed data cannot be stored outside of its closure
2020
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: borrowed data cannot be stored outside of its closure
2+
--> $DIR/regions-escape-bound-fn-2.rs:18:27
3+
|
4+
17 | let mut x = None;
5+
| ----- borrowed data cannot be stored into here...
6+
18 | with_int(|y| x = Some(y));
7+
| --- ^ cannot be stored outside of its closure
8+
| |
9+
| ...because it cannot outlive this closure
10+
11+
error: aborting due to previous error
12+

src/test/compile-fail/regions-escape-bound-fn.rs renamed to src/test/ui/borrowck/regions-escape-bound-fn.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ fn with_int<F>(f: F) where F: FnOnce(&isize) {
1616
fn main() {
1717
let mut x: Option<&isize> = None;
1818
with_int(|y| x = Some(y));
19-
//~^ ERROR borrowed data cannot be moved outside of its closure
19+
//~^ ERROR borrowed data cannot be stored outside of its closure
2020
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: borrowed data cannot be stored outside of its closure
2+
--> $DIR/regions-escape-bound-fn.rs:18:27
3+
|
4+
18 | with_int(|y| x = Some(y));
5+
| --- -----^-
6+
| | | |
7+
| | | cannot be stored outside of its closure
8+
| | cannot infer an appropriate lifetime
9+
| borrowed data cannot outlive this closure
10+
11+
error: aborting due to previous error
12+

src/test/compile-fail/regions-escape-unboxed-closure.rs renamed to src/test/ui/borrowck/regions-escape-unboxed-closure.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ fn with_int(f: &mut FnMut(&isize)) {
1414
fn main() {
1515
let mut x: Option<&isize> = None;
1616
with_int(&mut |y| x = Some(y));
17-
//~^ ERROR borrowed data cannot be moved outside of its closure
17+
//~^ ERROR borrowed data cannot be stored outside of its closure
1818
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: borrowed data cannot be stored outside of its closure
2+
--> $DIR/regions-escape-unboxed-closure.rs:16:32
3+
|
4+
16 | with_int(&mut |y| x = Some(y));
5+
| --- -----^-
6+
| | | |
7+
| | | cannot be stored outside of its closure
8+
| | cannot infer an appropriate lifetime
9+
| borrowed data cannot outlive this closure
10+
11+
error: aborting due to previous error
12+

src/test/compile-fail/closure-expected-type/expect-region-supply-region.rs renamed to src/test/ui/closure-expected-type/expect-region-supply-region.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn expect_bound_supply_nothing() {
2525
// it to escape into `f`:
2626
let mut f: Option<&u32> = None;
2727
closure_expecting_bound(|x| {
28-
f = Some(x); //~ ERROR borrowed data cannot be moved outside of its closure
28+
f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
2929
});
3030
}
3131

@@ -35,7 +35,7 @@ fn expect_bound_supply_bound() {
3535
// closure:
3636
let mut f: Option<&u32> = None;
3737
closure_expecting_bound(|x: &u32| {
38-
f = Some(x); //~ ERROR borrowed data cannot be moved outside of its closure
38+
f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
3939
});
4040
}
4141

@@ -50,7 +50,7 @@ fn expect_bound_supply_named<'x>() {
5050

5151
// And we still cannot let `x` escape into `f`.
5252
f = Some(x);
53-
//~^ ERROR borrowed data cannot be moved outside of its closure
53+
//~^ ERROR borrowed data cannot be stored outside of its closure
5454
});
5555
}
5656

0 commit comments

Comments
 (0)