diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 1c4fbbbb9bfaf..d66230acb8bda 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -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() }) @@ -1276,13 +1276,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect::>(); 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 @@ -1448,20 +1449,21 @@ 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>, ) -> 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::>() .join(", ") ), @@ -1469,7 +1471,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "s", ) }; - let spans = inexistent_fields.iter().map(|ident| ident.span).collect::>(); + let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::>(); let mut err = struct_span_err!( tcx.sess, spans, @@ -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, @@ -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::>(); - 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, @@ -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, + ); + } + } } } } diff --git a/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.rs b/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.rs new file mode 100644 index 0000000000000..dd2fe79731eac --- /dev/null +++ b/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.rs @@ -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] + _ => (), + } +} diff --git a/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr b/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr new file mode 100644 index 0000000000000..e8503f540c288 --- /dev/null +++ b/src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr @@ -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`.