Skip to content

Commit d7df1b1

Browse files
authored
Rollup merge of #87958 - m-ou-se:closure-migration-multispan-suggestions, r=estebank
Closure migration multispan suggestions This changes the `rust_2021_incompatible_closure_captures` lint to only suggest inserting the parts that need to be inserted, instead of suggesting to replace the entire closure by an almost identical closure with one statement added. Before: ``` [...] help: add a dummy let to cause `a` to be fully captured | 5 ~ let _ = || { 6 + let _ = &a; 7 + dbg!(a.0); 8 + println!("1"); 9 + println!("2"); 10 + println!("3"); ... | [...] help: add a dummy let to cause `b` to be fully captured | 14 | let _ = || { let _ = &b; dbg!(b.0); }; | ~~~~~~~~~~~~~~~~~~~~~~~~~~ [...] help: add a dummy let to cause `c` to be fully captured | 16 | let _ = || { let _ = &c; dbg!(c.0) }; | ~~~~~~~~~~~~~~~~~~~~~~~~~ ``` After: ``` [...] help: add a dummy let to cause `a` to be fully captured | 5 ~ let _ = || { 6 + let _ = &a; | [...] help: add a dummy let to cause `b` to be fully captured | 14 | let _ = || { let _ = &b; dbg!(b.0); }; | +++++++++++ [...] help: add a dummy let to cause `c` to be fully captured | 16 | let _ = || { let _ = &c; dbg!(c.0) }; | +++++++++++++ + ```
2 parents 84ca374 + 6431097 commit d7df1b1

10 files changed

+97
-189
lines changed

compiler/rustc_typeck/src/check/upvar.rs

+53-37
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use rustc_middle::ty::{
4747
};
4848
use rustc_session::lint;
4949
use rustc_span::sym;
50-
use rustc_span::{MultiSpan, Span, Symbol, DUMMY_SP};
50+
use rustc_span::{BytePos, MultiSpan, Pos, Span, Symbol, DUMMY_SP};
5151
use rustc_trait_selection::infer::InferCtxtExt;
5252

5353
use rustc_data_structures::stable_map::FxHashMap;
@@ -645,6 +645,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
645645
}
646646
diagnostics_builder.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
647647

648+
let diagnostic_msg = format!(
649+
"add a dummy let to cause {} to be fully captured",
650+
migrated_variables_concat
651+
);
652+
648653
let mut closure_body_span = self.tcx.hir().span(body_id.hir_id);
649654

650655
// If the body was entirely expanded from a macro
@@ -655,43 +660,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
655660
closure_body_span = closure_body_span.parent().unwrap_or(DUMMY_SP);
656661
}
657662

658-
let (span, sugg, app) =
659-
match self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
660-
Ok(s) => {
661-
let trimmed = s.trim_start();
662-
let mut lines = trimmed.lines();
663-
let line1 = lines.next().unwrap_or_default();
664-
665-
// If the closure contains a block then replace the opening brace
666-
// with "{ let _ = (..); "
667-
let sugg = if line1.trim_end() == "{" {
668-
// This is a multi-line closure with just a `{` on the first line,
669-
// so we put the `let` on its own line.
670-
// We take the indentation from the next non-empty line.
671-
let line2 = lines.filter(|line| !line.is_empty()).next().unwrap_or_default();
672-
let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0;
673-
format!("{{\n{}{};{}", indent, migration_string, &trimmed[line1.len()..])
674-
} else if line1.starts_with('{') {
675-
format!("{{ {}; {}", migration_string, &trimmed[1..].trim_start())
676-
} else {
677-
format!("{{ {}; {} }}", migration_string, s)
678-
};
679-
(closure_body_span, sugg, Applicability::MachineApplicable)
680-
}
681-
Err(_) => (closure_span, migration_string.clone(), Applicability::HasPlaceholders),
682-
};
683-
684-
let diagnostic_msg = format!(
685-
"add a dummy let to cause {} to be fully captured",
686-
migrated_variables_concat
687-
);
663+
if let Ok(s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
664+
let mut lines = s.lines();
665+
let line1 = lines.next().unwrap_or_default();
666+
667+
if line1.trim_end() == "{" {
668+
// This is a multi-line closure with just a `{` on the first line,
669+
// so we put the `let` on its own line.
670+
// We take the indentation from the next non-empty line.
671+
let line2 = lines.filter(|line| !line.is_empty()).next().unwrap_or_default();
672+
let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0;
673+
diagnostics_builder.span_suggestion(
674+
closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
675+
&diagnostic_msg,
676+
format!("\n{}{};", indent, migration_string),
677+
Applicability::MachineApplicable,
678+
);
679+
} else if line1.starts_with('{') {
680+
// This is a closure with its body wrapped in
681+
// braces, but with more than just the opening
682+
// brace on the first line. We put the `let`
683+
// directly after the `{`.
684+
diagnostics_builder.span_suggestion(
685+
closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(),
686+
&diagnostic_msg,
687+
format!(" {};", migration_string),
688+
Applicability::MachineApplicable,
689+
);
690+
} else {
691+
// This is a closure without braces around the body.
692+
// We add braces to add the `let` before the body.
693+
diagnostics_builder.multipart_suggestion(
694+
&diagnostic_msg,
695+
vec![
696+
(closure_body_span.shrink_to_lo(), format!("{{ {}; ", migration_string)),
697+
(closure_body_span.shrink_to_hi(), " }".to_string()),
698+
],
699+
Applicability::MachineApplicable
700+
);
701+
}
702+
} else {
703+
diagnostics_builder.span_suggestion(
704+
closure_span,
705+
&diagnostic_msg,
706+
migration_string,
707+
Applicability::HasPlaceholders
708+
);
709+
}
688710

