@@ -1078,8 +1078,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1078
1078
let mut unmentioned_fields = variant
1079
1079
. fields
1080
1080
. iter ( )
1081
- . map ( |field| field. ident . normalize_to_macros_2_0 ( ) )
1082
- . filter ( |ident| !used_fields. contains_key ( & ident) )
1081
+ . map ( |field| ( field, field . ident . normalize_to_macros_2_0 ( ) ) )
1082
+ . filter ( |( _ , ident) | !used_fields. contains_key ( & ident) )
1083
1083
. collect :: < Vec < _ > > ( ) ;
1084
1084
1085
1085
let inexistent_fields_err = if !( inexistent_fields. is_empty ( ) || variant. is_recovered ( ) ) {
@@ -1110,7 +1110,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1110
1110
tcx. sess . struct_span_err ( pat. span , "`..` cannot be used in union patterns" ) . emit ( ) ;
1111
1111
}
1112
1112
} else if !etc && !unmentioned_fields. is_empty ( ) {
1113
- unmentioned_err = Some ( self . error_unmentioned_fields ( pat, & unmentioned_fields) ) ;
1113
+ let no_accessible_unmentioned_fields = unmentioned_fields
1114
+ . iter ( )
1115
+ . filter ( |( field, _) | {
1116
+ field. vis . is_accessible_from ( tcx. parent_module ( pat. hir_id ) . to_def_id ( ) , tcx)
1117
+ } )
1118
+ . next ( )
1119
+ . is_none ( ) ;
1120
+
1121
+ if no_accessible_unmentioned_fields {
1122
+ unmentioned_err = Some ( self . error_no_accessible_fields ( pat, & fields) ) ;
1123
+ } else {
1124
+ unmentioned_err = Some ( self . error_unmentioned_fields ( pat, & unmentioned_fields) ) ;
1125
+ }
1114
1126
}
1115
1127
match ( inexistent_fields_err, unmentioned_err) {
1116
1128
( Some ( mut i) , Some ( mut u) ) => {
@@ -1173,7 +1185,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1173
1185
& self ,
1174
1186
kind_name : & str ,
1175
1187
inexistent_fields : & [ Ident ] ,
1176
- unmentioned_fields : & mut Vec < Ident > ,
1188
+ unmentioned_fields : & mut Vec < ( & ty :: FieldDef , Ident ) > ,
1177
1189
variant : & ty:: VariantDef ,
1178
1190
) -> DiagnosticBuilder < ' tcx > {
1179
1191
let tcx = self . tcx ;
@@ -1215,7 +1227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1215
1227
) ,
1216
1228
) ;
1217
1229
if plural == "" {
1218
- let input = unmentioned_fields. iter ( ) . map ( |field| & field. name ) ;
1230
+ let input = unmentioned_fields. iter ( ) . map ( |( _ , field) | & field. name ) ;
1219
1231
let suggested_name = find_best_match_for_name ( input, ident. name , None ) ;
1220
1232
if let Some ( suggested_name) = suggested_name {
1221
1233
err. span_suggestion (
@@ -1232,7 +1244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1232
1244
// `smart_resolve_context_dependent_help`.
1233
1245
if suggested_name. to_ident_string ( ) . parse :: < usize > ( ) . is_err ( ) {
1234
1246
// We don't want to throw `E0027` in case we have thrown `E0026` for them.
1235
- unmentioned_fields. retain ( |& x | x. name != suggested_name) ;
1247
+ unmentioned_fields. retain ( |& ( _ , x ) | x. name != suggested_name) ;
1236
1248
}
1237
1249
}
1238
1250
}
@@ -1300,17 +1312,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1300
1312
None
1301
1313
}
1302
1314
1315
+ /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
1316
+ /// inaccessible fields.
1317
+ ///
1318
+ /// ```ignore (diagnostic)
1319
+ /// error: pattern requires `..` due to inaccessible fields
1320
+ /// --> src/main.rs:10:9
1321
+ /// |
1322
+ /// LL | let foo::Foo {} = foo::Foo::default();
1323
+ /// | ^^^^^^^^^^^
1324
+ /// |
1325
+ /// help: add a `..`
1326
+ /// |
1327
+ /// LL | let foo::Foo { .. } = foo::Foo::default();
1328
+ /// | ^^^^^^
1329
+ /// ```
1330
+ fn error_no_accessible_fields (
1331
+ & self ,
1332
+ pat : & Pat < ' _ > ,
1333
+ fields : & ' tcx [ hir:: FieldPat < ' tcx > ] ,
1334
+ ) -> DiagnosticBuilder < ' tcx > {
1335
+ let mut err = self
1336
+ . tcx
1337
+ . sess
1338
+ . struct_span_err ( pat. span , "pattern requires `..` due to inaccessible fields" ) ;
1339
+
1340
+ if let Some ( field) = fields. last ( ) {
1341
+ err. span_suggestion_verbose (
1342
+ field. span . shrink_to_hi ( ) ,
1343
+ "ignore the inaccessible and unused fields" ,
1344
+ ", .." . to_string ( ) ,
1345
+ Applicability :: MachineApplicable ,
1346
+ ) ;
1347
+ } else {
1348
+ let qpath_span = if let PatKind :: Struct ( qpath, ..) = & pat. kind {
1349
+ qpath. span ( )
1350
+ } else {
1351
+ bug ! ( "`error_no_accessible_fields` called on non-struct pattern" ) ;
1352
+ } ;
1353
+
1354
+ // Shrink the span to exclude the `foo:Foo` in `foo::Foo { }`.
1355
+ let span = pat. span . with_lo ( qpath_span. shrink_to_hi ( ) . hi ( ) ) ;
1356
+ err. span_suggestion_verbose (
1357
+ span,
1358
+ "ignore the inaccessible and unused fields" ,
1359
+ " { .. }" . to_string ( ) ,
1360
+ Applicability :: MachineApplicable ,
1361
+ ) ;
1362
+ }
1363
+ err
1364
+ }
1365
+
1366
+ /// Returns a diagnostic reporting a struct pattern which does not mention some fields.
1367
+ ///
1368
+ /// ```ignore (diagnostic)
1369
+ /// error[E0027]: pattern does not mention field `you_cant_use_this_field`
1370
+ /// --> src/main.rs:15:9
1371
+ /// |
1372
+ /// LL | let foo::Foo {} = foo::Foo::new();
1373
+ /// | ^^^^^^^^^^^ missing field `you_cant_use_this_field`
1374
+ /// ```
1303
1375
fn error_unmentioned_fields (
1304
1376
& self ,
1305
1377
pat : & Pat < ' _ > ,
1306
- unmentioned_fields : & [ Ident ] ,
1378
+ unmentioned_fields : & [ ( & ty :: FieldDef , Ident ) ] ,
1307
1379
) -> DiagnosticBuilder < ' tcx > {
1308
1380
let field_names = if unmentioned_fields. len ( ) == 1 {
1309
- format ! ( "field `{}`" , unmentioned_fields[ 0 ] )
1381
+ format ! ( "field `{}`" , unmentioned_fields[ 0 ] . 1 )
1310
1382
} else {
1311
1383
let fields = unmentioned_fields
1312
1384
. iter ( )
1313
- . map ( |name| format ! ( "`{}`" , name) )
1385
+ . map ( |( _ , name) | format ! ( "`{}`" , name) )
1314
1386
. collect :: < Vec < String > > ( )
1315
1387
. join ( ", " ) ;
1316
1388
format ! ( "fields {}" , fields)
0 commit comments