@@ -16,6 +16,7 @@ use rustc_span::lev_distance::find_best_match_for_name;
16
16
use rustc_span:: source_map:: { Span , Spanned } ;
17
17
use rustc_span:: symbol:: Ident ;
18
18
use rustc_trait_selection:: traits:: { ObligationCause , Pattern } ;
19
+ use ty:: VariantDef ;
19
20
20
21
use std:: cmp;
21
22
use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
@@ -1209,14 +1210,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1209
1210
u. emit ( ) ;
1210
1211
}
1211
1212
}
1212
- ( None , Some ( mut err) ) | ( Some ( mut err) , None ) => {
1213
+ ( None , Some ( mut u) ) => {
1214
+ if let Some ( mut e) = self . error_tuple_variant_as_struct_pat ( pat, fields, variant) {
1215
+ u. delay_as_bug ( ) ;
1216
+ e. emit ( ) ;
1217
+ } else {
1218
+ u. emit ( ) ;
1219
+ }
1220
+ }
1221
+ ( Some ( mut err) , None ) => {
1213
1222
err. emit ( ) ;
1214
1223
}
1215
- ( None , None ) => { }
1224
+ ( None , None ) => {
1225
+ if let Some ( mut err) =
1226
+ self . error_tuple_variant_index_shorthand ( variant, pat, fields)
1227
+ {
1228
+ err. emit ( ) ;
1229
+ }
1230
+ }
1216
1231
}
1217
1232
no_field_errors
1218
1233
}
1219
1234
1235
+ fn error_tuple_variant_index_shorthand (
1236
+ & self ,
1237
+ variant : & VariantDef ,
1238
+ pat : & ' _ Pat < ' _ > ,
1239
+ fields : & [ hir:: FieldPat < ' _ > ] ,
1240
+ ) -> Option < DiagnosticBuilder < ' _ > > {
1241
+ // if this is a tuple struct, then all field names will be numbers
1242
+ // so if any fields in a struct pattern use shorthand syntax, they will
1243
+ // be invalid identifiers (for example, Foo { 0, 1 }).
1244
+ if let ( CtorKind :: Fn , PatKind :: Struct ( qpath, field_patterns, ..) ) =
1245
+ ( variant. ctor_kind , & pat. kind )
1246
+ {
1247
+ let has_shorthand_field_name = field_patterns. iter ( ) . any ( |field| field. is_shorthand ) ;
1248
+ if has_shorthand_field_name {
1249
+ let path = rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
1250
+ s. print_qpath ( qpath, false )
1251
+ } ) ;
1252
+ let mut err = struct_span_err ! (
1253
+ self . tcx. sess,
1254
+ pat. span,
1255
+ E0769 ,
1256
+ "tuple variant `{}` uses a bare index in a struct pattern" ,
1257
+ path
1258
+ ) ;
1259
+ err. span_suggestion (
1260
+ pat. span ,
1261
+ "use the tuple variant pattern syntax instead" ,
1262
+ format ! (
1263
+ "{}({})" ,
1264
+ path,
1265
+ self . get_suggested_tuple_struct_pattern( fields, variant)
1266
+ ) ,
1267
+ Applicability :: MaybeIncorrect ,
1268
+ ) ;
1269
+ return Some ( err) ;
1270
+ }
1271
+ }
1272
+ None
1273
+ }
1274
+
1220
1275
fn error_foreign_non_exhaustive_spat ( & self , pat : & Pat < ' _ > , descr : & str , no_fields : bool ) {
1221
1276
let sess = self . tcx . sess ;
1222
1277
let sm = sess. source_map ( ) ;
@@ -1356,16 +1411,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1356
1411
) ;
1357
1412
let ( sugg, appl) = if fields. len ( ) == variant. fields . len ( ) {
1358
1413
(
1359
- fields
1360
- . iter ( )
1361
- . map ( |f| match self . tcx . sess . source_map ( ) . span_to_snippet ( f. pat . span ) {
1362
- Ok ( f) => f,
1363
- Err ( _) => rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
1364
- s. print_pat ( f. pat )
1365
- } ) ,
1366
- } )
1367
- . collect :: < Vec < String > > ( )
1368
- . join ( ", " ) ,
1414
+ self . get_suggested_tuple_struct_pattern ( fields, variant) ,
1369
1415
Applicability :: MachineApplicable ,
1370
1416
)
1371
1417
} else {
@@ -1385,6 +1431,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1385
1431
None
1386
1432
}
1387
1433
1434
+ fn get_suggested_tuple_struct_pattern (
1435
+ & self ,
1436
+ fields : & [ hir:: FieldPat < ' _ > ] ,
1437
+ variant : & VariantDef ,
1438
+ ) -> String {
1439
+ let variant_field_idents = variant. fields . iter ( ) . map ( |f| f. ident ) . collect :: < Vec < Ident > > ( ) ;
1440
+ fields
1441
+ . iter ( )
1442
+ . map ( |field| {
1443
+ match self . tcx . sess . source_map ( ) . span_to_snippet ( field. pat . span ) {
1444
+ Ok ( f) => {
1445
+ // Field names are numbers, but numbers
1446
+ // are not valid identifiers
1447
+ if variant_field_idents. contains ( & field. ident ) {
1448
+ String :: from ( "_" )
1449
+ } else {
1450
+ f
1451
+ }
1452
+ }
1453
+ Err ( _) => rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
1454
+ s. print_pat ( field. pat )
1455
+ } ) ,
1456
+ }
1457
+ } )
1458
+ . collect :: < Vec < String > > ( )
1459
+ . join ( ", " )
1460
+ }
1461
+
1388
1462
/// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
1389
1463
/// inaccessible fields.
1390
1464
///
0 commit comments