@@ -35,6 +35,7 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError
3535use rustc_session:: parse:: ParseSess ;
3636use rustc_span:: source_map:: { Span , DUMMY_SP } ;
3737use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
38+ use rustc_span:: MultiSpan ;
3839use tracing:: debug;
3940
4041use std:: ops:: Range ;
@@ -145,7 +146,11 @@ pub struct Parser<'a> {
145146
146147 /// This allows us to recover when the user forget to add braces around
147148 /// multiple statements in the closure body.
148- pub last_closure_body : Option < Span /* The closing `|` of the closure declarator. */ > ,
149+ pub last_closure_body : Option < (
150+ Span , /* The whole body. */
151+ Span , /* The closing `|` of the closure declarator. */
152+ Span , /* What we parsed as closure body. */
153+ ) > ,
149154}
150155
151156/// Indicates a range of tokens that should be replaced by
@@ -779,15 +784,19 @@ impl<'a> Parser<'a> {
779784 let token_str = pprust:: token_kind_to_string ( t) ;
780785
781786 match self . last_closure_body . take ( ) {
782- Some ( right_pipe_span) if self . token . kind == TokenKind :: Semi => {
787+ Some ( ( closure_span, right_pipe_span, expr_span) )
788+ if self . token . kind == TokenKind :: Semi =>
789+ {
783790 // Finding a semicolon instead of a comma
784791 // after a closure body indicates that the
785792 // closure body may be a block but the user
786793 // forgot to put braces around its
787794 // statements.
788795
789796 self . recover_missing_braces_around_closure_body (
797+ closure_span,
790798 right_pipe_span,
799+ expr_span,
791800 expect_err,
792801 ) ?;
793802
@@ -868,16 +877,13 @@ impl<'a> Parser<'a> {
868877
869878 fn recover_missing_braces_around_closure_body (
870879 & mut self ,
880+ closure_span : Span ,
871881 right_pipe_span : Span ,
882+ expr_span : Span ,
872883 mut expect_err : DiagnosticBuilder < ' _ > ,
873884 ) -> PResult < ' a , ( ) > {
874885 let initial_semicolon = self . token . span ;
875886
876- expect_err. span_help (
877- initial_semicolon,
878- "This `;` turns the expression into a statement, which must be placed in a block" ,
879- ) ;
880-
881887 while self . eat ( & TokenKind :: Semi ) {
882888 let _ = self . parse_stmt ( ForceCollect :: Yes ) ?;
883889 }
@@ -889,6 +895,25 @@ impl<'a> Parser<'a> {
889895 let preceding_pipe_span = right_pipe_span;
890896 let following_token_span = self . token . span ;
891897
898+ let mut first_note = MultiSpan :: from ( vec ! [ initial_semicolon] ) ;
899+ first_note. push_span_label (
900+ initial_semicolon,
901+ "this `;` turns the preceding expression into a statement" . to_string ( ) ,
902+ ) ;
903+ first_note. push_span_label (
904+ expr_span,
905+ "this expression is a statement because of the trailing semicolon" . to_string ( ) ,
906+ ) ;
907+ expect_err. span_note ( first_note, "statement found outside of a block" ) ;
908+
909+ let mut second_note = MultiSpan :: from ( vec ! [ closure_span] ) ;
910+ second_note. push_span_label ( closure_span, "this is the parsed closure..." . to_string ( ) ) ;
911+ second_note. push_span_label (
912+ following_token_span,
913+ "...but likely you meant the closure to end here" . to_string ( ) ,
914+ ) ;
915+ expect_err. span_note ( second_note, "the closure body may be incorrectly delimited" ) ;
916+
892917 expect_err. set_span ( vec ! [ preceding_pipe_span, following_token_span] ) ;
893918
894919 let opening_suggestion_str = " {" . to_string ( ) ;
0 commit comments