Custom error when moving arg outside of its closure
When given the following code:
```rust
fn give_any<F: for<'r> 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;
| ^^^^^
```
This commit is contained in:
parent
bb345a0be3
commit
846042161c
4 changed files with 67 additions and 2 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -16,5 +16,5 @@ fn with_int<F>(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
|
||||
}
|
||||
|
|
|
|||
19
src/test/ui/borrowck/issue-45983.rs
Normal file
19
src/test/ui/borrowck/issue-45983.rs
Normal file
|
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn give_any<F: for<'r> 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
|
||||
}
|
||||
12
src/test/ui/borrowck/issue-45983.stderr
Normal file
12
src/test/ui/borrowck/issue-45983.stderr
Normal file
|
|
@ -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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue