@@ -239,6 +239,7 @@ impl<'a> Parser<'a> {
239
239
self . recover_const_impl ( const_span, attrs, def_ ( ) ) ?
240
240
} else {
241
241
self . recover_const_mut ( const_span) ;
242
+ self . recover_missing_kw_before_item ( ) ?;
242
243
let ( ident, generics, ty, expr) = self . parse_const_item ( ) ?;
243
244
(
244
245
ident,
@@ -311,6 +312,9 @@ impl<'a> Parser<'a> {
311
312
Case :: Insensitive ,
312
313
) ;
313
314
} else if macros_allowed && self . check_path ( ) {
315
+ if self . isnt_macro_invocation ( ) {
316
+ self . recover_missing_kw_before_item ( ) ?;
317
+ }
314
318
// MACRO INVOCATION ITEM
315
319
( Ident :: empty ( ) , ItemKind :: MacCall ( P ( self . parse_item_macro ( vis) ?) ) )
316
320
} else {
@@ -374,25 +378,25 @@ impl<'a> Parser<'a> {
374
378
self . check_ident ( ) && self . look_ahead ( 1 , |t| * t != token:: Not && * t != token:: PathSep )
375
379
}
376
380
377
- /// Recover on encountering a struct or method definition where the user
378
- /// forgot to add the `struct` or `fn` keyword after writing `pub`: `pub S {}`.
381
+ /// Recover on encountering a struct, enum, or method definition where the user
382
+ /// forgot to add the `struct`, `enum`, or `fn` keyword
379
383
fn recover_missing_kw_before_item ( & mut self ) -> PResult < ' a , ( ) > {
380
- // Space between `pub` keyword and the identifier
381
- //
382
- // pub S {}
383
- // ^^^ `sp` points here
384
- let sp = self . prev_token . span . between ( self . token . span ) ;
385
- let full_sp = self . prev_token . span . to ( self . token . span ) ;
386
- let ident_sp = self . token . span ;
387
-
388
- let ident = if self . look_ahead ( 1 , |t| {
389
- [
390
- token:: Lt ,
391
- token:: OpenDelim ( Delimiter :: Brace ) ,
392
- token:: OpenDelim ( Delimiter :: Parenthesis ) ,
393
- ]
394
- . contains ( & t. kind )
395
- } ) {
384
+ let is_pub = self . prev_token . is_keyword ( kw :: Pub ) ;
385
+ let is_const = self . prev_token . is_keyword ( kw :: Const ) ;
386
+ let ident_span = self . token . span ;
387
+ let span = if is_pub { self . prev_token . span . to ( ident_span ) } else { ident_span } ;
388
+ let insert_span = ident_span . shrink_to_lo ( ) ;
389
+
390
+ let ident = if ( !is_const
391
+ || self . look_ahead ( 1 , |t| * t == token :: OpenDelim ( Delimiter :: Parenthesis ) ) )
392
+ && self . look_ahead ( 1 , |t| {
393
+ [
394
+ token:: Lt ,
395
+ token:: OpenDelim ( Delimiter :: Brace ) ,
396
+ token:: OpenDelim ( Delimiter :: Parenthesis ) ,
397
+ ]
398
+ . contains ( & t. kind )
399
+ } ) {
396
400
self . parse_ident ( ) . unwrap ( )
397
401
} else {
398
402
return Ok ( ( ) ) ;
@@ -406,46 +410,56 @@ impl<'a> Parser<'a> {
406
410
}
407
411
408
412
let err = if self . check ( & token:: OpenDelim ( Delimiter :: Brace ) ) {
409
- // possible public struct definition where `struct` was forgotten
410
- Some ( errors:: MissingKeywordForItemDefinition :: Struct { span : sp, ident } )
413
+ // possible struct or enum definition where `struct` or `enum` was forgotten
414
+ if self . look_ahead ( 1 , |t| * t == token:: CloseDelim ( Delimiter :: Brace ) ) {
415
+ // `S {}` could be unit enum or struct
416
+ Some ( errors:: MissingKeywordForItemDefinition :: EnumOrStruct { span } )
417
+ } else if self . look_ahead ( 2 , |t| * t == token:: Colon )
418
+ || self . look_ahead ( 3 , |t| * t == token:: Colon )
419
+ {
420
+ // `S { f:` or `S { pub f:`
421
+ Some ( errors:: MissingKeywordForItemDefinition :: Struct { span, insert_span, ident } )
422
+ } else {
423
+ Some ( errors:: MissingKeywordForItemDefinition :: Enum { span, insert_span, ident } )
424
+ }
411
425
} else if self . check ( & token:: OpenDelim ( Delimiter :: Parenthesis ) ) {
412
- // possible public function or tuple struct definition where `fn`/`struct` was
413
- // forgotten
426
+ // possible function or tuple struct definition where `fn` or `struct` was forgotten
414
427
self . bump ( ) ; // `(`
415
428
let is_method = self . recover_self_param ( ) ;
416
429
417
430
self . consume_block ( Delimiter :: Parenthesis , ConsumeClosingDelim :: Yes ) ;
418
431
419
- let err =
420
- if self . check ( & token:: RArrow ) || self . check ( & token:: OpenDelim ( Delimiter :: Brace ) ) {
421
- self . eat_to_tokens ( & [ & token:: OpenDelim ( Delimiter :: Brace ) ] ) ;
422
- self . bump ( ) ; // `{`
423
- self . consume_block ( Delimiter :: Brace , ConsumeClosingDelim :: Yes ) ;
424
- if is_method {
425
- errors:: MissingKeywordForItemDefinition :: Method { span : sp, ident }
426
- } else {
427
- errors:: MissingKeywordForItemDefinition :: Function { span : sp, ident }
428
- }
429
- } else if self . check ( & token:: Semi ) {
430
- errors:: MissingKeywordForItemDefinition :: Struct { span : sp, ident }
432
+ let err = if self . check ( & token:: RArrow )
433
+ || self . check ( & token:: OpenDelim ( Delimiter :: Brace ) )
434
+ {
435
+ self . eat_to_tokens ( & [ & token:: OpenDelim ( Delimiter :: Brace ) ] ) ;
436
+ self . bump ( ) ; // `{`
437
+ self . consume_block ( Delimiter :: Brace , ConsumeClosingDelim :: Yes ) ;
438
+ if is_method {
439
+ errors:: MissingKeywordForItemDefinition :: Method { span, insert_span, ident }
431
440
} else {
432
- errors:: MissingKeywordForItemDefinition :: Ambiguous {
433
- span : sp,
434
- subdiag : if found_generics {
435
- None
436
- } else if let Ok ( snippet) = self . span_to_snippet ( ident_sp) {
437
- Some ( errors:: AmbiguousMissingKwForItemSub :: SuggestMacro {
438
- span : full_sp,
439
- snippet,
440
- } )
441
- } else {
442
- Some ( errors:: AmbiguousMissingKwForItemSub :: HelpMacro )
443
- } ,
444
- }
445
- } ;
441
+ errors:: MissingKeywordForItemDefinition :: Function { span, insert_span, ident }
442
+ }
443
+ } else if is_pub && self . check ( & token:: Semi ) {
444
+ errors:: MissingKeywordForItemDefinition :: Struct { span, insert_span, ident }
445
+ } else {
446
+ errors:: MissingKeywordForItemDefinition :: Ambiguous {
447
+ span,
448
+ subdiag : if found_generics {
449
+ None
450
+ } else if let Ok ( snippet) = self . span_to_snippet ( ident_span) {
451
+ Some ( errors:: AmbiguousMissingKwForItemSub :: SuggestMacro {
452
+ span : ident_span,
453
+ snippet,
454
+ } )
455
+ } else {
456
+ Some ( errors:: AmbiguousMissingKwForItemSub :: HelpMacro )
457
+ } ,
458
+ }
459
+ } ;
446
460
Some ( err)
447
461
} else if found_generics {
448
- Some ( errors:: MissingKeywordForItemDefinition :: Ambiguous { span : sp , subdiag : None } )
462
+ Some ( errors:: MissingKeywordForItemDefinition :: Ambiguous { span, subdiag : None } )
449
463
} else {
450
464
None
451
465
} ;
0 commit comments