@@ -47,7 +47,7 @@ use rustc_middle::ty::{
47
47
} ;
48
48
use rustc_session:: lint;
49
49
use rustc_span:: sym;
50
- use rustc_span:: { MultiSpan , Span , Symbol , DUMMY_SP } ;
50
+ use rustc_span:: { BytePos , MultiSpan , Pos , Span , Symbol , DUMMY_SP } ;
51
51
use rustc_trait_selection:: infer:: InferCtxtExt ;
52
52
53
53
use rustc_data_structures:: stable_map:: FxHashMap ;
@@ -645,6 +645,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
645
645
}
646
646
diagnostics_builder. note ( "for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>" ) ;
647
647
648
+ let diagnostic_msg = format ! (
649
+ "add a dummy let to cause {} to be fully captured" ,
650
+ migrated_variables_concat
651
+ ) ;
652
+
648
653
let mut closure_body_span = self . tcx . hir ( ) . span ( body_id. hir_id ) ;
649
654
650
655
// If the body was entirely expanded from a macro
@@ -655,43 +660,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
655
660
closure_body_span = closure_body_span. parent ( ) . unwrap_or ( DUMMY_SP ) ;
656
661
}
657
662
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
+ }
688
710
689
- diagnostics_builder. span_suggestion (
690
- span,
691
- & diagnostic_msg,
692
- sugg,
693
- app,
694
- ) ;
695
711
diagnostics_builder. emit ( ) ;
696
712
} ,
697
713
) ;
0 commit comments