@@ -6,7 +6,7 @@ use crate::ast::{
6
6
self , Param , BinOpKind , BindingMode , BlockCheckMode , Expr , ExprKind , Ident , Item , ItemKind ,
7
7
Mutability , Pat , PatKind , PathSegment , QSelf , Ty , TyKind ,
8
8
} ;
9
- use crate :: parse:: token:: { self , TokenKind } ;
9
+ use crate :: parse:: token:: { self , TokenKind , token_can_begin_expr } ;
10
10
use crate :: print:: pprust;
11
11
use crate :: ptr:: P ;
12
12
use crate :: symbol:: { kw, sym} ;
@@ -274,23 +274,23 @@ impl<'a> Parser<'a> {
274
274
expected. sort_by_cached_key ( |x| x. to_string ( ) ) ;
275
275
expected. dedup ( ) ;
276
276
let expect = tokens_to_string ( & expected[ ..] ) ;
277
- let actual = self . this_token_to_string ( ) ;
277
+ let actual = self . this_token_descr ( ) ;
278
278
let ( msg_exp, ( label_sp, label_exp) ) = if expected. len ( ) > 1 {
279
279
let short_expect = if expected. len ( ) > 6 {
280
280
format ! ( "{} possible tokens" , expected. len( ) )
281
281
} else {
282
282
expect. clone ( )
283
283
} ;
284
- ( format ! ( "expected one of {}, found `{}` " , expect, actual) ,
284
+ ( format ! ( "expected one of {}, found {} " , expect, actual) ,
285
285
( self . sess . source_map ( ) . next_point ( self . prev_span ) ,
286
286
format ! ( "expected one of {} here" , short_expect) ) )
287
287
} else if expected. is_empty ( ) {
288
- ( format ! ( "unexpected token: `{}` " , actual) ,
288
+ ( format ! ( "unexpected token: {} " , actual) ,
289
289
( self . prev_span , "unexpected token after this" . to_string ( ) ) )
290
290
} else {
291
- ( format ! ( "expected {}, found `{}` " , expect, actual) ,
291
+ ( format ! ( "expected {}, found {} " , expect, actual) ,
292
292
( self . sess . source_map ( ) . next_point ( self . prev_span ) ,
293
- format ! ( "expected {} here " , expect) ) )
293
+ format ! ( "expected {}" , expect) ) )
294
294
} ;
295
295
self . last_unexpected_token_span = Some ( self . token . span ) ;
296
296
let mut err = self . fatal ( & msg_exp) ;
@@ -326,58 +326,28 @@ impl<'a> Parser<'a> {
326
326
}
327
327
}
328
328
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
- ) ;
343
329
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" ) ;
381
351
}
382
352
self . maybe_annotate_with_ascription ( & mut err, false ) ;
383
353
Err ( err)
@@ -902,20 +872,64 @@ impl<'a> Parser<'a> {
902
872
}
903
873
}
904
874
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" ) ;
915
882
}
916
883
Err ( err)
917
884
}
918
885
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
+
919
933
pub ( super ) fn parse_semi_or_incorrect_foreign_fn_body (
920
934
& mut self ,
921
935
ident : & Ident ,
@@ -943,7 +957,7 @@ impl<'a> Parser<'a> {
943
957
Err ( mut err) => {
944
958
err. cancel ( ) ;
945
959
mem:: replace ( self , parser_snapshot) ;
946
- self . expect ( & token :: Semi ) ?;
960
+ self . expect_semi ( ) ?;
947
961
}
948
962
}
949
963
} else {
0 commit comments