Skip to content

Commit 16692ab

Browse files
committed
Suggest _ and .. if a pattern has too few fields
For example, this code: struct S(i32, f32); let S(x) = S(0, 1.0); will make the compiler suggest either: let S(x, _) = S(0, 1.0); or: let S(x, ..) = S(0, 1.0);
1 parent 058a710 commit 16692ab

File tree

9 files changed

+262
-0
lines changed

9 files changed

+262
-0
lines changed

compiler/rustc_typeck/src/check/pat.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ use rustc_span::hygiene::DesugaringKind;
1515
use rustc_span::lev_distance::find_best_match_for_name;
1616
use rustc_span::source_map::{Span, Spanned};
1717
use rustc_span::symbol::Ident;
18+
use rustc_span::{BytePos, DUMMY_SP};
1819
use rustc_trait_selection::traits::{ObligationCause, Pattern};
1920

2021
use std::cmp;
2122
use std::collections::hash_map::Entry::{Occupied, Vacant};
23+
use std::iter;
2224

2325
use super::report_unexpected_variant_res;
2426

@@ -1040,6 +1042,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10401042
vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
10411043
Applicability::MachineApplicable,
10421044
);
1045+
} else if fields.len() > subpats.len() {
1046+
let after_fields_span = if pat_span == DUMMY_SP {
1047+
pat_span
1048+
} else {
1049+
pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi()
1050+
};
1051+
1052+
let mut wildcard_sugg =
1053+
iter::repeat("_").take(fields.len() - subpats.len()).collect::<Vec<_>>().join(", ");
1054+
if !subpats.is_empty() {
1055+
wildcard_sugg = String::from(", ") + &wildcard_sugg;
1056+
}
1057+
1058+
let rest_sugg = if subpats.is_empty() { "..".to_owned() } else { ", ..".to_owned() };
1059+
1060+
err.span_suggestion(
1061+
after_fields_span,
1062+
"use `_` to explicitly ignore each field",
1063+
wildcard_sugg,
1064+
Applicability::MaybeIncorrect,
1065+
);
1066+
err.span_suggestion(
1067+
after_fields_span,
1068+
"use `..` to ignore all unmentioned fields",
1069+
rest_sugg,
1070+
Applicability::MaybeIncorrect,
1071+
);
10431072
}
10441073

10451074
err.emit();

src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ LL | struct TupleStruct<S, T>(S, T);
3131
...
3232
LL | TupleStruct(_) = TupleStruct(1, 2);
3333
| ^^^^^^^^^^^^^^ expected 2 fields, found 1
34+
|
35+
help: use `_` to explicitly ignore each field
36+
|
37+
LL | TupleStruct(_, _) = TupleStruct(1, 2);
38+
| ^^^
39+
help: use `..` to ignore all unmentioned fields
40+
|
41+
LL | TupleStruct(_, ..) = TupleStruct(1, 2);
42+
| ^^^^
3443

3544
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
3645
--> $DIR/tuple_struct_destructure_fail.rs:34:5
@@ -49,6 +58,15 @@ LL | SingleVariant(S, T)
4958
...
5059
LL | Enum::SingleVariant(_) = Enum::SingleVariant(1, 2);
5160
| ^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 1
61+
|
62+
help: use `_` to explicitly ignore each field
63+
|
64+
LL | Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2);
65+
| ^^^
66+
help: use `..` to ignore all unmentioned fields
67+
|
68+
LL | Enum::SingleVariant(_, ..) = Enum::SingleVariant(1, 2);
69+
| ^^^^
5270

5371
error[E0070]: invalid left-hand side of assignment
5472
--> $DIR/tuple_struct_destructure_fail.rs:40:12

src/test/ui/error-codes/E0023.stderr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ LL | Apple(String, String),
66
...
77
LL | Fruit::Apple(a) => {},
88
| ^^^^^^^^^^^^^^^ expected 2 fields, found 1
9+
|
10+
help: use `_` to explicitly ignore each field
11+
|
12+
LL | Fruit::Apple(a, _) => {},
13+
| ^^^
14+
help: use `..` to ignore all unmentioned fields
15+
|
16+
LL | Fruit::Apple(a, ..) => {},
17+
| ^^^^
918

