Reduce the diagnostic span when multiple fields are missing in pattern

This commit is contained in:
Esteban Küber 2018-03-18 23:01:11 -07:00
parent adf2135adc
commit 685c3c1b4a
2 changed files with 59 additions and 28 deletions

View 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,

View File

@ -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");
}
}