typeck/expr: inaccessible private fields

This commit adjusts the missing field diagnostic logic for struct
expressions in typeck to improve the diagnostic when the missing
fields are inaccessible.

Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
David Wood 2020-09-09 15:42:37 +01:00
parent a18b34d979
commit c0894e7232
No known key found for this signature in database
GPG Key ID: 2592E76C87381FD9
3 changed files with 103 additions and 33 deletions

View File

@ -1241,42 +1241,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tcx.sess.span_err(span, "union expressions should have exactly one field");
}
} else if check_completeness && !error_happened && !remaining_fields.is_empty() {
let len = remaining_fields.len();
let mut displayable_field_names =
remaining_fields.keys().map(|ident| ident.as_str()).collect::<Vec<_>>();
displayable_field_names.sort();
let truncated_fields_error = if len <= 3 {
String::new()
} else {
format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" })
};
let remaining_fields_names = displayable_field_names
let no_accessible_remaining_fields = remaining_fields
.iter()
.take(3)
.map(|n| format!("`{}`", n))
.collect::<Vec<_>>()
.join(", ");
.filter(|(_, (_, field))| {
field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
})
.next()
.is_none();
struct_span_err!(
tcx.sess,
span,
E0063,
"missing field{} {}{} in initializer of `{}`",
pluralize!(remaining_fields.len()),
remaining_fields_names,
truncated_fields_error,
adt_ty
)
.span_label(
span,
format!("missing {}{}", remaining_fields_names, truncated_fields_error),
)
.emit();
if no_accessible_remaining_fields {
self.report_no_accessible_fields(adt_ty, span);
} else {
self.report_missing_field(adt_ty, span, remaining_fields);
}
}
error_happened
}
@ -1293,6 +1272,79 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
/// Report an error for a struct field expression when there are fields which aren't provided.
///
/// ```ignore (diagnostic)
/// error: missing field `you_can_use_this_field` in initializer of `foo::Foo`
/// --> src/main.rs:8:5
/// |
/// 8 | foo::Foo {};
/// | ^^^^^^^^ missing `you_can_use_this_field`
///
/// error: aborting due to previous error
/// ```
fn report_missing_field(
&self,
adt_ty: Ty<'tcx>,
span: Span,
remaining_fields: FxHashMap<Ident, (usize, &ty::FieldDef)>,
) {
let tcx = self.tcx;
let len = remaining_fields.len();
let mut displayable_field_names =
remaining_fields.keys().map(|ident| ident.as_str()).collect::<Vec<_>>();
displayable_field_names.sort();
let truncated_fields_error = if len <= 3 {
String::new()
} else {
format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" })
};
let remaining_fields_names = displayable_field_names
.iter()
.take(3)
.map(|n| format!("`{}`", n))
.collect::<Vec<_>>()
.join(", ");
struct_span_err!(
tcx.sess,
span,
E0063,
"missing field{} {}{} in initializer of `{}`",
pluralize!(remaining_fields.len()),
remaining_fields_names,
truncated_fields_error,
adt_ty
)
.span_label(span, format!("missing {}{}", remaining_fields_names, truncated_fields_error))
.emit();
}
/// Report an error for a struct field expression when there are no visible fields.
///
/// ```ignore (diagnostic)
/// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
/// --> src/main.rs:8:5
/// |
/// 8 | foo::Foo {};
/// | ^^^^^^^^
///
/// error: aborting due to previous error
/// ```
fn report_no_accessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
self.tcx.sess.span_err(
span,
&format!(
"cannot construct `{}` with struct literal syntax due to inaccessible fields",
adt_ty,
),
);
}
fn report_unknown_field(
&self,
ty: Ty<'tcx>,

View File

@ -0,0 +1,10 @@
pub mod foo {
pub struct Foo {
you_cant_use_this_field: bool,
}
}
fn main() {
foo::Foo {};
//~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields
}

View File

@ -0,0 +1,8 @@
error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
--> $DIR/issue-76077.rs:8:5
|
LL | foo::Foo {};
| ^^^^^^^^
error: aborting due to previous error