Rollup merge of #49160 - estebank:issue-47457-missing-fields, r=oli-obk
Reduce the diagnostic spam when multiple fields are missing in pattern Fix #47457.
This commit is contained in:
commit
401a93096d
9 changed files with 104 additions and 42 deletions
|
|
@ -904,6 +904,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
|
|||
// 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 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
|
|||
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,47 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
|
|||
self.check_pat_walk(&field.pat, field_ty, def_bm, true);
|
||||
}
|
||||
|
||||
if inexistent_fields.len() > 0 {
|
||||
let (field_names, t, plural) = if inexistent_fields.len() == 1 {
|
||||
(format!("a field named `{}`", inexistent_fields[0].1), "this", "")
|
||||
} else {
|
||||
(format!("fields named {}",
|
||||
inexistent_fields.iter()
|
||||
.map(|(_, name)| format!("`{}`", name))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")), "these", "s")
|
||||
};
|
||||
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);
|
||||
if let Some((span, _)) = inexistent_fields.last() {
|
||||
err.span_label(*span,
|
||||
format!("{} `{}` does not have {} field{}",
|
||||
kind_name,
|
||||
tcx.item_path_str(variant.did),
|
||||
t,
|
||||
plural));
|
||||
}
|
||||
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,
|
||||
|
|
@ -979,13 +994,25 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
|
|||
tcx.sess.span_err(span, "`..` cannot be used in union patterns");
|
||||
}
|
||||
} else if !etc {
|
||||
for field in variant.fields
|
||||
let unmentioned_fields = variant.fields
|
||||
.iter()
|
||||
.filter(|field| !used_fields.contains_key(&field.name)) {
|
||||
.map(|field| field.name)
|
||||
.filter(|field| !used_fields.contains_key(&field))
|
||||
.collect::<Vec<_>>();
|
||||
if unmentioned_fields.len() > 0 {
|
||||
let field_names = if unmentioned_fields.len() == 1 {
|
||||
format!("field `{}`", unmentioned_fields[0])
|
||||
} else {
|
||||
format!("fields {}",
|
||||
unmentioned_fields.iter()
|
||||
.map(|name| format!("`{}`", name))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "))
|
||||
};
|
||||
let mut diag = struct_span_err!(tcx.sess, span, E0027,
|
||||
"pattern does not mention field `{}`",
|
||||
field.name);
|
||||
diag.span_label(span, format!("missing field `{}`", field.name));
|
||||
"pattern does not mention {}",
|
||||
field_names);
|
||||
diag.span_label(span, format!("missing {}", field_names));
|
||||
if variant.ctor_kind == CtorKind::Fn {
|
||||
diag.note("trying to match a tuple variant with a struct variant pattern");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,8 @@ struct a {
|
|||
impl a {
|
||||
fn foo(&self) {
|
||||
let a { x, y } = self.d; //~ ERROR no field `d` on type `&a`
|
||||
//~^ ERROR struct `a` does not have a field named `x`
|
||||
//~^^ ERROR struct `a` does not have a field named `y`
|
||||
//~^^^ ERROR pattern does not mention field `b`
|
||||
//~^^^^ ERROR pattern does not mention field `c`
|
||||
//~^ ERROR struct `a` does not have fields named `x`, `y`
|
||||
//~| ERROR pattern does not mention fields `b`, `c`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ error[E0026]: struct `Thing` does not have a field named `z`
|
|||
--> $DIR/E0026-teach.rs:21:23
|
||||
|
|
||||
LL | Thing { x, y, z } => {}
|
||||
| ^ struct `Thing` does not have field `z`
|
||||
| ^ struct `Thing` does not have this field
|
||||
|
|
||||
= 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.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ error[E0026]: struct `Thing` does not have a field named `z`
|
|||
--> $DIR/E0026.rs:19:23
|
||||
|
|
||||
LL | Thing { x, y, z } => {}
|
||||
| ^ struct `Thing` does not have field `z`
|
||||
| ^ struct `Thing` does not have this field
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
19
src/test/ui/missing-fields-in-struct-pattern.rs
Normal file
19
src/test/ui/missing-fields-in-struct-pattern.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// 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) {
|
||||
//~^ ERROR struct `S` does not have fields named `a`, `b`, `c`, `d` [E0026]
|
||||
//~| ERROR pattern does not mention fields `0`, `1`, `2`, `3` [E0027]
|
||||
println!("hi");
|
||||
}
|
||||
}
|
||||
18
src/test/ui/missing-fields-in-struct-pattern.stderr
Normal file
18
src/test/ui/missing-fields-in-struct-pattern.stderr
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
error[E0026]: struct `S` does not have fields named `a`, `b`, `c`, `d`
|
||||
--> $DIR/missing-fields-in-struct-pattern.rs:14:16
|
||||
|
|
||||
LL | if let S { a, b, c, d } = S(1, 2, 3, 4) {
|
||||
| ^ ^ ^ ^ struct `S` does not have these fields
|
||||
|
||||
error[E0027]: pattern does not mention fields `0`, `1`, `2`, `3`
|
||||
--> $DIR/missing-fields-in-struct-pattern.rs:14:12
|
||||
|
|
||||
LL | if let S { a, b, c, d } = S(1, 2, 3, 4) {
|
||||
| ^^^^^^^^^^^^^^^^ missing fields `0`, `1`, `2`, `3`
|
||||
|
|
||||
= note: trying to match a tuple variant with a struct variant pattern
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors occurred: E0026, E0027.
|
||||
For more information about an error, try `rustc --explain E0026`.
|
||||
|
|
@ -10,7 +10,7 @@ error[E0026]: struct `S` does not have a field named `0x1`
|
|||
--> $DIR/numeric-fields.rs:17:17
|
||||
|
|
||||
LL | S{0: a, 0x1: b, ..} => {}
|
||||
| ^^^^^^ struct `S` does not have field `0x1`
|
||||
| ^^^^^^ struct `S` does not have this field
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ error[E0026]: variant `X::Y` does not have a field named `number`
|
|||
--> $DIR/issue-41314.rs:17:16
|
||||
|
|
||||
LL | X::Y { number } => {} //~ ERROR does not have a field named `number`
|
||||
| ^^^^^^ variant `X::Y` does not have field `number`
|
||||
| ^^^^^^ variant `X::Y` does not have this field
|
||||
|
||||
error[E0027]: pattern does not mention field `0`
|
||||
--> $DIR/issue-41314.rs:17:9
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ error[E0026]: union `U` does not have a field named `c`
|
|||
--> $DIR/union-fields-2.rs:28:19
|
||||
|
|
||||
LL | let U { a, b, c } = u; //~ ERROR union patterns should have exactly one field
|
||||
| ^ union `U` does not have field `c`
|
||||
| ^ union `U` does not have this field
|
||||
|
||||
error: union patterns should have exactly one field
|
||||
--> $DIR/union-fields-2.rs:28:9
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue