@@ -17,6 +17,7 @@ use rustc_span::source_map::{Span, Spanned};
17
17
use rustc_span:: symbol:: Ident ;
18
18
use rustc_span:: { BytePos , DUMMY_SP } ;
19
19
use rustc_trait_selection:: traits:: { ObligationCause , Pattern } ;
20
+ use ty:: VariantDef ;
20
21
21
22
use std:: cmp;
22
23
use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
@@ -1264,14 +1265,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1264
1265
u. emit ( ) ;
1265
1266
}
1266
1267
}
1267
- ( None , Some ( mut err) ) | ( Some ( mut err) , None ) => {
1268
+ ( None , Some ( mut u) ) => {
1269
+ if let Some ( mut e) = self . error_tuple_variant_as_struct_pat ( pat, fields, variant) {
1270
+ u. delay_as_bug ( ) ;
1271
+ e. emit ( ) ;
1272
+ } else {
1273
+ u. emit ( ) ;
1274
+ }
1275
+ }
1276
+ ( Some ( mut err) , None ) => {
1268
1277
err. emit ( ) ;
1269
1278
}
1270
- ( None , None ) => { }
1279
+ ( None , None ) => {
1280
+ if let Some ( mut err) =
1281
+ self . error_tuple_variant_index_shorthand ( variant, pat, fields)
1282
+ {
1283
+ err. emit ( ) ;
1284
+ }
1285
+ }
1271
1286
}
1272
1287
no_field_errors
1273
1288
}
1274
1289
1290
+ fn error_tuple_variant_index_shorthand (
1291
+ & self ,
1292
+ variant : & VariantDef ,
1293
+ pat : & ' _ Pat < ' _ > ,
1294
+ fields : & [ hir:: FieldPat < ' _ > ] ,
1295
+ ) -> Option < DiagnosticBuilder < ' _ > > {
1296
+ // if this is a tuple struct, then all field names will be numbers
1297
+ // so if any fields in a struct pattern use shorthand syntax, they will
1298
+ // be invalid identifiers (for example, Foo { 0, 1 }).
1299
+ if let ( CtorKind :: Fn , PatKind :: Struct ( qpath, field_patterns, ..) ) =
1300
+ ( variant. ctor_kind , & pat. kind )
1301
+ {
1302
+ let has_shorthand_field_name = field_patterns. iter ( ) . any ( |field| field. is_shorthand ) ;
1303
+ if has_shorthand_field_name {
1304
+ let path = rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
1305
+ s. print_qpath ( qpath, false )
1306
+ } ) ;
1307
+ let mut err = struct_span_err ! (
1308
+ self . tcx. sess,
1309
+ pat. span,
1310
+ E0769 ,
1311
+ "tuple variant `{}` written as struct variant" ,
1312
+ path
1313
+ ) ;
1314
+ err. span_suggestion_verbose (
1315
+ qpath. span ( ) . shrink_to_hi ( ) . to ( pat. span . shrink_to_hi ( ) ) ,
1316
+ "use the tuple variant pattern syntax instead" ,
1317
+ format ! ( "({})" , self . get_suggested_tuple_struct_pattern( fields, variant) ) ,
1318
+ Applicability :: MaybeIncorrect ,
1319
+ ) ;
1320
+ return Some ( err) ;
1321
+ }
1322
+ }
1323
+ None
1324
+ }
1325
+
1275
1326
fn error_foreign_non_exhaustive_spat ( & self , pat : & Pat < ' _ > , descr : & str , no_fields : bool ) {
1276
1327
let sess = self . tcx . sess ;
1277
1328
let sm = sess. source_map ( ) ;
@@ -1411,16 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1411
1462
) ;
1412
1463
let ( sugg, appl) = if fields. len ( ) == variant. fields . len ( ) {
1413
1464
(
1414
- fields
1415
- . iter ( )
1416
- . map ( |f| match self . tcx . sess . source_map ( ) . span_to_snippet ( f. pat . span ) {
1417
- Ok ( f) => f,
1418
- Err ( _) => rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
1419
- s. print_pat ( f. pat )
1420
- } ) ,
1421
- } )
1422
- . collect :: < Vec < String > > ( )
1423
- . join ( ", " ) ,
1465
+ self . get_suggested_tuple_struct_pattern ( fields, variant) ,
1424
1466
Applicability :: MachineApplicable ,
1425
1467
)
1426
1468
} else {
@@ -1429,17 +1471,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1429
1471
Applicability :: MaybeIncorrect ,
1430
1472
)
1431
1473
} ;
1432
- err. span_suggestion (
1433
- pat. span ,
1474
+ err. span_suggestion_verbose (
1475
+ qpath . span ( ) . shrink_to_hi ( ) . to ( pat. span . shrink_to_hi ( ) ) ,
1434
1476
"use the tuple variant pattern syntax instead" ,
1435
- format ! ( "{} ({})" , path , sugg) ,
1477
+ format ! ( "({})" , sugg) ,
1436
1478
appl,
1437
1479
) ;
1438
1480
return Some ( err) ;
1439
1481
}
1440
1482
None
1441
1483
}
1442
1484
1485
+ fn get_suggested_tuple_struct_pattern (
1486
+ & self ,
1487
+ fields : & [ hir:: FieldPat < ' _ > ] ,
1488
+ variant : & VariantDef ,
1489
+ ) -> String {
1490
+ let variant_field_idents = variant. fields . iter ( ) . map ( |f| f. ident ) . collect :: < Vec < Ident > > ( ) ;
1491
+ fields
1492
+ . iter ( )
1493
+ . map ( |field| {
1494
+ match self . tcx . sess . source_map ( ) . span_to_snippet ( field. pat . span ) {
1495
+ Ok ( f) => {
1496
+ // Field names are numbers, but numbers
1497
+ // are not valid identifiers
1498
+ if variant_field_idents. contains ( & field. ident ) {
1499
+ String :: from ( "_" )
1500
+ } else {
1501
+ f
1502
+ }
1503
+ }
1504
+ Err ( _) => rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
1505
+ s. print_pat ( field. pat )
1506
+ } ) ,
1507
+ }
1508
+ } )
1509
+ . collect :: < Vec < String > > ( )
1510
+ . join ( ", " )
1511
+ }
1512
+
1443
1513
/// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
1444
1514
/// inaccessible fields.
1445
1515
///
0 commit comments