@@ -6,7 +6,7 @@ use crate::ast::{
66 self , Param , BinOpKind , BindingMode , BlockCheckMode , Expr , ExprKind , Ident , Item , ItemKind ,
77 Mutability , Pat , PatKind , PathSegment , QSelf , Ty , TyKind ,
88} ;
9- use crate :: parse:: token:: { self , TokenKind } ;
9+ use crate :: parse:: token:: { self , TokenKind , token_can_begin_expr } ;
1010use crate :: print:: pprust;
1111use crate :: ptr:: P ;
1212use crate :: symbol:: { kw, sym} ;
@@ -274,23 +274,23 @@ impl<'a> Parser<'a> {
274274 expected. sort_by_cached_key ( |x| x. to_string ( ) ) ;
275275 expected. dedup ( ) ;
276276 let expect = tokens_to_string ( & expected[ ..] ) ;
277- let actual = self . this_token_to_string ( ) ;
277+ let actual = self . this_token_descr ( ) ;
278278 let ( msg_exp, ( label_sp, label_exp) ) = if expected. len ( ) > 1 {
279279 let short_expect = if expected. len ( ) > 6 {
280280 format ! ( "{} possible tokens" , expected. len( ) )
281281 } else {
282282 expect. clone ( )
283283 } ;
284- ( format ! ( "expected one of {}, found `{}` " , expect, actual) ,
284+ ( format ! ( "expected one of {}, found {} " , expect, actual) ,
285285 ( self . sess . source_map ( ) . next_point ( self . prev_span ) ,
286286 format ! ( "expected one of {} here" , short_expect) ) )
287287 } else if expected. is_empty ( ) {
288- ( format ! ( "unexpected token: `{}` " , actual) ,
288+ ( format ! ( "unexpected token: {} " , actual) ,
289289 ( self . prev_span , "unexpected token after this" . to_string ( ) ) )
290290 } else {
291- ( format ! ( "expected {}, found `{}` " , expect, actual) ,
291+ ( format ! ( "expected {}, found {} " , expect, actual) ,
292292 ( self . sess . source_map ( ) . next_point ( self . prev_span ) ,
293- format ! ( "expected {} here " , expect) ) )
293+ format ! ( "expected {}" , expect) ) )
294294 } ;
295295 self . last_unexpected_token_span = Some ( self . token . span ) ;
296296 let mut err = self . fatal ( & msg_exp) ;
@@ -326,58 +326,28 @@ impl<'a> Parser<'a> {
326326 }
327327 }
328328
329- let is_semi_suggestable = expected. iter ( ) . any ( |t| match t {
330- TokenType :: Token ( token:: Semi ) => true , // We expect a `;` here.
331- _ => false ,
332- } ) && ( // A `;` would be expected before the current keyword.
333- self . token . is_keyword ( kw:: Break ) ||
334- self . token . is_keyword ( kw:: Continue ) ||
335- self . token . is_keyword ( kw:: For ) ||
336- self . token . is_keyword ( kw:: If ) ||
337- self . token . is_keyword ( kw:: Let ) ||
338- self . token . is_keyword ( kw:: Loop ) ||
339- self . token . is_keyword ( kw:: Match ) ||
340- self . token . is_keyword ( kw:: Return ) ||
341- self . token . is_keyword ( kw:: While )
342- ) ;
343329 let sm = self . sess . source_map ( ) ;
344- match ( sm. lookup_line ( self . token . span . lo ( ) ) , sm. lookup_line ( sp. lo ( ) ) ) {
345- ( Ok ( ref a) , Ok ( ref b) ) if a. line != b. line && is_semi_suggestable => {
346- // The spans are in different lines, expected `;` and found `let` or `return`.
347- // High likelihood that it is only a missing `;`.
348- err. span_suggestion_short (
349- label_sp,
350- "a semicolon may be missing here" ,
351- ";" . to_string ( ) ,
352- Applicability :: MaybeIncorrect ,
353- ) ;
354- err. emit ( ) ;
355- return Ok ( true ) ;
356- }
357- ( Ok ( ref a) , Ok ( ref b) ) if a. line == b. line => {
358- // When the spans are in the same line, it means that the only content between
359- // them is whitespace, point at the found token in that case:
360- //
361- // X | () => { syntax error };
362- // | ^^^^^ expected one of 8 possible tokens here
363- //
364- // instead of having:
365- //
366- // X | () => { syntax error };
367- // | -^^^^^ unexpected token
368- // | |
369- // | expected one of 8 possible tokens here
370- err. span_label ( self . token . span , label_exp) ;
371- }
372- _ if self . prev_span == syntax_pos:: DUMMY_SP => {
373- // Account for macro context where the previous span might not be
374- // available to avoid incorrect output (#54841).
375- err. span_label ( self . token . span , "unexpected token" ) ;
376- }
377- _ => {
378- err. span_label ( sp, label_exp) ;
379- err. span_label ( self . token . span , "unexpected token" ) ;
380- }
330+ if self . prev_span == DUMMY_SP {
331+ // Account for macro context where the previous span might not be
332+ // available to avoid incorrect output (#54841).
333+ err. span_label ( self . token . span , label_exp) ;
334+ } else if !sm. is_multiline ( self . token . span . shrink_to_hi ( ) . until ( sp. shrink_to_lo ( ) ) ) {
335+ // When the spans are in the same line, it means that the only content between
336+ // them is whitespace, point at the found token in that case:
337+ //
338+ // X | () => { syntax error };
339+ // | ^^^^^ expected one of 8 possible tokens here
340+ //
341+ // instead of having:
342+ //
343+ // X | () => { syntax error };
344+ // | -^^^^^ unexpected token
345+ // | |
346+ // | expected one of 8 possible tokens here
347+ err. span_label ( self . token . span , label_exp) ;
348+ } else {
349+ err. span_label ( sp, label_exp) ;
350+ err. span_label ( self . token . span , "unexpected token" ) ;
381351 }
382352 self . maybe_annotate_with_ascription ( & mut err, false ) ;
383353 Err ( err)
@@ -902,20 +872,64 @@ impl<'a> Parser<'a> {
902872 }
903873 }
904874 let sm = self . sess . source_map ( ) ;
905- match ( sm. lookup_line ( prev_sp. lo ( ) ) , sm. lookup_line ( sp. lo ( ) ) ) {
906- ( Ok ( ref a) , Ok ( ref b) ) if a. line == b. line => {
907- // When the spans are in the same line, it means that the only content
908- // between them is whitespace, point only at the found token.
909- err. span_label ( sp, label_exp) ;
910- }
911- _ => {
912- err. span_label ( prev_sp, label_exp) ;
913- err. span_label ( sp, "unexpected token" ) ;
914- }
875+ if !sm. is_multiline ( prev_sp. until ( sp) ) {
876+ // When the spans are in the same line, it means that the only content
877+ // between them is whitespace, point only at the found token.
878+ err. span_label ( sp, label_exp) ;
879+ } else {
880+ err. span_label ( prev_sp, label_exp) ;
881+ err. span_label ( sp, "unexpected token" ) ;
915882 }
916883 Err ( err)
917884 }
918885
886+ pub ( super ) fn expect_semi ( & mut self ) -> PResult < ' a , ( ) > {
887+ if self . eat ( & token:: Semi ) {
888+ return Ok ( ( ) ) ;
889+ }
890+ let sm = self . sess . source_map ( ) ;
891+ let msg = format ! ( "expected `;`, found `{}`" , self . this_token_descr( ) ) ;
892+ let appl = Applicability :: MachineApplicable ;
893+ if self . token . span == DUMMY_SP || self . prev_span == DUMMY_SP {
894+ // Likely inside a macro, can't provide meaninful suggestions.
895+ return self . expect ( & token:: Semi ) . map ( |_| ( ) ) ;
896+ } else if !sm. is_multiline ( self . prev_span . until ( self . token . span ) ) {
897+ // The current token is in the same line as the prior token, not recoverable.
898+ } else if self . look_ahead ( 1 , |t| t == & token:: CloseDelim ( token:: Brace )
899+ || token_can_begin_expr ( t) && t. kind != token:: Colon
900+ ) && [ token:: Comma , token:: Colon ] . contains ( & self . token . kind ) {
901+ // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
902+ // either `,` or `:`, and the next token could either start a new statement or is a
903+ // block close. For example:
904+ //
905+ // let x = 32:
906+ // let y = 42;
907+ self . bump ( ) ;
908+ let sp = self . prev_span ;
909+ self . struct_span_err ( sp, & msg)
910+ . span_suggestion ( sp, "change this to `;`" , ";" . to_string ( ) , appl)
911+ . emit ( ) ;
912+ return Ok ( ( ) )
913+ } else if self . look_ahead ( 0 , |t| t == & token:: CloseDelim ( token:: Brace ) || (
914+ token_can_begin_expr ( t)
915+ && t != & token:: Semi
916+ && t != & token:: Pound // Avoid triggering with too many trailing `#` in raw string.
917+ ) ) {
918+ // Missing semicolon typo. This is triggered if the next token could either start a
919+ // new statement or is a block close. For example:
920+ //
921+ // let x = 32
922+ // let y = 42;
923+ let sp = self . prev_span . shrink_to_hi ( ) ;
924+ self . struct_span_err ( sp, & msg)
925+ . span_label ( self . token . span , "unexpected token" )
926+ . span_suggestion_short ( sp, "add `;` here" , ";" . to_string ( ) , appl)
927+ . emit ( ) ;
928+ return Ok ( ( ) )
929+ }
930+ self . expect ( & token:: Semi ) . map ( |_| ( ) ) // Error unconditionally
931+ }
932+
919933 pub ( super ) fn parse_semi_or_incorrect_foreign_fn_body (
920934 & mut self ,
921935 ident : & Ident ,
@@ -943,7 +957,7 @@ impl<'a> Parser<'a> {
943957 Err ( mut err) => {
944958 err. cancel ( ) ;
945959 mem:: replace ( self , parser_snapshot) ;
946- self . expect ( & token :: Semi ) ?;
960+ self . expect_semi ( ) ?;
947961 }
948962 }
949963 } else {
0 commit comments