@@ -273,11 +273,13 @@ impl<'a> Parser<'a> {
273
273
// TYPE ITEM
274
274
self . parse_type_alias ( def ( ) ) ?
275
275
} else if self . eat_keyword ( kw:: Enum ) {
276
+ let start_span = self . prev_token . span ;
276
277
// ENUM ITEM
277
- self . parse_item_enum ( ) ?
278
+ self . parse_item_enum ( start_span ) ?
278
279
} else if self . eat_keyword ( kw:: Struct ) {
280
+ let start_span = self . prev_token . span ;
279
281
// STRUCT ITEM
280
- self . parse_item_struct ( ) ?
282
+ self . parse_item_struct ( start_span ) ?
281
283
} else if self . is_kw_followed_by_ident ( kw:: Union ) {
282
284
// UNION ITEM
283
285
self . bump ( ) ; // `union`
@@ -1199,13 +1201,14 @@ impl<'a> Parser<'a> {
1199
1201
}
1200
1202
1201
1203
/// Parses an enum declaration.
1202
- fn parse_item_enum ( & mut self ) -> PResult < ' a , ItemInfo > {
1204
+ fn parse_item_enum ( & mut self , start_span : Span ) -> PResult < ' a , ItemInfo > {
1203
1205
let id = self . parse_ident ( ) ?;
1204
1206
let mut generics = self . parse_generics ( ) ?;
1205
1207
generics. where_clause = self . parse_where_clause ( ) ?;
1206
1208
1207
- let ( variants, _) =
1208
- self . parse_delim_comma_seq ( token:: Brace , |p| p. parse_enum_variant ( ) ) . map_err ( |e| {
1209
+ let ( variants, _) = self
1210
+ . parse_delim_comma_seq ( token:: Brace , |p| p. parse_enum_variant ( start_span) )
1211
+ . map_err ( |e| {
1209
1212
self . recover_stmt ( ) ;
1210
1213
e
1211
1214
} ) ?;
@@ -1214,7 +1217,7 @@ impl<'a> Parser<'a> {
1214
1217
Ok ( ( id, ItemKind :: Enum ( enum_definition, generics) ) )
1215
1218
}
1216
1219
1217
- fn parse_enum_variant ( & mut self ) -> PResult < ' a , Option < Variant > > {
1220
+ fn parse_enum_variant ( & mut self , start_span : Span ) -> PResult < ' a , Option < Variant > > {
1218
1221
let variant_attrs = self . parse_outer_attributes ( ) ?;
1219
1222
self . collect_tokens_trailing_token (
1220
1223
variant_attrs,
@@ -1226,11 +1229,36 @@ impl<'a> Parser<'a> {
1226
1229
if !this. recover_nested_adt_item ( kw:: Enum ) ? {
1227
1230
return Ok ( ( None , TrailingToken :: None ) ) ;
1228
1231
}
1232
+ let enum_field_start_span = this. token . span ;
1229
1233
let ident = this. parse_field_ident ( "enum" , vlo) ?;
1234
+ if this. token . kind == token:: Colon {
1235
+ let snapshot = this. clone ( ) ;
1236
+ this. bump ( ) ;
1237
+ match this. parse_ty ( ) {
1238
+ Ok ( _) => {
1239
+ let mut err = this. struct_span_err (
1240
+ enum_field_start_span. to ( this. prev_token . span ) ,
1241
+ "the enum cannot have a struct field declaration" ,
1242
+ ) ;
1243
+ err. span_suggestion_verbose (
1244
+ start_span,
1245
+ "consider using `struct` instead of `enum`" ,
1246
+ "struct" . to_string ( ) ,
1247
+ Applicability :: MaybeIncorrect ,
1248
+ ) ;
1249
+ return Err ( err) ;
1250
+ }
1251
+ Err ( e) => {
1252
+ e. cancel ( ) ;
1253
+ * this = snapshot;
1254
+ }
1255
+ } ;
1256
+ }
1230
1257
1231
1258
let struct_def = if this. check ( & token:: OpenDelim ( token:: Brace ) ) {
1232
1259
// Parse a struct variant.
1233
- let ( fields, recovered) = this. parse_record_struct_body ( "struct" , false ) ?;
1260
+ let ( fields, recovered) =
1261
+ this. parse_record_struct_body ( "struct" , false , None ) ?;
1234
1262
VariantData :: Struct ( fields, recovered)
1235
1263
} else if this. check ( & token:: OpenDelim ( token:: Paren ) ) {
1236
1264
VariantData :: Tuple ( this. parse_tuple_struct_body ( ) ?, DUMMY_NODE_ID )
@@ -1258,7 +1286,7 @@ impl<'a> Parser<'a> {
1258
1286
}
1259
1287
1260
1288
/// Parses `struct Foo { ... }`.
1261
- fn parse_item_struct ( & mut self ) -> PResult < ' a , ItemInfo > {
1289
+ fn parse_item_struct ( & mut self , start_span : Span ) -> PResult < ' a , ItemInfo > {
1262
1290
let class_name = self . parse_ident ( ) ?;
1263
1291
1264
1292
let mut generics = self . parse_generics ( ) ?;
@@ -1284,17 +1312,23 @@ impl<'a> Parser<'a> {
1284
1312
VariantData :: Unit ( DUMMY_NODE_ID )
1285
1313
} else {
1286
1314
// If we see: `struct Foo<T> where T: Copy { ... }`
1287
- let ( fields, recovered) =
1288
- self . parse_record_struct_body ( "struct" , generics. where_clause . has_where_token ) ?;
1315
+ let ( fields, recovered) = self . parse_record_struct_body (
1316
+ "struct" ,
1317
+ generics. where_clause . has_where_token ,
1318
+ Some ( start_span) ,
1319
+ ) ?;
1289
1320
VariantData :: Struct ( fields, recovered)
1290
1321
}
1291
1322
// No `where` so: `struct Foo<T>;`
1292
1323
} else if self . eat ( & token:: Semi ) {
1293
1324
VariantData :: Unit ( DUMMY_NODE_ID )
1294
1325
// Record-style struct definition
1295
1326
} else if self . token == token:: OpenDelim ( token:: Brace ) {
1296
- let ( fields, recovered) =
1297
- self . parse_record_struct_body ( "struct" , generics. where_clause . has_where_token ) ?;
1327
+ let ( fields, recovered) = self . parse_record_struct_body (
1328
+ "struct" ,
1329
+ generics. where_clause . has_where_token ,
1330
+ Some ( start_span) ,
1331
+ ) ?;
1298
1332
VariantData :: Struct ( fields, recovered)
1299
1333
// Tuple-style struct definition with optional where-clause.
1300
1334
} else if self . token == token:: OpenDelim ( token:: Paren ) {
@@ -1323,12 +1357,18 @@ impl<'a> Parser<'a> {
1323
1357
1324
1358
let vdata = if self . token . is_keyword ( kw:: Where ) {
1325
1359
generics. where_clause = self . parse_where_clause ( ) ?;
1326
- let ( fields, recovered) =
1327
- self . parse_record_struct_body ( "union" , generics. where_clause . has_where_token ) ?;
1360
+ let ( fields, recovered) = self . parse_record_struct_body (
1361
+ "union" ,
1362
+ generics. where_clause . has_where_token ,
1363
+ None ,
1364
+ ) ?;
1328
1365
VariantData :: Struct ( fields, recovered)
1329
1366
} else if self . token == token:: OpenDelim ( token:: Brace ) {
1330
- let ( fields, recovered) =
1331
- self . parse_record_struct_body ( "union" , generics. where_clause . has_where_token ) ?;
1367
+ let ( fields, recovered) = self . parse_record_struct_body (
1368
+ "union" ,
1369
+ generics. where_clause . has_where_token ,
1370
+ None ,
1371
+ ) ?;
1332
1372
VariantData :: Struct ( fields, recovered)
1333
1373
} else {
1334
1374
let token_str = super :: token_descr ( & self . token ) ;
@@ -1345,12 +1385,13 @@ impl<'a> Parser<'a> {
1345
1385
& mut self ,
1346
1386
adt_ty : & str ,
1347
1387
parsed_where : bool ,
1388
+ start_span : Option < Span > ,
1348
1389
) -> PResult < ' a , ( Vec < FieldDef > , /* recovered */ bool ) > {
1349
1390
let mut fields = Vec :: new ( ) ;
1350
1391
let mut recovered = false ;
1351
1392
if self . eat ( & token:: OpenDelim ( token:: Brace ) ) {
1352
1393
while self . token != token:: CloseDelim ( token:: Brace ) {
1353
- let field = self . parse_field_def ( adt_ty) . map_err ( |e| {
1394
+ let field = self . parse_field_def ( adt_ty, start_span ) . map_err ( |e| {
1354
1395
self . consume_block ( token:: Brace , ConsumeClosingDelim :: No ) ;
1355
1396
recovered = true ;
1356
1397
e
@@ -1413,12 +1454,15 @@ impl<'a> Parser<'a> {
1413
1454
}
1414
1455
1415
1456
/// Parses an element of a struct declaration.
1416
- fn parse_field_def ( & mut self , adt_ty : & str ) -> PResult < ' a , FieldDef > {
1457
+ fn parse_field_def ( & mut self , adt_ty : & str , start_span : Option < Span > ) -> PResult < ' a , FieldDef > {
1417
1458
let attrs = self . parse_outer_attributes ( ) ?;
1418
1459
self . collect_tokens_trailing_token ( attrs, ForceCollect :: No , |this, attrs| {
1419
1460
let lo = this. token . span ;
1420
1461
let vis = this. parse_visibility ( FollowedByType :: No ) ?;
1421
- Ok ( ( this. parse_single_struct_field ( adt_ty, lo, vis, attrs) ?, TrailingToken :: None ) )
1462
+ Ok ( (
1463
+ this. parse_single_struct_field ( adt_ty, lo, vis, attrs, start_span) ?,
1464
+ TrailingToken :: None ,
1465
+ ) )
1422
1466
} )
1423
1467
}
1424
1468
@@ -1429,9 +1473,10 @@ impl<'a> Parser<'a> {
1429
1473
lo : Span ,
1430
1474
vis : Visibility ,
1431
1475
attrs : Vec < Attribute > ,
1476
+ start_span : Option < Span > ,
1432
1477
) -> PResult < ' a , FieldDef > {
1433
1478
let mut seen_comma: bool = false ;
1434
- let a_var = self . parse_name_and_ty ( adt_ty, lo, vis, attrs) ?;
1479
+ let a_var = self . parse_name_and_ty ( adt_ty, lo, vis, attrs, start_span ) ?;
1435
1480
if self . token == token:: Comma {
1436
1481
seen_comma = true ;
1437
1482
}
@@ -1555,9 +1600,32 @@ impl<'a> Parser<'a> {
1555
1600
lo : Span ,
1556
1601
vis : Visibility ,
1557
1602
attrs : Vec < Attribute > ,
1603
+ start_span : Option < Span > ,
1558
1604
) -> PResult < ' a , FieldDef > {
1605
+ let prev_token_kind = self . prev_token . kind . clone ( ) ;
1559
1606
let name = self . parse_field_ident ( adt_ty, lo) ?;
1560
- self . expect_field_ty_separator ( ) ?;
1607
+ if let Err ( mut error) = self . expect_field_ty_separator ( ) {
1608
+ if ( matches ! ( vis. kind, VisibilityKind :: Inherited )
1609
+ && ( prev_token_kind == token:: Comma
1610
+ || prev_token_kind == token:: OpenDelim ( token:: Brace ) ) )
1611
+ || !matches ! ( vis. kind, VisibilityKind :: Inherited )
1612
+ {
1613
+ let snapshot = self . clone ( ) ;
1614
+ if let Err ( err) = self . parse_ty ( ) {
1615
+ if let Some ( span) = start_span {
1616
+ error. span_suggestion_verbose (
1617
+ span,
1618
+ "consider using `enum` instead of `struct`" ,
1619
+ "enum" . to_string ( ) ,
1620
+ Applicability :: MaybeIncorrect ,
1621
+ ) ;
1622
+ }
1623
+ err. cancel ( ) ;
1624
+ * self = snapshot;
1625
+ }
1626
+ }
1627
+ return Err ( error) ;
1628
+ }
1561
1629
let ty = self . parse_ty ( ) ?;
1562
1630
if self . token . kind == token:: Colon && self . look_ahead ( 1 , |tok| tok. kind != token:: Colon ) {
1563
1631
self . struct_span_err ( self . token . span , "found single colon in a struct field type path" )
0 commit comments