@@ -1078,8 +1078,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10781078 let mut unmentioned_fields = variant
10791079 . fields
10801080 . 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) )
10831083 . collect :: < Vec < _ > > ( ) ;
10841084
10851085 let inexistent_fields_err = if !( inexistent_fields. is_empty ( ) || variant. is_recovered ( ) ) {
@@ -1110,7 +1110,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11101110 tcx. sess . struct_span_err ( pat. span , "`..` cannot be used in union patterns" ) . emit ( ) ;
11111111 }
11121112 } 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+ }
11141126 }
11151127 match ( inexistent_fields_err, unmentioned_err) {
11161128 ( Some ( mut i) , Some ( mut u) ) => {
@@ -1173,7 +1185,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11731185 & self ,
11741186 kind_name : & str ,
11751187 inexistent_fields : & [ Ident ] ,
1176- unmentioned_fields : & mut Vec < Ident > ,
1188+ unmentioned_fields : & mut Vec < ( & ty :: FieldDef , Ident ) > ,
11771189 variant : & ty:: VariantDef ,
11781190 ) -> DiagnosticBuilder < ' tcx > {
11791191 let tcx = self . tcx ;
@@ -1215,7 +1227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12151227 ) ,
12161228 ) ;
12171229 if plural == "" {
1218- let input = unmentioned_fields. iter ( ) . map ( |field| & field. name ) ;
1230+ let input = unmentioned_fields. iter ( ) . map ( |( _ , field) | & field. name ) ;
12191231 let suggested_name = find_best_match_for_name ( input, ident. name , None ) ;
12201232 if let Some ( suggested_name) = suggested_name {
12211233 err. span_suggestion (
@@ -1232,7 +1244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12321244 // `smart_resolve_context_dependent_help`.
12331245 if suggested_name. to_ident_string ( ) . parse :: < usize > ( ) . is_err ( ) {
12341246 // 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) ;
12361248 }
12371249 }
12381250 }
@@ -1300,17 +1312,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13001312 None
13011313 }
13021314
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+ /// ```
13031375 fn error_unmentioned_fields (
13041376 & self ,
13051377 pat : & Pat < ' _ > ,
1306- unmentioned_fields : & [ Ident ] ,
1378+ unmentioned_fields : & [ ( & ty :: FieldDef , Ident ) ] ,
13071379 ) -> DiagnosticBuilder < ' tcx > {
13081380 let field_names = if unmentioned_fields. len ( ) == 1 {
1309- format ! ( "field `{}`" , unmentioned_fields[ 0 ] )
1381+ format ! ( "field `{}`" , unmentioned_fields[ 0 ] . 1 )
13101382 } else {
13111383 let fields = unmentioned_fields
13121384 . iter ( )
1313- . map ( |name| format ! ( "`{}`" , name) )
1385+ . map ( |( _ , name) | format ! ( "`{}`" , name) )
13141386 . collect :: < Vec < String > > ( )
13151387 . join ( ", " ) ;
13161388 format ! ( "fields {}" , fields)
0 commit comments