From 846042161c17bcc696715b3dfe2e6c4970da0b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 2 Jan 2018 15:25:53 -0800 Subject: [PATCH 1/6] Custom error when moving arg outside of its closure When given the following code: ```rust fn give_any FnOnce(&'r ())>(f: F) { f(&()); } fn main() { let mut x = None; give_any(|y| x = Some(y)); } ``` provide a custom error: ``` error: borrowed data cannot be moved outside of its closure --> file.rs:7:27 | 6 | let mut x = None; | ----- binding declared outside of closure 7 | give_any(|y| x = Some(y)); | --- ^ cannot be assigned to binding outside of its closure | | | closure you can't escape ``` instead of the generic lifetime error: ``` error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> file.rs:7:27 | 7 | give_any(|y| x = Some(y)); | ^ | note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 7:14... --> file.rs:7:14 | 7 | give_any(|y| x = Some(y)); | ^^^^^^^^^^^^^^^ note: ...so that expression is assignable (expected &(), found &()) --> file.rs:7:27 | 7 | give_any(|y| x = Some(y)); | ^ note: but, the lifetime must be valid for the block suffix following statement 0 at 6:5... --> file.rs:6:5 | 6 | / let mut x = None; 7 | | give_any(|y| x = Some(y)); 8 | | } | |_^ note: ...so that variable is valid at time of its declaration --> file.rs:6:9 | 6 | let mut x = None; | ^^^^^ ``` --- src/librustc/infer/error_reporting/mod.rs | 36 ++++++++++++++++++- .../compile-fail/regions-escape-bound-fn-2.rs | 2 +- src/test/ui/borrowck/issue-45983.rs | 19 ++++++++++ src/test/ui/borrowck/issue-45983.stderr | 12 +++++++ 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/borrowck/issue-45983.rs create mode 100644 src/test/ui/borrowck/issue-45983.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index c477a0d383e21..3cd7c5e0af3ee 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -66,7 +66,7 @@ use hir::map as hir_map; use hir::def_id::DefId; use middle::region; use traits::{ObligationCause, ObligationCauseCode}; -use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants}; +use ty::{self, Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVariants}; use ty::error::TypeError; use syntax::ast::DUMMY_NODE_ID; use syntax_pos::{Pos, Span}; @@ -1067,6 +1067,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { sub_region: Region<'tcx>, sup_origin: SubregionOrigin<'tcx>, sup_region: Region<'tcx>) { + + // #45983: when trying to assign the contents of an argument to a binding outside of a + // closure, provide a specific message pointing this out. + if let (&SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span), + &SubregionOrigin::Subtype(TypeTrace { ref cause, .. }), + &RegionKind::ReFree(ref free_region)) = (&sub_origin, &sup_origin, sup_region) { + let hir = &self.tcx.hir; + if let Some(node_id) = hir.as_local_node_id(free_region.scope) { + match hir.get(node_id) { + hir_map::NodeExpr(hir::Expr { + node: hir::ExprClosure(_, _, _, closure_span, false), + .. + }) => { + let sp = var_origin.span(); + let mut err = self.tcx.sess.struct_span_err( + sp, + "borrowed data cannot be moved outside of its closure"); + let label = match cause.code { + ObligationCauseCode::ExprAssignable => { + "cannot be assigned to binding outside of its closure" + } + _ => "cannot be moved outside of its closure", + }; + err.span_label(sp, label); + err.span_label(*closure_span, "closure you can't escape"); + err.span_label(*external_span, "binding declared outside of closure"); + err.emit(); + return; + } + _ => {} + } + } + } + let mut err = self.report_inference_failure(var_origin); self.tcx.note_and_explain_region(region_scope_tree, &mut err, diff --git a/src/test/compile-fail/regions-escape-bound-fn-2.rs b/src/test/compile-fail/regions-escape-bound-fn-2.rs index 1329d05a0f690..042c55eed866e 100644 --- a/src/test/compile-fail/regions-escape-bound-fn-2.rs +++ b/src/test/compile-fail/regions-escape-bound-fn-2.rs @@ -16,5 +16,5 @@ fn with_int(f: F) where F: FnOnce(&isize) { fn main() { let mut x = None; with_int(|y| x = Some(y)); - //~^ ERROR cannot infer + //~^ ERROR borrowed data cannot be moved outside of its closure } diff --git a/src/test/ui/borrowck/issue-45983.rs b/src/test/ui/borrowck/issue-45983.rs new file mode 100644 index 0000000000000..b2316a6b61c81 --- /dev/null +++ b/src/test/ui/borrowck/issue-45983.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn give_any FnOnce(&'r ())>(f: F) { + f(&()); +} + +fn main() { + let x = None; + give_any(|y| x = Some(y)); + //~^ ERROR borrowed data cannot be moved outside of its closure +} diff --git a/src/test/ui/borrowck/issue-45983.stderr b/src/test/ui/borrowck/issue-45983.stderr new file mode 100644 index 0000000000000..689fe6053c9a9 --- /dev/null +++ b/src/test/ui/borrowck/issue-45983.stderr @@ -0,0 +1,12 @@ +error: borrowed data cannot be moved outside of its closure + --> $DIR/issue-45983.rs:17:27 + | +16 | let x = None; + | - binding declared outside of closure +17 | give_any(|y| x = Some(y)); + | --- ^ cannot be assigned to binding outside of its closure + | | + | closure you can't escape + +error: aborting due to previous error + From c31c60cbb9ceb75402240bfe1adc9c2b48a29aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jan 2018 14:22:38 -0800 Subject: [PATCH 2/6] Reword diagnostic --- src/librustc/infer/error_reporting/mod.rs | 16 ++++++---------- src/test/ui/borrowck/issue-45983.stderr | 6 +++--- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 3cd7c5e0af3ee..cdb90c7ba7e96 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1071,7 +1071,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // #45983: when trying to assign the contents of an argument to a binding outside of a // closure, provide a specific message pointing this out. if let (&SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span), - &SubregionOrigin::Subtype(TypeTrace { ref cause, .. }), + &SubregionOrigin::Subtype(_), &RegionKind::ReFree(ref free_region)) = (&sub_origin, &sup_origin, sup_region) { let hir = &self.tcx.hir; if let Some(node_id) = hir.as_local_node_id(free_region.scope) { @@ -1084,15 +1084,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let mut err = self.tcx.sess.struct_span_err( sp, "borrowed data cannot be moved outside of its closure"); - let label = match cause.code { - ObligationCauseCode::ExprAssignable => { - "cannot be assigned to binding outside of its closure" - } - _ => "cannot be moved outside of its closure", - }; - err.span_label(sp, label); - err.span_label(*closure_span, "closure you can't escape"); - err.span_label(*external_span, "binding declared outside of closure"); + err.span_label(sp, "cannot be moved outside of its closure"); + err.span_label(*external_span, + "borrowed data cannot be moved into here..."); + err.span_label(*closure_span, + "...because it cannot outlive this closure"); err.emit(); return; } diff --git a/src/test/ui/borrowck/issue-45983.stderr b/src/test/ui/borrowck/issue-45983.stderr index 689fe6053c9a9..cbc4a557be9ef 100644 --- a/src/test/ui/borrowck/issue-45983.stderr +++ b/src/test/ui/borrowck/issue-45983.stderr @@ -2,11 +2,11 @@ error: borrowed data cannot be moved outside of its closure --> $DIR/issue-45983.rs:17:27 | 16 | let x = None; - | - binding declared outside of closure + | - borrowed data cannot be moved into here... 17 | give_any(|y| x = Some(y)); - | --- ^ cannot be assigned to binding outside of its closure + | --- ^ cannot be moved outside of its closure | | - | closure you can't escape + | ...because it cannot outlive this closure error: aborting due to previous error From 2c5f2df201c65bbea0c0d3abe1190049093eb7b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jan 2018 15:54:33 -0800 Subject: [PATCH 3/6] Generalize cases where specific move error ocurrs Trigger new diagnostic in `compile-fail/regions-escape-bound-fn.rs` test, and not only in `compile-fail/regions-escape-bound-fn-2.rs`. --- src/librustc/infer/error_reporting/mod.rs | 3 +-- .../closure-expected-type/expect-region-supply-region.rs | 6 +++--- src/test/compile-fail/issue-7573.rs | 3 ++- src/test/compile-fail/regions-escape-bound-fn-2.rs | 2 +- src/test/compile-fail/regions-escape-bound-fn.rs | 3 ++- src/test/compile-fail/regions-escape-unboxed-closure.rs | 3 ++- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index cdb90c7ba7e96..645c8403b8e44 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1071,8 +1071,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // #45983: when trying to assign the contents of an argument to a binding outside of a // closure, provide a specific message pointing this out. if let (&SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span), - &SubregionOrigin::Subtype(_), - &RegionKind::ReFree(ref free_region)) = (&sub_origin, &sup_origin, sup_region) { + &RegionKind::ReFree(ref free_region)) = (&sub_origin, sup_region) { let hir = &self.tcx.hir; if let Some(node_id) = hir.as_local_node_id(free_region.scope) { match hir.get(node_id) { diff --git a/src/test/compile-fail/closure-expected-type/expect-region-supply-region.rs b/src/test/compile-fail/closure-expected-type/expect-region-supply-region.rs index 9da12dc901fba..678647ff28da5 100644 --- a/src/test/compile-fail/closure-expected-type/expect-region-supply-region.rs +++ b/src/test/compile-fail/closure-expected-type/expect-region-supply-region.rs @@ -25,7 +25,7 @@ fn expect_bound_supply_nothing() { // it to escape into `f`: let mut f: Option<&u32> = None; closure_expecting_bound(|x| { - f = Some(x); //~ ERROR E0495 + f = Some(x); //~ ERROR borrowed data cannot be moved outside of its closure }); } @@ -35,7 +35,7 @@ fn expect_bound_supply_bound() { // closure: let mut f: Option<&u32> = None; closure_expecting_bound(|x: &u32| { - f = Some(x); //~ ERROR E0495 + f = Some(x); //~ ERROR borrowed data cannot be moved outside of its closure }); } @@ -50,7 +50,7 @@ fn expect_bound_supply_named<'x>() { // And we still cannot let `x` escape into `f`. f = Some(x); - //~^ ERROR cannot infer + //~^ ERROR borrowed data cannot be moved outside of its closure }); } diff --git a/src/test/compile-fail/issue-7573.rs b/src/test/compile-fail/issue-7573.rs index d13da1d9fd948..7445501c4ebe6 100644 --- a/src/test/compile-fail/issue-7573.rs +++ b/src/test/compile-fail/issue-7573.rs @@ -24,7 +24,8 @@ impl CrateId { } pub fn remove_package_from_database() { - let mut lines_to_use: Vec<&CrateId> = Vec::new(); //~ ERROR E0495 + let mut lines_to_use: Vec<&CrateId> = Vec::new(); + //~^ ERROR borrowed data cannot be moved outside of its closure let push_id = |installed_id: &CrateId| { lines_to_use.push(installed_id); }; diff --git a/src/test/compile-fail/regions-escape-bound-fn-2.rs b/src/test/compile-fail/regions-escape-bound-fn-2.rs index 042c55eed866e..df07aec998a3b 100644 --- a/src/test/compile-fail/regions-escape-bound-fn-2.rs +++ b/src/test/compile-fail/regions-escape-bound-fn-2.rs @@ -16,5 +16,5 @@ fn with_int(f: F) where F: FnOnce(&isize) { fn main() { let mut x = None; with_int(|y| x = Some(y)); - //~^ ERROR borrowed data cannot be moved outside of its closure + //~^ ERROR borrowed data cannot be moved outside of its closure } diff --git a/src/test/compile-fail/regions-escape-bound-fn.rs b/src/test/compile-fail/regions-escape-bound-fn.rs index 02e62ffddfd50..86d91f530627b 100644 --- a/src/test/compile-fail/regions-escape-bound-fn.rs +++ b/src/test/compile-fail/regions-escape-bound-fn.rs @@ -15,5 +15,6 @@ fn with_int(f: F) where F: FnOnce(&isize) { fn main() { let mut x: Option<&isize> = None; - with_int(|y| x = Some(y)); //~ ERROR cannot infer + with_int(|y| x = Some(y)); + //~^ ERROR borrowed data cannot be moved outside of its closure } diff --git a/src/test/compile-fail/regions-escape-unboxed-closure.rs b/src/test/compile-fail/regions-escape-unboxed-closure.rs index cf41fad270839..e422dd02f06fa 100644 --- a/src/test/compile-fail/regions-escape-unboxed-closure.rs +++ b/src/test/compile-fail/regions-escape-unboxed-closure.rs @@ -13,5 +13,6 @@ fn with_int(f: &mut FnMut(&isize)) { fn main() { let mut x: Option<&isize> = None; - with_int(&mut |y| x = Some(y)); //~ ERROR cannot infer + with_int(&mut |y| x = Some(y)); + //~^ ERROR borrowed data cannot be moved outside of its closure } From 1a1afd74a643cead4794094e286adc9cf5ae2009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 4 Jan 2018 09:55:15 -0800 Subject: [PATCH 4/6] Handle case of moving into vec with uninferred lifetime --- src/librustc/infer/error_reporting/mod.rs | 22 +++++++++++++++------- src/test/compile-fail/issue-7573.rs | 5 ++++- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 645c8403b8e44..630a2d857a014 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1079,15 +1079,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { node: hir::ExprClosure(_, _, _, closure_span, false), .. }) => { - let sp = var_origin.span(); + let sup_sp = sup_origin.span(); + let origin_sp = var_origin.span(); let mut err = self.tcx.sess.struct_span_err( - sp, + sup_sp, "borrowed data cannot be moved outside of its closure"); - err.span_label(sp, "cannot be moved outside of its closure"); - err.span_label(*external_span, - "borrowed data cannot be moved into here..."); - err.span_label(*closure_span, - "...because it cannot outlive this closure"); + err.span_label(sup_sp, "cannot be moved outside of its closure"); + if sup_sp == origin_sp { + err.span_label(*external_span, + "borrowed data cannot be moved into here..."); + err.span_label(*closure_span, + "...because it cannot outlive this closure"); + } else { + err.span_label(*closure_span, + "borrowed data cannot outlive this closure"); + err.span_label(origin_sp, + "cannot infer an appropriate lifetime"); + } err.emit(); return; } diff --git a/src/test/compile-fail/issue-7573.rs b/src/test/compile-fail/issue-7573.rs index 7445501c4ebe6..e41d25c17ead2 100644 --- a/src/test/compile-fail/issue-7573.rs +++ b/src/test/compile-fail/issue-7573.rs @@ -25,9 +25,12 @@ impl CrateId { pub fn remove_package_from_database() { let mut lines_to_use: Vec<&CrateId> = Vec::new(); - //~^ ERROR borrowed data cannot be moved outside of its closure + //~^ NOTE cannot infer an appropriate lifetime let push_id = |installed_id: &CrateId| { + //~^ NOTE borrowed data cannot outlive this closure lines_to_use.push(installed_id); + //~^ ERROR borrowed data cannot be moved outside of its closure + //~| NOTE cannot be moved outside of its closure }; list_database(push_id); From 1820da52110cc5cfb40436225c939067049ccf32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 15 Jan 2018 10:55:10 -0800 Subject: [PATCH 5/6] 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`. --- src/librustc/infer/error_reporting/mod.rs | 38 +------ .../nice_region_error/different_lifetimes.rs | 2 +- .../error_reporting/nice_region_error/mod.rs | 40 +++++-- .../nice_region_error/named_anon_conflict.rs | 2 +- .../nice_region_error/outlives_closure.rs | 94 ++++++++++++++++ .../borrow_check/nll/region_infer/mod.rs | 2 +- src/test/ui/borrowck/issue-45983.rs | 2 +- src/test/ui/borrowck/issue-45983.stderr | 6 +- .../borrowck}/issue-7573.rs | 4 +- src/test/ui/borrowck/issue-7573.stderr | 14 +++ .../borrowck}/regions-escape-bound-fn-2.rs | 2 +- .../borrowck/regions-escape-bound-fn-2.stderr | 12 +++ .../borrowck}/regions-escape-bound-fn.rs | 2 +- .../borrowck/regions-escape-bound-fn.stderr | 12 +++ .../regions-escape-unboxed-closure.rs | 2 +- .../regions-escape-unboxed-closure.stderr | 12 +++ .../expect-region-supply-region.rs | 6 +- .../expect-region-supply-region.stderr | 100 ++++++++++++++++++ 18 files changed, 289 insertions(+), 63 deletions(-) create mode 100644 src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs rename src/test/{compile-fail => ui/borrowck}/issue-7573.rs (90%) create mode 100644 src/test/ui/borrowck/issue-7573.stderr rename src/test/{compile-fail => ui/borrowck}/regions-escape-bound-fn-2.rs (89%) create mode 100644 src/test/ui/borrowck/regions-escape-bound-fn-2.stderr rename src/test/{compile-fail => ui/borrowck}/regions-escape-bound-fn.rs (90%) create mode 100644 src/test/ui/borrowck/regions-escape-bound-fn.stderr rename src/test/{compile-fail => ui/borrowck}/regions-escape-unboxed-closure.rs (89%) create mode 100644 src/test/ui/borrowck/regions-escape-unboxed-closure.stderr rename src/test/{compile-fail => ui}/closure-expected-type/expect-region-supply-region.rs (90%) create mode 100644 src/test/ui/closure-expected-type/expect-region-supply-region.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 630a2d857a014..541c1356dd4ab 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -66,7 +66,7 @@ use hir::map as hir_map; use hir::def_id::DefId; use middle::region; use traits::{ObligationCause, ObligationCauseCode}; -use ty::{self, Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVariants}; +use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants}; use ty::error::TypeError; use syntax::ast::DUMMY_NODE_ID; use syntax_pos::{Pos, Span}; @@ -1068,42 +1068,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { sup_origin: SubregionOrigin<'tcx>, sup_region: Region<'tcx>) { - // #45983: when trying to assign the contents of an argument to a binding outside of a - // closure, provide a specific message pointing this out. - if let (&SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span), - &RegionKind::ReFree(ref free_region)) = (&sub_origin, sup_region) { - let hir = &self.tcx.hir; - if let Some(node_id) = hir.as_local_node_id(free_region.scope) { - match hir.get(node_id) { - hir_map::NodeExpr(hir::Expr { - node: hir::ExprClosure(_, _, _, closure_span, false), - .. - }) => { - let sup_sp = sup_origin.span(); - let origin_sp = var_origin.span(); - let mut err = self.tcx.sess.struct_span_err( - sup_sp, - "borrowed data cannot be moved outside of its closure"); - err.span_label(sup_sp, "cannot be moved outside of its closure"); - if sup_sp == origin_sp { - err.span_label(*external_span, - "borrowed data cannot be moved into here..."); - err.span_label(*closure_span, - "...because it cannot outlive this closure"); - } else { - err.span_label(*closure_span, - "borrowed data cannot outlive this closure"); - err.span_label(origin_sp, - "cannot infer an appropriate lifetime"); - } - err.emit(); - return; - } - _ => {} - } - } - } - let mut err = self.report_inference_failure(var_origin); self.tcx.note_and_explain_region(region_scope_tree, &mut err, diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs index d4ea899dc747f..7b0f2933580b3 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -53,7 +53,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { /// /// It will later be extended to trait objects. pub(super) fn try_report_anon_anon_conflict(&self) -> Option { - let NiceRegionError { span, sub, sup, .. } = *self; + let (span, sub, sup) = self.get_regions(); // Determine whether the sub and sup consist of both anonymous (elided) regions. let anon_reg_sup = self.is_suitable_region(sup)?; diff --git a/src/librustc/infer/error_reporting/nice_region_error/mod.rs b/src/librustc/infer/error_reporting/nice_region_error/mod.rs index edc38b6bb14ee..59b36a50a2b09 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/mod.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/mod.rs @@ -18,46 +18,64 @@ use util::common::ErrorReported; mod different_lifetimes; mod find_anon_type; mod named_anon_conflict; +mod outlives_closure; mod util; impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool { - let (span, sub, sup) = match *error { - ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup), - SubSupConflict(_, ref origin, sub, _, sup) => (origin.span(), sub, sup), - _ => return false, // inapplicable - }; + match *error { + ConcreteFailure(..) | SubSupConflict(..) => {} + _ => return false, // inapplicable + } if let Some(tables) = self.in_progress_tables { let tables = tables.borrow(); - NiceRegionError::new(self.tcx, span, sub, sup, Some(&tables)).try_report().is_some() + NiceRegionError::new(self.tcx, error.clone(), Some(&tables)).try_report().is_some() } else { - NiceRegionError::new(self.tcx, span, sub, sup, None).try_report().is_some() + NiceRegionError::new(self.tcx, error.clone(), None).try_report().is_some() } } } pub struct NiceRegionError<'cx, 'gcx: 'tcx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'gcx, 'tcx>, - span: Span, - sub: ty::Region<'tcx>, - sup: ty::Region<'tcx>, + error: Option>, + regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>, tables: Option<&'cx ty::TypeckTables<'tcx>>, } impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> { pub fn new( + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + error: RegionResolutionError<'tcx>, + tables: Option<&'cx ty::TypeckTables<'tcx>>, + ) -> Self { + Self { tcx, error: Some(error), regions: None, tables } + } + + pub fn new_from_span( tcx: TyCtxt<'cx, 'gcx, 'tcx>, span: Span, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>, tables: Option<&'cx ty::TypeckTables<'tcx>>, ) -> Self { - Self { tcx, span, sub, sup, tables } + Self { tcx, error: None, regions: Some((span, sub, sup)), tables } } pub fn try_report(&self) -> Option { self.try_report_named_anon_conflict() .or_else(|| self.try_report_anon_anon_conflict()) + .or_else(|| self.try_report_outlives_closure()) + } + + pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) { + match (&self.error, self.regions) { + (&Some(ConcreteFailure(ref origin, sub, sup)), None) => (origin.span(), sub, sup), + (&Some(SubSupConflict(_, ref origin, sub, _, sup)), None) => (origin.span(), sub, sup), + (None, Some((span, sub, sup))) => (span, sub, sup), + (Some(_), Some(_)) => panic!("incorrectly built NiceRegionError"), + _ => panic!("trying to report on an incorrect lifetime failure"), + } } } diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 9d0ddfd4be04b..657480c486c87 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -18,7 +18,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { /// When given a `ConcreteFailure` for a function with arguments containing a named region and /// an anonymous region, emit an descriptive diagnostic error. pub(super) fn try_report_named_anon_conflict(&self) -> Option { - let NiceRegionError { span, sub, sup, .. } = *self; + let (span, sub, sup) = self.get_regions(); debug!( "try_report_named_anon_conflict(sub={:?}, sup={:?})", diff --git a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs new file mode 100644 index 0000000000000..f6a99579598ca --- /dev/null +++ b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs @@ -0,0 +1,94 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Error Reporting for Anonymous Region Lifetime Errors +//! where both the regions are anonymous. + +use infer::error_reporting::nice_region_error::NiceRegionError; +use infer::SubregionOrigin; +use ty::RegionKind; +use hir::{Expr, ExprClosure}; +use hir::map::NodeExpr; +use util::common::ErrorReported; +use infer::lexical_region_resolve::RegionResolutionError::SubSupConflict; + +impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { + /// Print the error message for lifetime errors when binding excapes a closure. + /// + /// Consider a case where we have + /// + /// ```no_run + /// fn with_int(f: F) where F: FnOnce(&isize) { + /// let x = 3; + /// f(&x); + /// } + /// fn main() { + /// let mut x = None; + /// with_int(|y| x = Some(y)); + /// } + /// ``` + /// + /// the output will be + /// + /// ```text + /// let mut x = None; + /// ----- borrowed data cannot be stored into here... + /// with_int(|y| x = Some(y)); + /// --- ^ cannot be stored outside of its closure + /// | + /// ...because it cannot outlive this closure + /// ``` + pub(super) fn try_report_outlives_closure(&self) -> Option { + if let Some(SubSupConflict(origin, + ref sub_origin, + _, + ref sup_origin, + sup_region)) = self.error { + + // #45983: when trying to assign the contents of an argument to a binding outside of a + // closure, provide a specific message pointing this out. + if let (&SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span), + &RegionKind::ReFree(ref free_region)) = (&sub_origin, sup_region) { + let hir = &self.tcx.hir; + if let Some(node_id) = hir.as_local_node_id(free_region.scope) { + match hir.get(node_id) { + NodeExpr(Expr { + node: ExprClosure(_, _, _, closure_span, false), + .. + }) => { + let sup_sp = sup_origin.span(); + let origin_sp = origin.span(); + let mut err = self.tcx.sess.struct_span_err( + sup_sp, + "borrowed data cannot be stored outside of its closure"); + err.span_label(sup_sp, "cannot be stored outside of its closure"); + if sup_sp == origin_sp { + err.span_label(*external_span, + "borrowed data cannot be stored into here..."); + err.span_label(*closure_span, + "...because it cannot outlive this closure"); + } else { + err.span_label(*closure_span, + "borrowed data cannot outlive this closure"); + err.span_label(origin_sp, + "cannot infer an appropriate lifetime"); + } + err.emit(); + return Some(ErrorReported); + } + _ => {} + } + } + } + } + None + } +} + diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index da136a34b9971..9a2f98d4622f7 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -989,7 +989,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) { let tables = infcx.tcx.typeck_tables_of(mir_def_id); - let nice = NiceRegionError::new(infcx.tcx, blame_span, o, f, Some(tables)); + let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables)); if let Some(ErrorReported) = nice.try_report() { return; } diff --git a/src/test/ui/borrowck/issue-45983.rs b/src/test/ui/borrowck/issue-45983.rs index b2316a6b61c81..a6e5067195f47 100644 --- a/src/test/ui/borrowck/issue-45983.rs +++ b/src/test/ui/borrowck/issue-45983.rs @@ -15,5 +15,5 @@ fn give_any FnOnce(&'r ())>(f: F) { fn main() { let x = None; give_any(|y| x = Some(y)); - //~^ ERROR borrowed data cannot be moved outside of its closure + //~^ ERROR borrowed data cannot be stored outside of its closure } diff --git a/src/test/ui/borrowck/issue-45983.stderr b/src/test/ui/borrowck/issue-45983.stderr index cbc4a557be9ef..496f15c289c17 100644 --- a/src/test/ui/borrowck/issue-45983.stderr +++ b/src/test/ui/borrowck/issue-45983.stderr @@ -1,10 +1,10 @@ -error: borrowed data cannot be moved outside of its closure +error: borrowed data cannot be stored outside of its closure --> $DIR/issue-45983.rs:17:27 | 16 | let x = None; - | - borrowed data cannot be moved into here... + | - borrowed data cannot be stored into here... 17 | give_any(|y| x = Some(y)); - | --- ^ cannot be moved outside of its closure + | --- ^ cannot be stored outside of its closure | | | ...because it cannot outlive this closure diff --git a/src/test/compile-fail/issue-7573.rs b/src/test/ui/borrowck/issue-7573.rs similarity index 90% rename from src/test/compile-fail/issue-7573.rs rename to src/test/ui/borrowck/issue-7573.rs index e41d25c17ead2..b318bd70cf2d2 100644 --- a/src/test/compile-fail/issue-7573.rs +++ b/src/test/ui/borrowck/issue-7573.rs @@ -29,8 +29,8 @@ pub fn remove_package_from_database() { let push_id = |installed_id: &CrateId| { //~^ NOTE borrowed data cannot outlive this closure lines_to_use.push(installed_id); - //~^ ERROR borrowed data cannot be moved outside of its closure - //~| NOTE cannot be moved outside of its closure + //~^ ERROR borrowed data cannot be stored outside of its closure + //~| NOTE cannot be stored outside of its closure }; list_database(push_id); diff --git a/src/test/ui/borrowck/issue-7573.stderr b/src/test/ui/borrowck/issue-7573.stderr new file mode 100644 index 0000000000000..6c549a029b602 --- /dev/null +++ b/src/test/ui/borrowck/issue-7573.stderr @@ -0,0 +1,14 @@ +error: borrowed data cannot be stored outside of its closure + --> $DIR/issue-7573.rs:31:27 + | +27 | let mut lines_to_use: Vec<&CrateId> = Vec::new(); + | - cannot infer an appropriate lifetime +28 | //~^ NOTE cannot infer an appropriate lifetime +29 | let push_id = |installed_id: &CrateId| { + | ------------------------ borrowed data cannot outlive this closure +30 | //~^ NOTE borrowed data cannot outlive this closure +31 | lines_to_use.push(installed_id); + | ^^^^^^^^^^^^ cannot be stored outside of its closure + +error: aborting due to previous error + diff --git a/src/test/compile-fail/regions-escape-bound-fn-2.rs b/src/test/ui/borrowck/regions-escape-bound-fn-2.rs similarity index 89% rename from src/test/compile-fail/regions-escape-bound-fn-2.rs rename to src/test/ui/borrowck/regions-escape-bound-fn-2.rs index df07aec998a3b..1c38dee99a7b0 100644 --- a/src/test/compile-fail/regions-escape-bound-fn-2.rs +++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.rs @@ -16,5 +16,5 @@ fn with_int(f: F) where F: FnOnce(&isize) { fn main() { let mut x = None; with_int(|y| x = Some(y)); - //~^ ERROR borrowed data cannot be moved outside of its closure + //~^ ERROR borrowed data cannot be stored outside of its closure } diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.stderr new file mode 100644 index 0000000000000..3d88f4fd52e2e --- /dev/null +++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.stderr @@ -0,0 +1,12 @@ +error: borrowed data cannot be stored outside of its closure + --> $DIR/regions-escape-bound-fn-2.rs:18:27 + | +17 | let mut x = None; + | ----- borrowed data cannot be stored into here... +18 | with_int(|y| x = Some(y)); + | --- ^ cannot be stored outside of its closure + | | + | ...because it cannot outlive this closure + +error: aborting due to previous error + diff --git a/src/test/compile-fail/regions-escape-bound-fn.rs b/src/test/ui/borrowck/regions-escape-bound-fn.rs similarity index 90% rename from src/test/compile-fail/regions-escape-bound-fn.rs rename to src/test/ui/borrowck/regions-escape-bound-fn.rs index 86d91f530627b..c22742371acbc 100644 --- a/src/test/compile-fail/regions-escape-bound-fn.rs +++ b/src/test/ui/borrowck/regions-escape-bound-fn.rs @@ -16,5 +16,5 @@ fn with_int(f: F) where F: FnOnce(&isize) { fn main() { let mut x: Option<&isize> = None; with_int(|y| x = Some(y)); - //~^ ERROR borrowed data cannot be moved outside of its closure + //~^ ERROR borrowed data cannot be stored outside of its closure } diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.stderr b/src/test/ui/borrowck/regions-escape-bound-fn.stderr new file mode 100644 index 0000000000000..306da8b54e4f7 --- /dev/null +++ b/src/test/ui/borrowck/regions-escape-bound-fn.stderr @@ -0,0 +1,12 @@ +error: borrowed data cannot be stored outside of its closure + --> $DIR/regions-escape-bound-fn.rs:18:27 + | +18 | with_int(|y| x = Some(y)); + | --- -----^- + | | | | + | | | cannot be stored outside of its closure + | | cannot infer an appropriate lifetime + | borrowed data cannot outlive this closure + +error: aborting due to previous error + diff --git a/src/test/compile-fail/regions-escape-unboxed-closure.rs b/src/test/ui/borrowck/regions-escape-unboxed-closure.rs similarity index 89% rename from src/test/compile-fail/regions-escape-unboxed-closure.rs rename to src/test/ui/borrowck/regions-escape-unboxed-closure.rs index e422dd02f06fa..5a214504df4c1 100644 --- a/src/test/compile-fail/regions-escape-unboxed-closure.rs +++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.rs @@ -14,5 +14,5 @@ fn with_int(f: &mut FnMut(&isize)) { fn main() { let mut x: Option<&isize> = None; with_int(&mut |y| x = Some(y)); - //~^ ERROR borrowed data cannot be moved outside of its closure + //~^ ERROR borrowed data cannot be stored outside of its closure } diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr b/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr new file mode 100644 index 0000000000000..5e51be4629539 --- /dev/null +++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr @@ -0,0 +1,12 @@ +error: borrowed data cannot be stored outside of its closure + --> $DIR/regions-escape-unboxed-closure.rs:16:32 + | +16 | with_int(&mut |y| x = Some(y)); + | --- -----^- + | | | | + | | | cannot be stored outside of its closure + | | cannot infer an appropriate lifetime + | borrowed data cannot outlive this closure + +error: aborting due to previous error + diff --git a/src/test/compile-fail/closure-expected-type/expect-region-supply-region.rs b/src/test/ui/closure-expected-type/expect-region-supply-region.rs similarity index 90% rename from src/test/compile-fail/closure-expected-type/expect-region-supply-region.rs rename to src/test/ui/closure-expected-type/expect-region-supply-region.rs index 678647ff28da5..a464c5853e1c1 100644 --- a/src/test/compile-fail/closure-expected-type/expect-region-supply-region.rs +++ b/src/test/ui/closure-expected-type/expect-region-supply-region.rs @@ -25,7 +25,7 @@ fn expect_bound_supply_nothing() { // it to escape into `f`: let mut f: Option<&u32> = None; closure_expecting_bound(|x| { - f = Some(x); //~ ERROR borrowed data cannot be moved outside of its closure + f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure }); } @@ -35,7 +35,7 @@ fn expect_bound_supply_bound() { // closure: let mut f: Option<&u32> = None; closure_expecting_bound(|x: &u32| { - f = Some(x); //~ ERROR borrowed data cannot be moved outside of its closure + f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure }); } @@ -50,7 +50,7 @@ fn expect_bound_supply_named<'x>() { // And we still cannot let `x` escape into `f`. f = Some(x); - //~^ ERROR borrowed data cannot be moved outside of its closure + //~^ ERROR borrowed data cannot be stored outside of its closure }); } diff --git a/src/test/ui/closure-expected-type/expect-region-supply-region.stderr b/src/test/ui/closure-expected-type/expect-region-supply-region.stderr new file mode 100644 index 0000000000000..d34b17bb25b5f --- /dev/null +++ b/src/test/ui/closure-expected-type/expect-region-supply-region.stderr @@ -0,0 +1,100 @@ +error: borrowed data cannot be stored outside of its closure + --> $DIR/expect-region-supply-region.rs:28:18 + | +27 | closure_expecting_bound(|x| { + | --- borrowed data cannot outlive this closure +28 | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure + | -----^- + | | | + | | cannot be stored outside of its closure + | cannot infer an appropriate lifetime + +error: borrowed data cannot be stored outside of its closure + --> $DIR/expect-region-supply-region.rs:38:18 + | +37 | closure_expecting_bound(|x: &u32| { + | --------- borrowed data cannot outlive this closure +38 | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure + | -----^- + | | | + | | cannot be stored outside of its closure + | cannot infer an appropriate lifetime + +error[E0308]: mismatched types + --> $DIR/expect-region-supply-region.rs:47:33 + | +47 | closure_expecting_bound(|x: &'x u32| { + | ^^^^^^^ lifetime mismatch + | + = note: expected type `&u32` + found type `&'x u32` +note: the anonymous lifetime #2 defined on the body at 47:29... + --> $DIR/expect-region-supply-region.rs:47:29 + | +47 | closure_expecting_bound(|x: &'x u32| { + | _____________________________^ +48 | | //~^ ERROR mismatched types +49 | | //~| ERROR mismatched types +50 | | +... | +53 | | //~^ ERROR borrowed data cannot be stored outside of its closure +54 | | }); + | |_____^ +note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 42:1 + --> $DIR/expect-region-supply-region.rs:42:1 + | +42 | / fn expect_bound_supply_named<'x>() { +43 | | let mut f: Option<&u32> = None; +44 | | +45 | | // Here we give a type annotation that `x` should be free. We get +... | +54 | | }); +55 | | } + | |_^ + +error[E0308]: mismatched types + --> $DIR/expect-region-supply-region.rs:47:33 + | +47 | closure_expecting_bound(|x: &'x u32| { + | ^^^^^^^ lifetime mismatch + | + = note: expected type `&u32` + found type `&'x u32` +note: the lifetime 'x as defined on the function body at 42:1... + --> $DIR/expect-region-supply-region.rs:42:1 + | +42 | / fn expect_bound_supply_named<'x>() { +43 | | let mut f: Option<&u32> = None; +44 | | +45 | | // Here we give a type annotation that `x` should be free. We get +... | +54 | | }); +55 | | } + | |_^ +note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 47:29 + --> $DIR/expect-region-supply-region.rs:47:29 + | +47 | closure_expecting_bound(|x: &'x u32| { + | _____________________________^ +48 | | //~^ ERROR mismatched types +49 | | //~| ERROR mismatched types +50 | | +... | +53 | | //~^ ERROR borrowed data cannot be stored outside of its closure +54 | | }); + | |_____^ + +error: borrowed data cannot be stored outside of its closure + --> $DIR/expect-region-supply-region.rs:52:18 + | +47 | closure_expecting_bound(|x: &'x u32| { + | ------------ borrowed data cannot outlive this closure +... +52 | f = Some(x); + | -----^- + | | | + | | cannot be stored outside of its closure + | cannot infer an appropriate lifetime + +error: aborting due to 5 previous errors + From 6f9ecaa7cf0a15db46d13d72932acb2d678c29f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 19 Jan 2018 12:30:30 -0800 Subject: [PATCH 6/6] Tweak wording and spans of closure lifetime errors --- .../nice_region_error/outlives_closure.rs | 36 +++++++++++++++++-- src/test/ui/borrowck/issue-7573.rs | 1 + src/test/ui/borrowck/issue-7573.stderr | 12 ++++--- .../borrowck/regions-escape-bound-fn.stderr | 10 +++--- .../regions-escape-unboxed-closure.stderr | 10 +++--- .../expect-region-supply-region.stderr | 28 +++++++-------- 6 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs index f6a99579598ca..95f44b813c5d2 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs @@ -69,16 +69,46 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { sup_sp, "borrowed data cannot be stored outside of its closure"); err.span_label(sup_sp, "cannot be stored outside of its closure"); - if sup_sp == origin_sp { + if origin_sp == sup_sp || origin_sp.contains(sup_sp) { +// // sup_sp == origin.span(): +// +// let mut x = None; +// ----- borrowed data cannot be stored into here... +// with_int(|y| x = Some(y)); +// --- ^ cannot be stored outside of its closure +// | +// ...because it cannot outlive this closure +// +// // origin.contains(&sup_sp): +// +// let mut f: Option<&u32> = None; +// ----- borrowed data cannot be stored into here... +// closure_expecting_bound(|x: &'x u32| { +// ------------ ... because it cannot outlive this closure +// f = Some(x); +// ^ cannot be stored outside of its closure err.span_label(*external_span, "borrowed data cannot be stored into here..."); err.span_label(*closure_span, "...because it cannot outlive this closure"); } else { +// FIXME: the wording for this case could be much improved +// +// let mut lines_to_use: Vec<&CrateId> = Vec::new(); +// - cannot infer an appropriate lifetime... +// let push_id = |installed_id: &CrateId| { +// ------- ------------------------ borrowed data cannot outlive this closure +// | +// ...so that variable is valid at time of its declaration +// lines_to_use.push(installed_id); +// ^^^^^^^^^^^^ cannot be stored outside of its closure + err.span_label(origin_sp, + "cannot infer an appropriate lifetime..."); + err.span_label(*external_span, + "...so that variable is valid at time of its \ + declaration"); err.span_label(*closure_span, "borrowed data cannot outlive this closure"); - err.span_label(origin_sp, - "cannot infer an appropriate lifetime"); } err.emit(); return Some(ErrorReported); diff --git a/src/test/ui/borrowck/issue-7573.rs b/src/test/ui/borrowck/issue-7573.rs index b318bd70cf2d2..8f1545fa00986 100644 --- a/src/test/ui/borrowck/issue-7573.rs +++ b/src/test/ui/borrowck/issue-7573.rs @@ -28,6 +28,7 @@ pub fn remove_package_from_database() { //~^ NOTE cannot infer an appropriate lifetime let push_id = |installed_id: &CrateId| { //~^ NOTE borrowed data cannot outlive this closure + //~| NOTE ...so that variable is valid at time of its declaration lines_to_use.push(installed_id); //~^ ERROR borrowed data cannot be stored outside of its closure //~| NOTE cannot be stored outside of its closure diff --git a/src/test/ui/borrowck/issue-7573.stderr b/src/test/ui/borrowck/issue-7573.stderr index 6c549a029b602..99b48d9276c06 100644 --- a/src/test/ui/borrowck/issue-7573.stderr +++ b/src/test/ui/borrowck/issue-7573.stderr @@ -1,13 +1,15 @@ error: borrowed data cannot be stored outside of its closure - --> $DIR/issue-7573.rs:31:27 + --> $DIR/issue-7573.rs:32:27 | 27 | let mut lines_to_use: Vec<&CrateId> = Vec::new(); - | - cannot infer an appropriate lifetime + | - cannot infer an appropriate lifetime... 28 | //~^ NOTE cannot infer an appropriate lifetime 29 | let push_id = |installed_id: &CrateId| { - | ------------------------ borrowed data cannot outlive this closure -30 | //~^ NOTE borrowed data cannot outlive this closure -31 | lines_to_use.push(installed_id); + | ------- ------------------------ borrowed data cannot outlive this closure + | | + | ...so that variable is valid at time of its declaration +... +32 | lines_to_use.push(installed_id); | ^^^^^^^^^^^^ cannot be stored outside of its closure error: aborting due to previous error diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.stderr b/src/test/ui/borrowck/regions-escape-bound-fn.stderr index 306da8b54e4f7..a2ad7c3f768c6 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn.stderr +++ b/src/test/ui/borrowck/regions-escape-bound-fn.stderr @@ -1,12 +1,12 @@ error: borrowed data cannot be stored outside of its closure --> $DIR/regions-escape-bound-fn.rs:18:27 | +17 | let mut x: Option<&isize> = None; + | ----- borrowed data cannot be stored into here... 18 | with_int(|y| x = Some(y)); - | --- -----^- - | | | | - | | | cannot be stored outside of its closure - | | cannot infer an appropriate lifetime - | borrowed data cannot outlive this closure + | --- ^ cannot be stored outside of its closure + | | + | ...because it cannot outlive this closure error: aborting due to previous error diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr b/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr index 5e51be4629539..4b01e42fa67d0 100644 --- a/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr +++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr @@ -1,12 +1,12 @@ error: borrowed data cannot be stored outside of its closure --> $DIR/regions-escape-unboxed-closure.rs:16:32 | +15 | let mut x: Option<&isize> = None; + | ----- borrowed data cannot be stored into here... 16 | with_int(&mut |y| x = Some(y)); - | --- -----^- - | | | | - | | | cannot be stored outside of its closure - | | cannot infer an appropriate lifetime - | borrowed data cannot outlive this closure + | --- ^ cannot be stored outside of its closure + | | + | ...because it cannot outlive this closure error: aborting due to previous error diff --git a/src/test/ui/closure-expected-type/expect-region-supply-region.stderr b/src/test/ui/closure-expected-type/expect-region-supply-region.stderr index d34b17bb25b5f..ebb1e561e57ab 100644 --- a/src/test/ui/closure-expected-type/expect-region-supply-region.stderr +++ b/src/test/ui/closure-expected-type/expect-region-supply-region.stderr @@ -1,24 +1,22 @@ error: borrowed data cannot be stored outside of its closure --> $DIR/expect-region-supply-region.rs:28:18 | +26 | let mut f: Option<&u32> = None; + | ----- borrowed data cannot be stored into here... 27 | closure_expecting_bound(|x| { - | --- borrowed data cannot outlive this closure + | --- ...because it cannot outlive this closure 28 | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure - | -----^- - | | | - | | cannot be stored outside of its closure - | cannot infer an appropriate lifetime + | ^ cannot be stored outside of its closure error: borrowed data cannot be stored outside of its closure --> $DIR/expect-region-supply-region.rs:38:18 | +36 | let mut f: Option<&u32> = None; + | ----- borrowed data cannot be stored into here... 37 | closure_expecting_bound(|x: &u32| { - | --------- borrowed data cannot outlive this closure + | --------- ...because it cannot outlive this closure 38 | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure - | -----^- - | | | - | | cannot be stored outside of its closure - | cannot infer an appropriate lifetime + | ^ cannot be stored outside of its closure error[E0308]: mismatched types --> $DIR/expect-region-supply-region.rs:47:33 @@ -87,14 +85,14 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the b error: borrowed data cannot be stored outside of its closure --> $DIR/expect-region-supply-region.rs:52:18 | +43 | let mut f: Option<&u32> = None; + | ----- borrowed data cannot be stored into here... +... 47 | closure_expecting_bound(|x: &'x u32| { - | ------------ borrowed data cannot outlive this closure + | ------------ ...because it cannot outlive this closure ... 52 | f = Some(x); - | -----^- - | | | - | | cannot be stored outside of its closure - | cannot infer an appropriate lifetime + | ^ cannot be stored outside of its closure error: aborting due to 5 previous errors