Skip to content

Commit 685c3c1

Browse files
committed
Reduce the diagnostic span when multiple fields are missing in pattern
1 parent adf2135 commit 685c3c1

File tree

2 files changed

+59
-28
lines changed

2 files changed

+59
-28
lines changed

src/librustc_typeck/check/_match.rs

+42-28
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
904904
// Keep track of which fields have already appeared in the pattern.
905905
let mut used_fields = FxHashMap();
906906

907+
let mut inexistent_fields = vec![];
907908
// Typecheck each field.
908909
for &Spanned { node: ref field, span } in fields {
909910
let field_ty = match used_fields.entry(field.name) {
@@ -927,34 +928,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
927928
self.field_ty(span, f, substs)
928929
})
929930
.unwrap_or_else(|| {
930-
let mut err = struct_span_err!(
931-
tcx.sess,
932-
span,
933-
E0026,
934-
"{} `{}` does not have a field named `{}`",
935-
kind_name,
936-
tcx.item_path_str(variant.did),
937-
field.name
938-
);
939-
err.span_label(span,
940-
format!("{} `{}` does not have field `{}`",
941-
kind_name,
942-
tcx.item_path_str(variant.did),
943-
field.name));
944-
if tcx.sess.teach(&err.get_code().unwrap()) {
945-
err.note(
946-
"This error indicates that a struct pattern attempted to \
947-
extract a non-existent field from a struct. Struct fields \
948-
are identified by the name used before the colon : so struct \
949-
patterns should resemble the declaration of the struct type \
950-
being matched.\n\n\
951-
If you are using shorthand field patterns but want to refer \
952-
to the struct field by a different name, you should rename \
953-
it explicitly."
954-
);
955-
}
956-
err.emit();
957-
931+
inexistent_fields.push((span, field.name));
958932
tcx.types.err
959933
})
960934
}
@@ -963,6 +937,46 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
963937
self.check_pat_walk(&field.pat, field_ty, def_bm, true);
964938
}
965939

940+
if inexistent_fields.len() > 0 {
941+
let field_names = if inexistent_fields.len() == 1 {
942+
format!("a field named `{}`", inexistent_fields[0].1)
943+
} else {
944+
format!("fields named {}",
945+
inexistent_fields.iter()
946+
.map(|(_, name)| format!("`{}`", name))
947+
.collect::<Vec<String>>()
948+
.join(", "))
949+
};
950+
let spans = inexistent_fields.iter().map(|(span, _)| *span).collect::<Vec<_>>();
951+
let mut err = struct_span_err!(tcx.sess,
952+
spans,
953+
E0026,
954+
"{} `{}` does not have {}",
955+
kind_name,
956+
tcx.item_path_str(variant.did),
957+
field_names);
958+
for (span, name) in &inexistent_fields {
959+
err.span_label(*span,
960+
format!("{} `{}` does not have field `{}`",
961+
kind_name,
962+
tcx.item_path_str(variant.did),
963+
name));
964+
}
965+
if tcx.sess.teach(&err.get_code().unwrap()) {
966+
err.note(
967+
"This error indicates that a struct pattern attempted to \
968+
extract a non-existent field from a struct. Struct fields \
969+
are identified by the name used before the colon : so struct \
970+
patterns should resemble the declaration of the struct type \
971+
being matched.\n\n\
972+
If you are using shorthand field patterns but want to refer \
973+
to the struct field by a different name, you should rename \
974+
it explicitly."
975+
);
976+
}
977+
err.emit();
978+
}
979+
966980
// Require `..` if struct has non_exhaustive attribute.
967981
if adt.is_struct() && adt.is_non_exhaustive() && !adt.did.is_local() && !etc {
968982
span_err!(tcx.sess, span, E0638,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct S(usize, usize, usize, usize);
12+
13+
fn main() {
14+
if let S { a, b, c, d } = S(1, 2, 3, 4) {
15+
println!("hi");
16+
}
17+
}

0 commit comments

Comments
 (0)