@@ -16,6 +16,7 @@ use rustc_span::lev_distance::find_best_match_for_name;
1616use rustc_span:: source_map:: { Span , Spanned } ;
1717use rustc_span:: symbol:: Ident ;
1818use rustc_trait_selection:: traits:: { ObligationCause , Pattern } ;
19+ use ty:: VariantDef ;
1920
2021use std:: cmp;
2122use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
@@ -1209,14 +1210,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12091210 u. emit ( ) ;
12101211 }
12111212 }
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 ) => {
12131222 err. emit ( ) ;
12141223 }
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+ }
12161231 }
12171232 no_field_errors
12181233 }
12191234
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+
12201275 fn error_foreign_non_exhaustive_spat ( & self , pat : & Pat < ' _ > , descr : & str , no_fields : bool ) {
12211276 let sess = self . tcx . sess ;
12221277 let sm = sess. source_map ( ) ;
@@ -1356,16 +1411,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13561411 ) ;
13571412 let ( sugg, appl) = if fields. len ( ) == variant. fields . len ( ) {
13581413 (
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) ,
13691415 Applicability :: MachineApplicable ,
13701416 )
13711417 } else {
@@ -1385,6 +1431,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13851431 None
13861432 }
13871433
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+
13881462 /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
13891463 /// inaccessible fields.
13901464 ///
0 commit comments