689-
diagnostics_builder.span_suggestion(
690-
span,
691-
&diagnostic_msg,
692-
sugg,
693-
app,
694-
);
695711
diagnostics_builder.emit();
696712
},
697713
);

src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr

+11-15
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ LL | #![deny(rust_2021_incompatible_closure_captures)]
1616
help: add a dummy let to cause `fptr` to be fully captured
1717
|
1818
LL ~ thread::spawn(move || { let _ = &fptr; unsafe {
19-
LL +
20-
LL +
21-
LL +
22-
LL +
23-
LL + *fptr.0 = 20;
19+
LL |
20+
LL |
21+
LL |
22+
LL |
23+
LL | *fptr.0 = 20;
2424
...
2525

2626
error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
@@ -36,11 +36,11 @@ LL | *fptr.0.0 = 20;
3636
help: add a dummy let to cause `fptr` to be fully captured
3737
|
3838
LL ~ thread::spawn(move || { let _ = &fptr; unsafe {
39-
LL +
40-
LL +
41-
LL +
42-
LL +
43-
LL + *fptr.0.0 = 20;
39+
LL |
40+
LL |
41+
LL |
42+
LL |
43+
LL | *fptr.0.0 = 20;
4444
...
4545

4646
error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
@@ -60,11 +60,7 @@ help: add a dummy let to cause `f` to be fully captured
6060
|
6161
LL ~ let c = || {
6262
LL + let _ = &f;
63-
LL +
64-
LL +
65-
LL +
66-
LL +
67-
...
63+
|
6864

6965
error: aborting due to 3 previous errors
7066

src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr

+7-35
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,7 @@ help: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
3030
|
3131
LL ~ let c = || {
3232
LL + let _ = (&t, &t1, &t2);
33-
LL +
34-
LL +
35-
LL +
36-
LL +
37-
...
33+
|
3834

3935
error: changes to closure capture in Rust 2021 will affect drop order
4036
--> $DIR/insignificant_drop.rs:41:13
@@ -59,11 +55,7 @@ help: add a dummy let to cause `t`, `t1` to be fully captured
5955
|
6056
LL ~ let c = || {
6157
LL + let _ = (&t, &t1);
62-
LL +
63-
LL +
64-
LL +
65-
LL + let _t = t.0;
66-
...
58+
|
6759

6860
error: changes to closure capture in Rust 2021 will affect drop order
6961
--> $DIR/insignificant_drop.rs:62:13
@@ -82,11 +74,7 @@ help: add a dummy let to cause `t` to be fully captured
8274
|
8375
LL ~ let c = || {
8476
LL + let _ = &t;
85-
LL +
86-
LL +
87-
LL +
88-
LL + let _t = t.0;
89-
...
77+
|
9078

9179
error: changes to closure capture in Rust 2021 will affect drop order
9280
--> $DIR/insignificant_drop.rs:83:13
@@ -105,11 +93,7 @@ help: add a dummy let to cause `t` to be fully captured
10593
|
10694
LL ~ let c = || {
10795
LL + let _ = &t;
108-
LL +
109-
LL +
110-
LL +
111-
LL + let _t = t.0;
112-
...
96+
|
11397

11498
error: changes to closure capture in Rust 2021 will affect drop order
11599
--> $DIR/insignificant_drop.rs:104:13
@@ -128,11 +112,7 @@ help: add a dummy let to cause `t` to be fully captured
128112
|
129113
LL ~ let c = || {
130114
LL + let _ = &t;
131-
LL +
132-
LL +
133-
LL +
134-
LL + let _t = t.0;
135-
...
115+
|
136116

137117
error: changes to closure capture in Rust 2021 will affect drop order
138118
--> $DIR/insignificant_drop.rs:122:13
@@ -156,11 +136,7 @@ help: add a dummy let to cause `t1`, `t` to be fully captured
156136
|
157137
LL ~ let c = move || {
158138
LL + let _ = (&t1, &t);
159-
LL +
160-
LL +
161-
LL +
162-
LL + println!("{} {}", t1.1, t.1);
163-
...
139+
|
164140

165141
error: changes to closure capture in Rust 2021 will affect drop order
166142
--> $DIR/insignificant_drop.rs:142:13
@@ -179,11 +155,7 @@ help: add a dummy let to cause `t` to be fully captured
179155
|
180156
LL ~ let c = || {
181157
LL + let _ = &t;
182-
LL +
183-
LL +
184-
LL +
185-
LL + let _t = t.0;
186-
...
158+
|
187159

188160
error: aborting due to 7 previous errors
189161

src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr

+2-10
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@ help: add a dummy let to cause `t` to be fully captured
2020
|
2121
LL ~ let c = || {
2222
LL + let _ = &t;
23-
LL +
24-
LL +
25-
LL +
26-
LL + let _t = t.0;
27-
...
23+
|
2824

2925
error: changes to closure capture in Rust 2021 will affect drop order
3026
--> $DIR/insignificant_drop_attr_migrations.rs:57:13
@@ -43,11 +39,7 @@ help: add a dummy let to cause `t` to be fully captured
4339
|
4440
LL ~ let c = move || {
4541
LL + let _ = &t;
46-
LL +
47-
LL +
48-
LL +
49-
LL + let _t = t.1;
50-
...
42+
|
5143

5244
error: aborting due to 2 previous errors
5345

src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ LL | #![deny(rust_2021_incompatible_closure_captures)]
1818
help: add a dummy let to cause `a` to be fully captured
1919
|
2020
LL | let _ = || { let _ = &a; dbg!(a.0) };
21-
| ~~~~~~~~~~~~~~~~~~~~~~~~~
21+
| +++++++++++++ +
2222

2323
error: aborting due to previous error
2424

src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr

+2-6
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@ help: add a dummy let to cause `t` to be fully captured
2020
|
2121
LL ~ let c = || {
2222
LL + let _ = &t;
23-
LL +
24-
LL +
25-
LL +
26-
LL + let _t = t.0;
27-
...
23+
|
2824

2925
error: changes to closure capture in Rust 2021 will affect drop order
3026
--> $DIR/migrations_rustfix.rs:33:13
@@ -41,7 +37,7 @@ LL | }
4137
help: add a dummy let to cause `t` to be fully captured
4238
|
4339
LL | let c = || { let _ = &t; t.0 };
44-
| ~~~~~~~~~~~~~~~~~~~
40+
| +++++++++++++ +
4541

4642
error: aborting due to 2 previous errors
4743

src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr

+1-5
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@ help: add a dummy let to cause `f` to be fully captured
1717
|
1818
LL ~ let result = panic::catch_unwind(move || {
1919
LL + let _ = &f;
20-
LL +
21-
LL +
22-
LL +
23-
LL +
24-
...
20+
|
2521

2622
error: aborting due to previous error
2723

src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr

+9-25
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,7 @@ help: add a dummy let to cause `f1`, `f2` to be fully captured
2323
|
2424
LL ~ let c = || {
2525
LL + let _ = (&f1, &f2);
26-
LL +
27-
LL +
28-
LL +
29-
LL +
30-
...
26+
|
3127

3228
error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
3329
--> $DIR/multi_diagnostics.rs:42:13
@@ -43,11 +39,7 @@ help: add a dummy let to cause `f1` to be fully captured
4339
|
4440
LL ~ let c = || {
4541
LL + let _ = &f1;
46-
LL +
47-
LL +
48-
LL +
49-
LL +
50-
...
42+
|
5143

5244
error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
5345
--> $DIR/multi_diagnostics.rs:67:13
@@ -69,11 +61,7 @@ help: add a dummy let to cause `f1` to be fully captured
6961
|
7062
LL ~ let c = || {
7163
LL + let _ = &f1;
72-
LL +
73-
LL +
74-
LL +
75-
LL +
76-
...
64+
|
7765

7866
error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
7967
--> $DIR/multi_diagnostics.rs:86:13
@@ -98,11 +86,7 @@ help: add a dummy let to cause `f1` to be fully captured
9886
|
9987
LL ~ let c = || {
10088
LL + let _ = &f1;
101-
LL +
102-
LL +
103-
LL +
104-
LL +
105-
...
89+
|
10690

10791
error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
10892
--> $DIR/multi_diagnostics.rs:119:19
@@ -123,11 +107,11 @@ LL | *fptr2.0 = 20;
123107
help: add a dummy let to cause `fptr1`, `fptr2` to be fully captured
124108
|
125109
LL ~ thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe {
126-
LL +
127-
LL +
128-
LL +
129-
LL +
130-
LL +
110+
LL |
111+
LL |
112+
LL |
113+
LL |
114+
LL |
131115
...
132116

133117
error: aborting due to 5 previous errors

0 commit comments

Comments
 (0)