Skip to content

Commit 15713e1

Browse files
author
Yan Chen
committed
Fix #95079 by adding help and suggestion for missing move in nested closure
1 parent 4916e2b commit 15713e1

7 files changed

+104
-0
lines changed

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

+37
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
546546
executing...",
547547
);
548548
diag.note("...therefore, they cannot allow references to captured variables to escape");
549+
self.suggest_move_on_borrowing_closure(&mut diag);
549550

550551
diag
551552
}
@@ -716,6 +717,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
716717

717718
self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
718719
self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
720+
self.suggest_move_on_borrowing_closure(&mut diag);
719721

720722
diag
721723
}
@@ -901,4 +903,39 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
901903

902904
suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
903905
}
906+
907+
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
908+
let map = self.infcx.tcx.hir();
909+
let body_id = map.body_owned_by(self.mir_def_id());
910+
let expr = &map.body(body_id).value;
911+
let mut closure_span = None::<rustc_span::Span>;
912+
match expr.kind {
913+
hir::ExprKind::MethodCall(.., args, _) => {
914+
// only the first closre parameter of the method. args[0] is MethodCall PathSegment
915+
for i in 1..args.len() {
916+
if let hir::ExprKind::Closure(..) = args[i].kind {
917+
closure_span = Some(args[i].span.shrink_to_lo());
918+
break;
919+
}
920+
}
921+
}
922+
hir::ExprKind::Block(blk, _) => {
923+
if let Some(ref expr) = blk.expr {
924+
// only when the block is a closure
925+
if let hir::ExprKind::Closure(..) = expr.kind {
926+
closure_span = Some(expr.span.shrink_to_lo());
927+
}
928+
}
929+
}
930+
_ => {}
931+
}
932+
if let Some(closure_span) = closure_span {
933+
diag.span_suggestion_verbose(
934+
closure_span,
935+
format!("consider adding 'move' keyword before the nested closure"),
936+
"move ",
937+
Applicability::MaybeIncorrect,
938+
);
939+
}
940+
}
904941
}

src/test/ui/borrowck/borrowck-describe-lvalue.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ LL | | }
3636
|
3737
= note: `FnMut` closures only have access to their captured variables while they are executing...
3838
= note: ...therefore, they cannot allow references to captured variables to escape
39+
help: consider adding 'move' keyword before the nested closure
40+
|
41+
LL | move || {
42+
| ++++
3943

4044
error[E0503]: cannot use `f.x` because it was mutably borrowed
4145
--> $DIR/borrowck-describe-lvalue.rs:37:9

src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ LL | || f() // The `nested` closure
1010
| ^^^^^^ returning this value requires that `'1` must outlive `'2`
1111
|
1212
= note: closure implements `Fn`, so references to captured variables can't escape the closure
13+
help: consider adding 'move' keyword before the nested closure
14+
|
15+
LL | move || f() // The `nested` closure
16+
| ++++
1317

1418
error: aborting due to previous error
1519

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
fn foo1(s: &str) -> impl Iterator<Item = String> + '_ {
2+
None.into_iter()
3+
.flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s)))
4+
//~^ ERROR captured variable cannot escape `FnMut` closure body
5+
//~| HELP consider adding 'move' keyword before the nested closure
6+
}
7+
8+
fn foo2(s: &str) -> impl Sized + '_ {
9+
move |()| s.chars().map(|c| format!("{}{}", c, s))
10+
//~^ ERROR lifetime may not live long enough
11+
//~| HELP consider adding 'move' keyword before the nested closure
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
error: captured variable cannot escape `FnMut` closure body
2+
--> $DIR/issue-95079-missing-move-in-nested-closure.rs:3:29
3+
|
4+
LL | fn foo1(s: &str) -> impl Iterator<Item = String> + '_ {
5+
| - variable defined here
6+
LL | None.into_iter()
7+
LL | .flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s)))
8+
| - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9+
| | |
10+
| | returns a reference to a captured variable which escapes the closure body
11+
| | variable captured here
12+
| inferred to be a `FnMut` closure
13+
|
14+
= note: `FnMut` closures only have access to their captured variables while they are executing...
15+
= note: ...therefore, they cannot allow references to captured variables to escape
16+
help: consider adding 'move' keyword before the nested closure
17+
|
18+
LL | .flat_map(move |()| s.chars().map(move |c| format!("{}{}", c, s)))
19+
| ++++
20+
21+
error: lifetime may not live long enough
22+
--> $DIR/issue-95079-missing-move-in-nested-closure.rs:9:15
23+
|
24+
LL | move |()| s.chars().map(|c| format!("{}{}", c, s))
25+
| --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
26+
| | |
27+
| | return type of closure `Map<Chars<'_>, [closure@$DIR/issue-95079-missing-move-in-nested-closure.rs:9:29: 9:32]>` contains a lifetime `'2`
28+
| lifetime `'1` represents this closure's body
29+
|
30+
= note: closure implements `Fn`, so references to captured variables can't escape the closure
31+
help: consider adding 'move' keyword before the nested closure
32+
|
33+
LL | move |()| s.chars().map(move |c| format!("{}{}", c, s))
34+
| ++++
35+
36+
error: aborting due to 2 previous errors
37+

src/test/ui/issues/issue-40510-3.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ LL | | }
1414
|
1515
= note: `FnMut` closures only have access to their captured variables while they are executing...
1616
= note: ...therefore, they cannot allow references to captured variables to escape
17+
help: consider adding 'move' keyword before the nested closure
18+
|
19+
LL | move || {
20+
| ++++
1721

1822
error: aborting due to previous error
1923

src/test/ui/issues/issue-49824.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ LL | | }
1414
|
1515
= note: `FnMut` closures only have access to their captured variables while they are executing...
1616
= note: ...therefore, they cannot allow references to captured variables to escape
17+
help: consider adding 'move' keyword before the nested closure
18+
|
19+
LL | move || {
20+
| ++++
1721

1822
error: aborting due to previous error
1923

0 commit comments

Comments
 (0)