mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Fix #95079 by adding help and suggestion for missing move in nested closure
This commit is contained in:
parent
4916e2b9e6
commit
15713e1717
@ -546,6 +546,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
executing...",
|
executing...",
|
||||||
);
|
);
|
||||||
diag.note("...therefore, they cannot allow references to captured variables to escape");
|
diag.note("...therefore, they cannot allow references to captured variables to escape");
|
||||||
|
self.suggest_move_on_borrowing_closure(&mut diag);
|
||||||
|
|
||||||
diag
|
diag
|
||||||
}
|
}
|
||||||
@ -716,6 +717,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
|
self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
|
||||||
self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
|
self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
|
||||||
|
self.suggest_move_on_borrowing_closure(&mut diag);
|
||||||
|
|
||||||
diag
|
diag
|
||||||
}
|
}
|
||||||
@ -901,4 +903,39 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
|
suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
|
||||||
|
let map = self.infcx.tcx.hir();
|
||||||
|
let body_id = map.body_owned_by(self.mir_def_id());
|
||||||
|
let expr = &map.body(body_id).value;
|
||||||
|
let mut closure_span = None::<rustc_span::Span>;
|
||||||
|
match expr.kind {
|
||||||
|
hir::ExprKind::MethodCall(.., args, _) => {
|
||||||
|
// only the first closre parameter of the method. args[0] is MethodCall PathSegment
|
||||||
|
for i in 1..args.len() {
|
||||||
|
if let hir::ExprKind::Closure(..) = args[i].kind {
|
||||||
|
closure_span = Some(args[i].span.shrink_to_lo());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hir::ExprKind::Block(blk, _) => {
|
||||||
|
if let Some(ref expr) = blk.expr {
|
||||||
|
// only when the block is a closure
|
||||||
|
if let hir::ExprKind::Closure(..) = expr.kind {
|
||||||
|
closure_span = Some(expr.span.shrink_to_lo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
if let Some(closure_span) = closure_span {
|
||||||
|
diag.span_suggestion_verbose(
|
||||||
|
closure_span,
|
||||||
|
format!("consider adding 'move' keyword before the nested closure"),
|
||||||
|
"move ",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,10 @@ LL | | }
|
|||||||
|
|
|
|
||||||
= note: `FnMut` closures only have access to their captured variables while they are executing...
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
|
||||||
= note: ...therefore, they cannot allow references to captured variables to escape
|
= note: ...therefore, they cannot allow references to captured variables to escape
|
||||||
|
help: consider adding 'move' keyword before the nested closure
|
||||||
|
|
|
||||||
|
LL | move || {
|
||||||
|
| ++++
|
||||||
|
|
||||||
error[E0503]: cannot use `f.x` because it was mutably borrowed
|
error[E0503]: cannot use `f.x` because it was mutably borrowed
|
||||||
--> $DIR/borrowck-describe-lvalue.rs:37:9
|
--> $DIR/borrowck-describe-lvalue.rs:37:9
|
||||||
|
@ -10,6 +10,10 @@ LL | || f() // The `nested` closure
|
|||||||
| ^^^^^^ returning this value requires that `'1` must outlive `'2`
|
| ^^^^^^ returning this value requires that `'1` must outlive `'2`
|
||||||
|
|
|
|
||||||
= note: closure implements `Fn`, so references to captured variables can't escape the closure
|
= note: closure implements `Fn`, so references to captured variables can't escape the closure
|
||||||
|
help: consider adding 'move' keyword before the nested closure
|
||||||
|
|
|
||||||
|
LL | move || f() // The `nested` closure
|
||||||
|
| ++++
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
fn foo1(s: &str) -> impl Iterator<Item = String> + '_ {
|
||||||
|
None.into_iter()
|
||||||
|
.flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s)))
|
||||||
|
//~^ ERROR captured variable cannot escape `FnMut` closure body
|
||||||
|
//~| HELP consider adding 'move' keyword before the nested closure
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo2(s: &str) -> impl Sized + '_ {
|
||||||
|
move |()| s.chars().map(|c| format!("{}{}", c, s))
|
||||||
|
//~^ ERROR lifetime may not live long enough
|
||||||
|
//~| HELP consider adding 'move' keyword before the nested closure
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,37 @@
|
|||||||
|
error: captured variable cannot escape `FnMut` closure body
|
||||||
|
--> $DIR/issue-95079-missing-move-in-nested-closure.rs:3:29
|
||||||
|
|
|
||||||
|
LL | fn foo1(s: &str) -> impl Iterator<Item = String> + '_ {
|
||||||
|
| - variable defined here
|
||||||
|
LL | None.into_iter()
|
||||||
|
LL | .flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s)))
|
||||||
|
| - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
| | |
|
||||||
|
| | returns a reference to a captured variable which escapes the closure body
|
||||||
|
| | variable captured here
|
||||||
|
| inferred to be a `FnMut` closure
|
||||||
|
|
|
||||||
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
|
||||||
|
= note: ...therefore, they cannot allow references to captured variables to escape
|
||||||
|
help: consider adding 'move' keyword before the nested closure
|
||||||
|
|
|
||||||
|
LL | .flat_map(move |()| s.chars().map(move |c| format!("{}{}", c, s)))
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/issue-95079-missing-move-in-nested-closure.rs:9:15
|
||||||
|
|
|
||||||
|
LL | move |()| s.chars().map(|c| format!("{}{}", c, s))
|
||||||
|
| --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
|
||||||
|
| | |
|
||||||
|
| | return type of closure `Map<Chars<'_>, [closure@$DIR/issue-95079-missing-move-in-nested-closure.rs:9:29: 9:32]>` contains a lifetime `'2`
|
||||||
|
| lifetime `'1` represents this closure's body
|
||||||
|
|
|
||||||
|
= note: closure implements `Fn`, so references to captured variables can't escape the closure
|
||||||
|
help: consider adding 'move' keyword before the nested closure
|
||||||
|
|
|
||||||
|
LL | move |()| s.chars().map(move |c| format!("{}{}", c, s))
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -14,6 +14,10 @@ LL | | }
|
|||||||
|
|
|
|
||||||
= note: `FnMut` closures only have access to their captured variables while they are executing...
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
|
||||||
= note: ...therefore, they cannot allow references to captured variables to escape
|
= note: ...therefore, they cannot allow references to captured variables to escape
|
||||||
|
help: consider adding 'move' keyword before the nested closure
|
||||||
|
|
|
||||||
|
LL | move || {
|
||||||
|
| ++++
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -14,6 +14,10 @@ LL | | }
|
|||||||
|
|
|
|
||||||
= note: `FnMut` closures only have access to their captured variables while they are executing...
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
|
||||||
= note: ...therefore, they cannot allow references to captured variables to escape
|
= note: ...therefore, they cannot allow references to captured variables to escape
|
||||||
|
help: consider adding 'move' keyword before the nested closure
|
||||||
|
|
|
||||||
|
LL | move || {
|
||||||
|
| ++++
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user