Skip to content

Commit

Permalink
Auto merge of #95396 - TaKO8Ki:suggest-replacing-field-when-using-the…
Browse files Browse the repository at this point in the history
…-same-type, r=compiler-errors

Suggest replacing a field when using the same type

closes #89166
  • Loading branch information
bors committed Mar 28, 2022
2 parents 13c9fc3 + c26cfd1 commit b3e46a9
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 22 deletions.
59 changes: 37 additions & 22 deletions compiler/rustc_typeck/src/check/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1258,7 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.field_ty(span, f, substs)
})
.unwrap_or_else(|| {
inexistent_fields.push(field.ident);
inexistent_fields.push(field);
no_field_errors = false;
tcx.ty_error()
})
Expand All @@ -1276,13 +1276,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.collect::<Vec<_>>();

let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered())
&& !inexistent_fields.iter().any(|field| field.name == kw::Underscore)
&& !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
{
Some(self.error_inexistent_fields(
adt.variant_descr(),
&inexistent_fields,
&mut unmentioned_fields,
variant,
substs,
))
} else {
None
Expand Down Expand Up @@ -1448,28 +1449,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn error_inexistent_fields(
&self,
kind_name: &str,
inexistent_fields: &[Ident],
unmentioned_fields: &mut Vec<(&ty::FieldDef, Ident)>,
inexistent_fields: &[&hir::PatField<'tcx>],
unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
variant: &ty::VariantDef,
substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let tcx = self.tcx;
let (field_names, t, plural) = if inexistent_fields.len() == 1 {
(format!("a field named `{}`", inexistent_fields[0]), "this", "")
(format!("a field named `{}`", inexistent_fields[0].ident), "this", "")
} else {
(
format!(
"fields named {}",
inexistent_fields
.iter()
.map(|ident| format!("`{}`", ident))
.map(|field| format!("`{}`", field.ident))
.collect::<Vec<String>>()
.join(", ")
),
"these",
"s",
)
};
let spans = inexistent_fields.iter().map(|ident| ident.span).collect::<Vec<_>>();
let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
let mut err = struct_span_err!(
tcx.sess,
spans,
Expand All @@ -1479,9 +1481,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tcx.def_path_str(variant.def_id),
field_names
);
if let Some(ident) = inexistent_fields.last() {
if let Some(pat_field) = inexistent_fields.last() {
err.span_label(
ident.span,
pat_field.ident.span,
format!(
"{} `{}` does not have {} field{}",
kind_name,
Expand All @@ -1494,10 +1496,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if unmentioned_fields.len() == 1 {
let input =
unmentioned_fields.iter().map(|(_, field)| field.name).collect::<Vec<_>>();
let suggested_name = find_best_match_for_name(&input, ident.name, None);
let suggested_name = find_best_match_for_name(&input, pat_field.ident.name, None);
if let Some(suggested_name) = suggested_name {
err.span_suggestion(
ident.span,
pat_field.ident.span,
"a field with a similar name exists",
suggested_name.to_string(),
Applicability::MaybeIncorrect,
Expand All @@ -1513,17 +1515,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
}
} else if inexistent_fields.len() == 1 {
let unmentioned_field = unmentioned_fields[0].1.name;
err.span_suggestion_short(
ident.span,
&format!(
"`{}` has a field named `{}`",
tcx.def_path_str(variant.def_id),
unmentioned_field
),
unmentioned_field.to_string(),
Applicability::MaybeIncorrect,
);
match pat_field.pat.kind {
PatKind::Lit(expr)
if !self.can_coerce(
self.typeck_results.borrow().expr_ty(expr),
self.field_ty(
unmentioned_fields[0].1.span,
unmentioned_fields[0].0,
substs,
),
) => {}
_ => {
let unmentioned_field = unmentioned_fields[0].1.name;
err.span_suggestion_short(
pat_field.ident.span,
&format!(
"`{}` has a field named `{}`",
tcx.def_path_str(variant.def_id),
unmentioned_field
),
unmentioned_field.to_string(),
Applicability::MaybeIncorrect,
);
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
enum Foo {
Bar { a: u8, b: i8, c: u8 },
Baz { a: f32 },
None,
}

fn main() {
let foo = Foo::None;
match foo {
Foo::Bar { a, aa: 1, c } => (),
//~^ ERROR variant `Foo::Bar` does not have a field named `aa` [E0026]
//~| ERROR pattern does not mention field `b` [E0027]
Foo::Baz { bb: 1.0 } => (),
//~^ ERROR variant `Foo::Baz` does not have a field named `bb` [E0026]
//~| ERROR pattern does not mention field `a` [E0027]
_ => (),
}

match foo {
Foo::Bar { a, aa: "", c } => (),
//~^ ERROR variant `Foo::Bar` does not have a field named `aa` [E0026]
//~| ERROR pattern does not mention field `b` [E0027]
Foo::Baz { bb: "" } => (),
//~^ ERROR variant `Foo::Baz` does not have a field named `bb` [E0026]
//~| pattern does not mention field `a` [E0027]
_ => (),
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
error[E0026]: variant `Foo::Bar` does not have a field named `aa`
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:10:23
|
LL | Foo::Bar { a, aa: 1, c } => (),
| ^^
| |
| variant `Foo::Bar` does not have this field
| help: `Foo::Bar` has a field named `b`

error[E0027]: pattern does not mention field `b`
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:10:9
|
LL | Foo::Bar { a, aa: 1, c } => (),
| ^^^^^^^^^^^^^^^^^^^^^^^^ missing field `b`
|
help: include the missing field in the pattern
|
LL | Foo::Bar { a, aa: 1, c, b } => (),
| ~~~~~
help: if you don't care about this missing field, you can explicitly ignore it
|
LL | Foo::Bar { a, aa: 1, c, .. } => (),
| ~~~~~~

error[E0026]: variant `Foo::Baz` does not have a field named `bb`
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:13:20
|
LL | Foo::Baz { bb: 1.0 } => (),
| ^^
| |
| variant `Foo::Baz` does not have this field
| help: `Foo::Baz` has a field named `a`

error[E0027]: pattern does not mention field `a`
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:13:9
|
LL | Foo::Baz { bb: 1.0 } => (),
| ^^^^^^^^^^^^^^^^^^^^ missing field `a`
|
help: include the missing field in the pattern
|
LL | Foo::Baz { bb: 1.0, a } => (),
| ~~~~~
help: if you don't care about this missing field, you can explicitly ignore it
|
LL | Foo::Baz { bb: 1.0, .. } => (),
| ~~~~~~

error[E0026]: variant `Foo::Bar` does not have a field named `aa`
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:20:23
|
LL | Foo::Bar { a, aa: "", c } => (),
| ^^ variant `Foo::Bar` does not have this field

error[E0027]: pattern does not mention field `b`
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:20:9
|
LL | Foo::Bar { a, aa: "", c } => (),
| ^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `b`
|
help: include the missing field in the pattern
|
LL | Foo::Bar { a, aa: "", c, b } => (),
| ~~~~~
help: if you don't care about this missing field, you can explicitly ignore it
|
LL | Foo::Bar { a, aa: "", c, .. } => (),
| ~~~~~~

error[E0026]: variant `Foo::Baz` does not have a field named `bb`
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:23:20
|
LL | Foo::Baz { bb: "" } => (),
| ^^ variant `Foo::Baz` does not have this field

error[E0027]: pattern does not mention field `a`
--> $DIR/suggest-replacing-field-when-specifying-same-type.rs:23:9
|
LL | Foo::Baz { bb: "" } => (),
| ^^^^^^^^^^^^^^^^^^^ missing field `a`
|
help: include the missing field in the pattern
|
LL | Foo::Baz { bb: "", a } => (),
| ~~~~~
help: if you don't care about this missing field, you can explicitly ignore it
|
LL | Foo::Baz { bb: "", .. } => (),
| ~~~~~~

error: aborting due to 8 previous errors

Some errors have detailed explanations: E0026, E0027.
For more information about an error, try `rustc --explain E0026`.

0 comments on commit b3e46a9

Please sign in to comment.