Skip to content

Commit 111201d

Browse files
committed
Use multi span suggestions for closure migrations.
1 parent 23461b2 commit 111201d

File tree

1 file changed

+53
-37
lines changed

1 file changed

+53
-37
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
);

0 commit comments

Comments
 (0)