1019
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
1120
--> $DIR/E0023.rs:12:9

src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ LL | struct P<T>(T); // 1 type parameter wanted
1717
...
1818
LL | let P() = U {};
1919
| ^^^ expected 1 field, found 0
20+
|
21+
help: use `_` to explicitly ignore each field
22+
|
23+
LL | let P(_) = U {};
24+
| ^
25+
help: use `..` to ignore all unmentioned fields
26+
|
27+
LL | let P(..) = U {};
28+
| ^^
2029

2130
error: aborting due to 2 previous errors
2231

src/test/ui/issues/issue-72574-2.stderr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ LL | struct Binder(i32, i32, i32);
2626
...
2727
LL | Binder(_a, _x @ ..) => {}
2828
| ^^^^^^^^^^^^^^^^^^^ expected 3 fields, found 2
29+
|
30+
help: use `_` to explicitly ignore each field
31+
|
32+
LL | Binder(_a, _x @ .., _) => {}
33+
| ^^^
34+
help: use `..` to ignore all unmentioned fields
35+
|
36+
LL | Binder(_a, _x @ .., ..) => {}
37+
| ^^^^
2938

3039
error: aborting due to 3 previous errors
3140

src/test/ui/match/match-pattern-field-mismatch.stderr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ LL | Rgb(usize, usize, usize),
66
...
77
LL | Color::Rgb(_, _) => { }
88
| ^^^^^^^^^^^^^^^^ expected 3 fields, found 2
9+
|
10+
help: use `_` to explicitly ignore each field
11+
|
12+
LL | Color::Rgb(_, _, _) => { }
13+
| ^^^
14+
help: use `..` to ignore all unmentioned fields
15+
|
16+
LL | Color::Rgb(_, _, ..) => { }
17+
| ^^^^
918

1019
error: aborting due to previous error
1120

