@@ -17,6 +17,7 @@ use rustc_span::source_map::{Span, Spanned};
1717use rustc_span:: symbol:: Ident ;
1818use rustc_span:: { BytePos , DUMMY_SP } ;
1919use rustc_trait_selection:: traits:: { ObligationCause , Pattern } ;
20+ use ty:: VariantDef ;
2021
2122use std:: cmp;
2223use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
@@ -1264,14 +1265,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12641265 u. emit ( ) ;
12651266 }
12661267 }
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 ) => {
12681277 err. emit ( ) ;
12691278 }
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+ }
12711286 }
12721287 no_field_errors
12731288 }
12741289
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+
12751326 fn error_foreign_non_exhaustive_spat ( & self , pat : & Pat < ' _ > , descr : & str , no_fields : bool ) {
12761327 let sess = self . tcx . sess ;
12771328 let sm = sess. source_map ( ) ;
@@ -1411,16 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14111462 ) ;
14121463 let ( sugg, appl) = if fields. len ( ) == variant. fields . len ( ) {
14131464 (
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) ,
14241466 Applicability :: MachineApplicable ,
14251467 )
14261468 } else {
@@ -1429,17 +1471,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14291471 Applicability :: MaybeIncorrect ,
14301472 )
14311473 } ;
1432- err. span_suggestion (
1433- pat. span ,
1474+ err. span_suggestion_verbose (
1475+ qpath . span ( ) . shrink_to_hi ( ) . to ( pat. span . shrink_to_hi ( ) ) ,
14341476 "use the tuple variant pattern syntax instead" ,
1435- format ! ( "{} ({})" , path , sugg) ,
1477+ format ! ( "({})" , sugg) ,
14361478 appl,
14371479 ) ;
14381480 return Some ( err) ;
14391481 }
14401482 None
14411483 }
14421484
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+
14431513 /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
14441514 /// inaccessible fields.
14451515 ///
0 commit comments