]> git.lizzy.rs Git - rust.git/commitdiff
Reduce the diagnostic span when multiple fields are missing in pattern
authorEsteban Küber <esteban@kuber.com.ar>
Mon, 19 Mar 2018 06:01:11 +0000 (23:01 -0700)
committerEsteban Küber <esteban@kuber.com.ar>
Mon, 19 Mar 2018 06:01:11 +0000 (23:01 -0700)
src/librustc_typeck/check/_match.rs
src/test/ui/missing-fields-in-struct-pattern.rs [new file with mode: 0644]

index 379fd93ba2bd6ebb31bb8ab2ab46c971a21e4a6a..0b5383f1f8d1ed06cac2c209129ea8eb8c7fb83f 100644 (file)
@@ -904,6 +904,7 @@ fn check_struct_pat_fields(&self,
         // Keep track of which fields have already appeared in the pattern.
         let mut used_fields = FxHashMap();
 
+        let mut inexistent_fields = vec![];
         // Typecheck each field.
         for &Spanned { node: ref field, span } in fields {
             let field_ty = match used_fields.entry(field.name) {
@@ -927,34 +928,7 @@ fn check_struct_pat_fields(&self,
                             self.field_ty(span, f, substs)
                         })
                         .unwrap_or_else(|| {
-                            let mut err = struct_span_err!(
-                                tcx.sess,
-                                span,
-                                E0026,
-                                "{} `{}` does not have a field named `{}`",
-                                kind_name,
-                                tcx.item_path_str(variant.did),
-                                field.name
-                            );
-                            err.span_label(span,
-                                           format!("{} `{}` does not have field `{}`",
-                                                   kind_name,
-                                                   tcx.item_path_str(variant.did),
-                                                   field.name));
-                            if tcx.sess.teach(&err.get_code().unwrap()) {
-                                err.note(
-                                    "This error indicates that a struct pattern attempted to \
-                                     extract a non-existent field from a struct. Struct fields \
-                                     are identified by the name used before the colon : so struct \
-                                     patterns should resemble the declaration of the struct type \
-                                     being matched.\n\n\
-                                     If you are using shorthand field patterns but want to refer \
-                                     to the struct field by a different name, you should rename \
-                                     it explicitly."
-                                );
-                            }
-                            err.emit();
-
+                            inexistent_fields.push((span, field.name));
                             tcx.types.err
                         })
                 }
@@ -963,6 +937,46 @@ fn check_struct_pat_fields(&self,
             self.check_pat_walk(&field.pat, field_ty, def_bm, true);
         }
 
+        if inexistent_fields.len() > 0 {
+            let field_names = if inexistent_fields.len() == 1 {
+                format!("a field named `{}`", inexistent_fields[0].1)
+            } else {
+                format!("fields named {}",
+                        inexistent_fields.iter()
+                            .map(|(_, name)| format!("`{}`", name))
+                            .collect::<Vec<String>>()
+                            .join(", "))
+            };
+            let spans = inexistent_fields.iter().map(|(span, _)| *span).collect::<Vec<_>>();
+            let mut err = struct_span_err!(tcx.sess,
+                                           spans,
+                                           E0026,
+                                           "{} `{}` does not have {}",
+                                           kind_name,
+                                           tcx.item_path_str(variant.did),
+                                           field_names);
+            for (span, name) in &inexistent_fields {
+                err.span_label(*span,
+                               format!("{} `{}` does not have field `{}`",
+                                       kind_name,
+                                       tcx.item_path_str(variant.did),
+                                       name));
+            }
+            if tcx.sess.teach(&err.get_code().unwrap()) {
+                err.note(
+                    "This error indicates that a struct pattern attempted to \
+                     extract a non-existent field from a struct. Struct fields \
+                     are identified by the name used before the colon : so struct \
+                     patterns should resemble the declaration of the struct type \
+                     being matched.\n\n\
+                     If you are using shorthand field patterns but want to refer \
+                     to the struct field by a different name, you should rename \
+                     it explicitly."
+                );
+            }
+            err.emit();
+        }
+
         // Require `..` if struct has non_exhaustive attribute.
         if adt.is_struct() && adt.is_non_exhaustive() && !adt.did.is_local() && !etc {
             span_err!(tcx.sess, span, E0638,
diff --git a/src/test/ui/missing-fields-in-struct-pattern.rs b/src/test/ui/missing-fields-in-struct-pattern.rs
new file mode 100644 (file)
index 0000000..2469f24
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S(usize, usize, usize, usize);
+
+fn main() {
+    if let S { a, b, c, d } = S(1, 2, 3, 4) {
+        println!("hi");
+    }
+}