src/test/ui/pattern/issue-74539.stderr

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ LL | A(u8, u8),
2626
...
2727
LL | E::A(x @ ..) => {
2828
| ^^^^^^^^^^^^ expected 2 fields, found 1
29+
|
30+
help: use `_` to explicitly ignore each field
31+
|
32+
LL | E::A(x @ .., _) => {
33+
| ^^^
34+
help: use `..` to ignore all unmentioned fields
35+
|
36+
LL | E::A(x @ .., ..) => {
37+
| ^^^^
2938

3039
error: aborting due to 3 previous errors
3140

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
struct S(i32, f32);
2+
enum E {
3+
S(i32, f32),
4+
}
5+
6+
fn main() {
7+
match S(0, 1.0) {
8+
S(x) => {}
9+
//~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
10+
//~| HELP use `_` to explicitly ignore each field
11+
//~| HELP use `..` to ignore all unmentioned fields
12+
}
13+
match S(0, 1.0) {
14+
S(_) => {}
15+
//~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
16+
//~| HELP use `_` to explicitly ignore each field
17+
//~| HELP use `..` to ignore all unmentioned fields
18+
}
19+
match S(0, 1.0) {
20+
S() => {}
21+
//~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 2 fields
22+
//~| HELP use `_` to explicitly ignore each field
23+
//~| HELP use `..` to ignore all unmentioned fields
24+
}
25+
26+
match E::S(0, 1.0) {
27+
E::S(x) => {}
28+
//~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
29+
//~| HELP use `_` to explicitly ignore each field
30+
//~| HELP use `..` to ignore all unmentioned fields
31+
}
32+
match E::S(0, 1.0) {
33+
E::S(_) => {}
34+
//~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
35+
//~| HELP use `_` to explicitly ignore each field
36+
//~| HELP use `..` to ignore all unmentioned fields
37+
}
38+
match E::S(0, 1.0) {
39+
E::S() => {}
40+
//~^ ERROR this pattern has 0 fields, but the corresponding tuple variant has 2 fields
41+
//~| HELP use `_` to explicitly ignore each field
42+
//~| HELP use `..` to ignore all unmentioned fields
43+
}
44+
match E::S(0, 1.0) {
45+
E::S => {}
46+
//~^ ERROR expected unit struct, unit variant or constant, found tuple variant `E::S`
47+
//~| HELP use the tuple variant pattern syntax instead
48+
}
49+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::S`
2+
--> $DIR/pat-tuple-underfield.rs:45:9
3+
|
4+
LL | S(i32, f32),
5+
| ----------- `E::S` defined here
6+
...
7+
LL | E::S => {}
8+
| ^^^^ help: use the tuple variant pattern syntax instead: `E::S(_, _)`
9+
10+
error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
11+
--> $DIR/pat-tuple-underfield.rs:8:9
12+
|
13+
LL | struct S(i32, f32);
14+
| ------------------- tuple struct defined here
15+
...
16+
LL | S(x) => {}
17+
| ^^^^ expected 2 fields, found 1
18+
|
19+
help: use `_` to explicitly ignore each field
20+
|
21+
LL | S(x, _) => {}
22+
| ^^^
23+
help: use `..` to ignore all unmentioned fields
24+
|
25+
LL | S(x, ..) => {}
26+
| ^^^^
27+
28+
error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
29+
--> $DIR/pat-tuple-underfield.rs:14:9
30+
|
31+
LL | struct S(i32, f32);
32+
| ------------------- tuple struct defined here
33+
...
34+
LL | S(_) => {}
35+
| ^^^^ expected 2 fields, found 1
36+
|
37+
help: use `_` to explicitly ignore each field
38+
|
39+
LL | S(_, _) => {}
40+
| ^^^
41+
help: use `..` to ignore all unmentioned fields
42+
|
43+
LL | S(_, ..) => {}
44+
| ^^^^
45+
46+
error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields
47+
--> $DIR/pat-tuple-underfield.rs:20:9
48+
|
49+
LL | struct S(i32, f32);
50+
| ------------------- tuple struct defined here
51+
...
52+
LL | S() => {}
53+
| ^^^ expected 2 fields, found 0
54+
|
55+
help: use `_` to explicitly ignore each field
56+
|
57+
LL | S(_, _) => {}
58+
| ^^^^
59+
help: use `..` to ignore all unmentioned fields
60+
|
61+
LL | S(..) => {}
62+
| ^^
63+
64+
error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
65+
--> $DIR/pat-tuple-underfield.rs:27:9
66+
|
67+
LL | S(i32, f32),
68+
| ----------- tuple variant defined here
69+
...
70+
LL | E::S(x) => {}
71+
| ^^^^^^^ expected 2 fields, found 1
72+
|
73+
help: use `_` to explicitly ignore each field
74+
|
75+
LL | E::S(x, _) => {}
76+
| ^^^
77+
help: use `..` to ignore all unmentioned fields
78+
|
79+
LL | E::S(x, ..) => {}
80+
| ^^^^
81+
82+
error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
83+
--> $DIR/pat-tuple-underfield.rs:33:9
84+
|
85+
LL | S(i32, f32),
86+
| ----------- tuple variant defined here
87+
...
88+
LL | E::S(_) => {}
89+
| ^^^^^^^ expected 2 fields, found 1
90+
|
91+
help: use `_` to explicitly ignore each field
92+
|
93+
LL | E::S(_, _) => {}
94+
| ^^^
95+
help: use `..` to ignore all unmentioned fields
96+
|
97+
LL | E::S(_, ..) => {}
98+
| ^^^^
99+
100+
error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields
101+
--> $DIR/pat-tuple-underfield.rs:39:9
102+
|
103+
LL | S(i32, f32),
104+
| ----------- tuple variant defined here
105+
...
106+
LL | E::S() => {}
107+
| ^^^^^^ expected 2 fields, found 0
108+
|
109+
help: use `_` to explicitly ignore each field
110+
|
111+
LL | E::S(_, _) => {}
112+
| ^^^^
113+
help: use `..` to ignore all unmentioned fields
114+
|
115+
LL | E::S(..) => {}
116+
| ^^
117+
118+
error: aborting due to 7 previous errors
119+
120+
Some errors have detailed explanations: E0023, E0532.
121+
For more information about an error, try `rustc --explain E0023`.

0 commit comments

Comments
 (0)