mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
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.
This commit is contained in:
commit
4be63b2b5c
@ -1313,15 +1313,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
.emit();
|
||||
}
|
||||
} else if check_completeness && !error_happened && !remaining_fields.is_empty() {
|
||||
let no_accessible_remaining_fields = remaining_fields
|
||||
.iter()
|
||||
.find(|(_, (_, field))| {
|
||||
field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
|
||||
})
|
||||
.is_none();
|
||||
let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
|
||||
!field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
|
||||
});
|
||||
|
||||
if no_accessible_remaining_fields {
|
||||
self.report_no_accessible_fields(adt_ty, span);
|
||||
if inaccessible_remaining_fields {
|
||||
self.report_inaccessible_fields(adt_ty, span);
|
||||
} else {
|
||||
self.report_missing_fields(adt_ty, span, remaining_fields);
|
||||
}
|
||||
@ -1398,7 +1395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
.emit();
|
||||
}
|
||||
|
||||
/// Report an error for a struct field expression when there are no visible fields.
|
||||
/// Report an error for a struct field expression when there are invisible fields.
|
||||
///
|
||||
/// ```text
|
||||
/// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
|
||||
@ -1409,7 +1406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
///
|
||||
/// error: aborting due to previous error
|
||||
/// ```
|
||||
fn report_no_accessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
|
||||
fn report_inaccessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
&format!(
|
||||
|
@ -1250,15 +1250,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
|
||||
}
|
||||
} else if !etc && !unmentioned_fields.is_empty() {
|
||||
let no_accessible_unmentioned_fields = !unmentioned_fields.iter().any(|(field, _)| {
|
||||
field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
|
||||
});
|
||||
let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|(field, _)| {
|
||||
field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if no_accessible_unmentioned_fields {
|
||||
if accessible_unmentioned_fields.is_empty() {
|
||||
unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields));
|
||||
} else {
|
||||
unmentioned_err =
|
||||
Some(self.error_unmentioned_fields(pat, &unmentioned_fields, &fields));
|
||||
unmentioned_err = Some(self.error_unmentioned_fields(
|
||||
pat,
|
||||
&accessible_unmentioned_fields,
|
||||
accessible_unmentioned_fields.len() != unmentioned_fields.len(),
|
||||
&fields,
|
||||
));
|
||||
}
|
||||
}
|
||||
match (inexistent_fields_err, unmentioned_err) {
|
||||
@ -1583,17 +1591,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&self,
|
||||
pat: &Pat<'_>,
|
||||
unmentioned_fields: &[(&ty::FieldDef, Ident)],
|
||||
have_inaccessible_fields: bool,
|
||||
fields: &'tcx [hir::PatField<'tcx>],
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
|
||||
let field_names = if unmentioned_fields.len() == 1 {
|
||||
format!("field `{}`", unmentioned_fields[0].1)
|
||||
format!("field `{}`{}", unmentioned_fields[0].1, inaccessible)
|
||||
} else {
|
||||
let fields = unmentioned_fields
|
||||
.iter()
|
||||
.map(|(_, name)| format!("`{}`", name))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ");
|
||||
format!("fields {}", fields)
|
||||
format!("fields {}{}", fields, inaccessible)
|
||||
};
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
@ -1624,17 +1634,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
err.span_suggestion(
|
||||
sp,
|
||||
&format!(
|
||||
"include the missing field{} in the pattern",
|
||||
"include the missing field{} in the pattern{}",
|
||||
if len == 1 { "" } else { "s" },
|
||||
if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
|
||||
),
|
||||
format!(
|
||||
"{}{}{}",
|
||||
"{}{}{}{}",
|
||||
prefix,
|
||||
unmentioned_fields
|
||||
.iter()
|
||||
.map(|(_, name)| name.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
if have_inaccessible_fields { ", .." } else { "" },
|
||||
postfix,
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
|
@ -0,0 +1,11 @@
|
||||
pub mod foo {
|
||||
pub struct Foo {
|
||||
pub you_can_use_this_field: bool,
|
||||
you_cant_use_this_field: bool,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo::Foo {};
|
||||
//~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
|
||||
--> $DIR/issue-87872-missing-inaccessible-field-literal.rs:9:5
|
||||
|
|
||||
LL | foo::Foo {};
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,11 @@
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
pub mod foo {
|
||||
#[derive(Default)]
|
||||
pub struct Foo { pub visible: bool, invisible: bool, }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo::Foo {} = foo::Foo::default();
|
||||
//~^ ERROR pattern does not mention field `visible` and inaccessible fields
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
error[E0027]: pattern does not mention field `visible` and inaccessible fields
|
||||
--> $DIR/issue-87872-missing-inaccessible-field-pattern.rs:9:9
|
||||
|
|
||||
LL | let foo::Foo {} = foo::Foo::default();
|
||||
| ^^^^^^^^^^^ missing field `visible` and inaccessible fields
|
||||
|
|
||||
help: include the missing field in the pattern and ignore the inaccessible fields
|
||||
|
|
||||
LL | let foo::Foo { visible, .. } = foo::Foo::default();
|
||||
| ^^^^^^^^^^^^^^^
|
||||
help: if you don't care about this missing field, you can explicitly ignore it
|
||||
|
|
||||
LL | let foo::Foo { .. } = foo::Foo::default();
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0027`.
|
Loading…
Reference in New Issue
Block a user