@@ -1082,20 +1082,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10821082 . filter ( |ident| !used_fields. contains_key ( & ident) )
10831083 . collect :: < Vec < _ > > ( ) ;
10841084
1085- if !inexistent_fields. is_empty ( ) && !variant. recovered {
1086- self . error_inexistent_fields (
1085+ let inexistent_fields_err = if !inexistent_fields. is_empty ( ) && !variant. recovered {
1086+ Some ( self . error_inexistent_fields (
10871087 adt. variant_descr ( ) ,
10881088 & inexistent_fields,
10891089 & mut unmentioned_fields,
10901090 variant,
1091- ) ;
1092- }
1091+ ) )
1092+ } else {
1093+ None
1094+ } ;
10931095
10941096 // Require `..` if struct has non_exhaustive attribute.
10951097 if variant. is_field_list_non_exhaustive ( ) && !adt. did . is_local ( ) && !etc {
10961098 self . error_foreign_non_exhaustive_spat ( pat, adt. variant_descr ( ) , fields. is_empty ( ) ) ;
10971099 }
10981100
1101+ let mut unmentioned_err = None ;
10991102 // Report an error if incorrect number of the fields were specified.
11001103 if adt. is_union ( ) {
11011104 if fields. len ( ) != 1 {
@@ -1107,7 +1110,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11071110 tcx. sess . struct_span_err ( pat. span , "`..` cannot be used in union patterns" ) . emit ( ) ;
11081111 }
11091112 } else if !etc && !unmentioned_fields. is_empty ( ) {
1110- self . error_unmentioned_fields ( pat. span , & unmentioned_fields, variant) ;
1113+ unmentioned_err = Some ( self . error_unmentioned_fields ( pat. span , & unmentioned_fields) ) ;
1114+ }
1115+ match ( inexistent_fields_err, unmentioned_err) {
1116+ ( Some ( mut i) , Some ( mut u) ) => {
1117+ if let Some ( mut e) = self . error_tuple_variant_as_struct_pat ( pat, fields, variant) {
1118+ // We don't want to show the inexistent fields error when this was
1119+ // `Foo { a, b }` when it should have been `Foo(a, b)`.
1120+ i. delay_as_bug ( ) ;
1121+ u. delay_as_bug ( ) ;
1122+ e. emit ( ) ;
1123+ } else {
1124+ i. emit ( ) ;
1125+ u. emit ( ) ;
1126+ }
1127+ }
1128+ ( None , Some ( mut err) ) | ( Some ( mut err) , None ) => {
1129+ err. emit ( ) ;
1130+ }
1131+ ( None , None ) => { }
11111132 }
11121133 no_field_errors
11131134 }
@@ -1154,7 +1175,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11541175 inexistent_fields : & [ Ident ] ,
11551176 unmentioned_fields : & mut Vec < Ident > ,
11561177 variant : & ty:: VariantDef ,
1157- ) {
1178+ ) -> DiagnosticBuilder < ' tcx > {
11581179 let tcx = self . tcx ;
11591180 let ( field_names, t, plural) = if inexistent_fields. len ( ) == 1 {
11601181 ( format ! ( "a field named `{}`" , inexistent_fields[ 0 ] ) , "this" , "" )
@@ -1221,15 +1242,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12211242 it explicitly.",
12221243 ) ;
12231244 }
1224- err. emit ( ) ;
1245+ err
1246+ }
1247+
1248+ fn error_tuple_variant_as_struct_pat (
1249+ & self ,
1250+ pat : & Pat < ' _ > ,
1251+ fields : & ' tcx [ hir:: FieldPat < ' tcx > ] ,
1252+ variant : & ty:: VariantDef ,
1253+ ) -> Option < DiagnosticBuilder < ' tcx > > {
1254+ if let ( CtorKind :: Fn , PatKind :: Struct ( qpath, ..) ) = ( variant. ctor_kind , & pat. kind ) {
1255+ let path = rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
1256+ s. print_qpath ( qpath, false )
1257+ } ) ;
1258+ let mut err = struct_span_err ! (
1259+ self . tcx. sess,
1260+ pat. span,
1261+ E0769 ,
1262+ "tuple variant `{}` written as struct variant" ,
1263+ path
1264+ ) ;
1265+ let ( sugg, appl) = if fields. len ( ) == variant. fields . len ( ) {
1266+ (
1267+ fields
1268+ . iter ( )
1269+ . map ( |f| match self . tcx . sess . source_map ( ) . span_to_snippet ( f. pat . span ) {
1270+ Ok ( f) => f,
1271+ Err ( _) => rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
1272+ s. print_pat ( f. pat )
1273+ } ) ,
1274+ } )
1275+ . collect :: < Vec < String > > ( )
1276+ . join ( ", " ) ,
1277+ Applicability :: MachineApplicable ,
1278+ )
1279+ } else {
1280+ (
1281+ variant. fields . iter ( ) . map ( |_| "_" ) . collect :: < Vec < & str > > ( ) . join ( ", " ) ,
1282+ Applicability :: MaybeIncorrect ,
1283+ )
1284+ } ;
1285+ err. span_suggestion (
1286+ pat. span ,
1287+ "use the tuple variant pattern syntax instead" ,
1288+ format ! ( "{}({})" , path, sugg) ,
1289+ appl,
1290+ ) ;
1291+ return Some ( err) ;
1292+ }
1293+ None
12251294 }
12261295
12271296 fn error_unmentioned_fields (
12281297 & self ,
12291298 span : Span ,
12301299 unmentioned_fields : & [ Ident ] ,
1231- variant : & ty:: VariantDef ,
1232- ) {
1300+ ) -> DiagnosticBuilder < ' tcx > {
12331301 let field_names = if unmentioned_fields. len ( ) == 1 {
12341302 format ! ( "field `{}`" , unmentioned_fields[ 0 ] )
12351303 } else {
@@ -1248,9 +1316,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12481316 field_names
12491317 ) ;
12501318 diag. span_label ( span, format ! ( "missing {}" , field_names) ) ;
1251- if variant. ctor_kind == CtorKind :: Fn {
1252- diag. note ( "trying to match a tuple variant with a struct variant pattern" ) ;
1253- }
12541319 if self . tcx . sess . teach ( & diag. get_code ( ) . unwrap ( ) ) {
12551320 diag. note (
12561321 "This error indicates that a pattern for a struct fails to specify a \
@@ -1259,7 +1324,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12591324 ignore unwanted fields.",
12601325 ) ;
12611326 }
1262- diag. emit ( ) ;
1327+ diag
12631328 }
12641329
12651330 fn check_pat_box (
0 commit comments