// 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) {
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
})
}
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,
--- /dev/null
+// 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");
+ }
+}