Skip to content

Commit 4be63b2

Browse files
authored
Rollup merge of #87895 - TheWastl:issue-87872, r=estebank
typeck: don't suggest inaccessible fields in struct literals and suggest ignoring inaccessible fields in struct patterns Fixes #87872. This PR adjusts the missing field diagnostic logic in typeck so that when any of the missing fields in a struct literal or pattern is inaccessible then the error is less confusing, even if some of the missing fields are accessible. See also #76524.
2 parents 4d4915a + cda6ecf commit 4be63b2

6 files changed

+77
-20
lines changed

compiler/rustc_typeck/src/check/expr.rs

+7-10
Original file line numberDiff line numberDiff line change
@@ -1313,15 +1313,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13131313
.emit();
13141314
}
13151315
} else if check_completeness && !error_happened && !remaining_fields.is_empty() {
1316-
let no_accessible_remaining_fields = remaining_fields
1317-
.iter()
1318-
.find(|(_, (_, field))| {
1319-
field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
1320-
})
1321-
.is_none();
1316+
let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
1317+
!field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
1318+
});
13221319

1323-
if no_accessible_remaining_fields {
1324-
self.report_no_accessible_fields(adt_ty, span);
1320+
if inaccessible_remaining_fields {
1321+
self.report_inaccessible_fields(adt_ty, span);
13251322
} else {
13261323
self.report_missing_fields(adt_ty, span, remaining_fields);
13271324
}
@@ -1398,7 +1395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13981395
.emit();
13991396
}
14001397

1401-
/// Report an error for a struct field expression when there are no visible fields.
1398+
/// Report an error for a struct field expression when there are invisible fields.
14021399
///
14031400
/// ```text
14041401
/// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
@@ -1409,7 +1406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14091406
///
14101407
/// error: aborting due to previous error
14111408
/// ```
1412-
fn report_no_accessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
1409+
fn report_inaccessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
14131410
self.tcx.sess.span_err(
14141411
span,
14151412
&format!(

compiler/rustc_typeck/src/check/pat.rs

+22-10
Original file line numberDiff line numberDiff line change
@@ -1250,15 +1250,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12501250
tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
12511251
}
12521252
} else if !etc && !unmentioned_fields.is_empty() {
1253-
let no_accessible_unmentioned_fields = !unmentioned_fields.iter().any(|(field, _)| {
1254-
field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
1255-
});
1253+
let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
1254+
.iter()
1255+
.copied()
1256+
.filter(|(field, _)| {
1257+
field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
1258+
})
1259+
.collect();
12561260

1257-
if no_accessible_unmentioned_fields {
1261+
if accessible_unmentioned_fields.is_empty() {
12581262
unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields));
12591263
} else {
1260-
unmentioned_err =
1261-
Some(self.error_unmentioned_fields(pat, &unmentioned_fields, &fields));
1264+
unmentioned_err = Some(self.error_unmentioned_fields(
1265+
pat,
1266+
&accessible_unmentioned_fields,
1267+
accessible_unmentioned_fields.len() != unmentioned_fields.len(),
1268+
&fields,
1269+
));
12621270
}
12631271
}
12641272
match (inexistent_fields_err, unmentioned_err) {
@@ -1583,17 +1591,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15831591
&self,
15841592
pat: &Pat<'_>,
15851593
unmentioned_fields: &[(&ty::FieldDef, Ident)],
1594+
have_inaccessible_fields: bool,
15861595
fields: &'tcx [hir::PatField<'tcx>],
15871596
) -> DiagnosticBuilder<'tcx> {
1597+
let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
15881598
let field_names = if unmentioned_fields.len() == 1 {
1589-
format!("field `{}`", unmentioned_fields[0].1)
1599+
format!("field `{}`{}", unmentioned_fields[0].1, inaccessible)
15901600
} else {
15911601
let fields = unmentioned_fields
15921602
.iter()
15931603
.map(|(_, name)| format!("`{}`", name))
15941604
.collect::<Vec<String>>()
15951605
.join(", ");
1596-
format!("fields {}", fields)
1606+
format!("fields {}{}", fields, inaccessible)
15971607
};
15981608
let mut err = struct_span_err!(
15991609
self.tcx.sess,
@@ -1624,17 +1634,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16241634
err.span_suggestion(
16251635
sp,
16261636
&format!(
1627-
"include the missing field{} in the pattern",
1637+
"include the missing field{} in the pattern{}",
16281638
if len == 1 { "" } else { "s" },
1639+
if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
16291640
),
16301641
format!(
1631-
"{}{}{}",
1642+
"{}{}{}{}",
16321643
prefix,
16331644
unmentioned_fields
16341645
.iter()
16351646
.map(|(_, name)| name.to_string())
16361647
.collect::<Vec<_>>()
16371648
.join(", "),
1649+
if have_inaccessible_fields { ", .." } else { "" },
16381650
postfix,
16391651
),
16401652
Applicability::MachineApplicable,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
pub mod foo {
2+
pub struct Foo {
3+
pub you_can_use_this_field: bool,
4+
you_cant_use_this_field: bool,
5+
}
6+
}
7+
8+
fn main() {
9+
foo::Foo {};
10+
//~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
2+
--> $DIR/issue-87872-missing-inaccessible-field-literal.rs:9:5
3+
|
4+
LL | foo::Foo {};
5+
| ^^^^^^^^
6+
7+
error: aborting due to previous error
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![allow(dead_code, unused_variables)]
2+
3+
pub mod foo {
4+
#[derive(Default)]
5+
pub struct Foo { pub visible: bool, invisible: bool, }
6+
}
7+
8+
fn main() {
9+
let foo::Foo {} = foo::Foo::default();
10+
//~^ ERROR pattern does not mention field `visible` and inaccessible fields
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0027]: pattern does not mention field `visible` and inaccessible fields
2+
--> $DIR/issue-87872-missing-inaccessible-field-pattern.rs:9:9
3+
|
4+
LL | let foo::Foo {} = foo::Foo::default();
5+
| ^^^^^^^^^^^ missing field `visible` and inaccessible fields
6+
|
7+
help: include the missing field in the pattern and ignore the inaccessible fields
8+
|
9+
LL | let foo::Foo { visible, .. } = foo::Foo::default();
10+
| ^^^^^^^^^^^^^^^
11+
help: if you don't care about this missing field, you can explicitly ignore it
12+
|
13+
LL | let foo::Foo { .. } = foo::Foo::default();
14+
| ^^^^^^
15+
16+
error: aborting due to previous error
17+
18+
For more information about this error, try `rustc --explain E0027`.

0 commit comments

Comments
 (0)