about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTakayuki Maeda <takoyaki0316@gmail.com>2022-03-28 12:38:10 +0900
committerTakayuki Maeda <takoyaki0316@gmail.com>2022-03-28 12:38:10 +0900
commit9e4d019fee6f8f0b452c99f883c501c341d36dba (patch)
treeb66e550ab71bef24b4aa5aa4801597617ef319a9
parent185a3f0a112fd6439247cf15452d0c5dfb3c8c92 (diff)
downloadrust-9e4d019fee6f8f0b452c99f883c501c341d36dba.tar.gz
rust-9e4d019fee6f8f0b452c99f883c501c341d36dba.zip
suggest replacing field when using the same type
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs60
-rw-r--r--src/test/ui/issues/issue-51102.stderr5
-rw-r--r--src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.rs28
-rw-r--r--src/test/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr94
4 files changed, 161 insertions, 26 deletions
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 1c4fbbbb9bf..67124f2d238 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -10,6 +10,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::{HirId, Pat, PatKind};
 use rustc_infer::infer;
+use rustc_infer::infer::error_reporting::same_type_modulo_infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable};
@@ -1258,7 +1259,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 +1277,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
@@ -1448,20 +1450,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<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(", ")
                 ),
@@ -1469,7 +1472,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 "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,
@@ -1479,9 +1482,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 +1497,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,
@@ -1513,17 +1516,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 !same_type_modulo_infer(
+                                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/issues/issue-51102.stderr b/src/test/ui/issues/issue-51102.stderr
index 09c52292dcc..eb9eb680200 100644
--- a/src/test/ui/issues/issue-51102.stderr
+++ b/src/test/ui/issues/issue-51102.stderr
@@ -2,10 +2,7 @@ error[E0026]: struct `SimpleStruct` does not have a field named `state`
   --> $DIR/issue-51102.rs:13:17
    |
 LL |                 state: 0,
-   |                 ^^^^^
-   |                 |
-   |                 struct `SimpleStruct` does not have this field
-   |                 help: `SimpleStruct` has a field named `no_state_here`
+   |                 ^^^^^ struct `SimpleStruct` does not have this field
 
 error[E0025]: field `no_state_here` bound multiple times in the pattern
   --> $DIR/issue-51102.rs:24:17
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 00000000000..dd2fe79731e
--- /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 00000000000..e8503f540c2
--- /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`.