@@ -47,7 +47,7 @@ use rustc_middle::ty::{
4747} ;
4848use rustc_session:: lint;
4949use rustc_span:: sym;
50- use rustc_span:: { MultiSpan , Span , Symbol , DUMMY_SP } ;
50+ use rustc_span:: { BytePos , MultiSpan , Pos , Span , Symbol , DUMMY_SP } ;
5151use rustc_trait_selection:: infer:: InferCtxtExt ;
5252
5353use 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