@@ -1082,20 +1082,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1082
1082
. filter ( |ident| !used_fields. contains_key ( & ident) )
1083
1083
. collect :: < Vec < _ > > ( ) ;
1084
1084
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 (
1087
1087
adt. variant_descr ( ) ,
1088
1088
& inexistent_fields,
1089
1089
& mut unmentioned_fields,
1090
1090
variant,
1091
- ) ;
1092
- }
1091
+ ) )
1092
+ } else {
1093
+ None
1094
+ } ;
1093
1095
1094
1096
// Require `..` if struct has non_exhaustive attribute.
1095
1097
if variant. is_field_list_non_exhaustive ( ) && !adt. did . is_local ( ) && !etc {
1096
1098
self . error_foreign_non_exhaustive_spat ( pat, adt. variant_descr ( ) , fields. is_empty ( ) ) ;
1097
1099
}
1098
1100
1101
+ let mut unmentioned_err = None ;
1099
1102
// Report an error if incorrect number of the fields were specified.
1100
1103
if adt. is_union ( ) {
1101
1104
if fields. len ( ) != 1 {
@@ -1107,7 +1110,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1107
1110
tcx. sess . struct_span_err ( pat. span , "`..` cannot be used in union patterns" ) . emit ( ) ;
1108
1111
}
1109
1112
} 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 ) => { }
1111
1132
}
1112
1133
no_field_errors
1113
1134
}
@@ -1154,7 +1175,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1154
1175
inexistent_fields : & [ Ident ] ,
1155
1176
unmentioned_fields : & mut Vec < Ident > ,
1156
1177
variant : & ty:: VariantDef ,
1157
- ) {
1178
+ ) -> DiagnosticBuilder < ' tcx > {
1158
1179
let tcx = self . tcx ;
1159
1180
let ( field_names, t, plural) = if inexistent_fields. len ( ) == 1 {
1160
1181
( format ! ( "a field named `{}`" , inexistent_fields[ 0 ] ) , "this" , "" )
@@ -1221,15 +1242,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1221
1242
it explicitly.",
1222
1243
) ;
1223
1244
}
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
1225
1294
}
1226
1295
1227
1296
fn error_unmentioned_fields (
1228
1297
& self ,
1229
1298
span : Span ,
1230
1299
unmentioned_fields : & [ Ident ] ,
1231
- variant : & ty:: VariantDef ,
1232
- ) {
1300
+ ) -> DiagnosticBuilder < ' tcx > {
1233
1301
let field_names = if unmentioned_fields. len ( ) == 1 {
1234
1302
format ! ( "field `{}`" , unmentioned_fields[ 0 ] )
1235
1303
} else {
@@ -1248,9 +1316,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1248
1316
field_names
1249
1317
) ;
1250
1318
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
- }
1254
1319
if self . tcx . sess . teach ( & diag. get_code ( ) . unwrap ( ) ) {
1255
1320
diag. note (
1256
1321
"This error indicates that a pattern for a struct fails to specify a \
@@ -1259,7 +1324,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1259
1324
ignore unwanted fields.",
1260
1325
) ;
1261
1326
}
1262
- diag. emit ( ) ;
1327
+ diag
1263
1328
}
1264
1329
1265
1330
fn check_pat_box (
0 commit comments