Skip to content

Commit 084ca79

Browse files
committed
When finding a match expr with multiple arms that requires more, suggest it
Given ```rust match Some(42) { Some(0) => {} Some(1) => {} } ``` suggest ```rust match Some(42) { Some(0) => {} Some(1) => {} None | Some(_) => todo!(), } ```
1 parent 2383858 commit 084ca79

28 files changed

+263
-50
lines changed

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+15
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,21 @@ fn non_exhaustive_match<'p, 'tcx>(
604604
format!("{}{}{} => todo!()", comma, pre_indentation, pattern),
605605
));
606606
}
607+
[.., prev, last] if prev.span.ctxt() == last.span.ctxt() => {
608+
if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) {
609+
let comma =
610+
if matches!(last.body.kind, hir::ExprKind::Block(..)) { "" } else { "," };
611+
suggestion = Some((
612+
last.span.shrink_to_hi(),
613+
format!(
614+
"{}{}{} => todo!()",
615+
comma,
616+
snippet.strip_prefix(",").unwrap_or(&snippet),
617+
pattern
618+
),
619+
));
620+
}
621+
}
607622
_ => {}
608623
}
609624

src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ LL | let _e = || { match e2 { E2::A => (), E2::B => () } };
3737
| ^^ pattern `_` not covered
3838
|
3939
= note: the matched value is of type `E2`, which is marked as non-exhaustive
40-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
40+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
41+
|
42+
LL | let _e = || { match e2 { E2::A => (), E2::B => (), _ => todo!() } };
43+
| ++++++++++++++
4144

4245
error[E0505]: cannot move out of `e3` because it is borrowed
4346
--> $DIR/non-exhaustive-match.rs:46:22

src/test/ui/match/match_non_exhaustive.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ LL | match e2 { E2::A => (), E2::B => () };
3737
| ^^ pattern `_` not covered
3838
|
3939
= note: the matched value is of type `E2`, which is marked as non-exhaustive
40-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
40+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
41+
|
42+
LL | match e2 { E2::A => (), E2::B => (), _ => todo!() };
43+
| ++++++++++++++
4144

4245
error: aborting due to 3 previous errors
4346

src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr

+15-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ LL | match Foo::A {
55
| ^^^^^^ pattern `_` not covered
66
|
77
= note: the matched value is of type `Foo`
8-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
8+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
9+
|
10+
LL ~ Foo::B => {}
11+
LL + _ => todo!()
12+
|
913

1014
error[E0004]: non-exhaustive patterns: `B` not covered
1115
--> $DIR/doc-hidden-non-exhaustive.rs:14:11
@@ -19,7 +23,11 @@ LL | B,
1923
| - not covered
2024
|
2125
= note: the matched value is of type `Foo`
22-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
26+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
27+
|
28+
LL ~ Foo::C => {}
29+
LL + B => todo!()
30+
|
2331

2432
error[E0004]: non-exhaustive patterns: `B` and `_` not covered
2533
--> $DIR/doc-hidden-non-exhaustive.rs:20:11
@@ -51,7 +59,11 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
5159
| ---- not covered
5260
|
5361
= note: the matched value is of type `Option<Foo>`
54-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
62+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
63+
|
64+
LL ~ Some(Foo::A) => {}
65+
LL + Some(B) | Some(_) => todo!()
66+
|
5567

5668
error: aborting due to 4 previous errors
5769

src/test/ui/pattern/usefulness/guards.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ LL | match 0u8 {
55
| ^^^ pattern `128_u8..=u8::MAX` not covered
66
|
77
= note: the matched value is of type `u8`
8-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
8+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
9+
|
10+
LL ~ 128 ..= 255 if true => {}
11+
LL + 128_u8..=u8::MAX => todo!()
12+
|
913

1014
error: aborting due to previous error
1115

src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr

+10-2
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,11 @@ LL | match 0i8 {
9696
| ^^^ pattern `0_i8` not covered
9797
|
9898
= note: the matched value is of type `i8`
99-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
99+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
100+
|
101+
LL ~ 1 ..= i8::MAX => {}
102+
LL + 0_i8 => todo!()
103+
|
100104

101105
error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
102106
--> $DIR/exhaustiveness.rs:59:8
@@ -144,7 +148,11 @@ LL | match (0u8, true) {
144148
| ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
145149
|
146150
= note: the matched value is of type `(u8, bool)`
147-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
151+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
152+
|
153+
LL ~ (0 ..= 255, true) => {}
154+
LL + (126_u8..=127_u8, false) => todo!()
155+
|
148156

149157
error: aborting due to 12 previous errors
150158

src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,11 @@ LL | match 0isize {
153153
= note: the matched value is of type `isize`
154154
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
155155
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
156-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
156+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
157+
|
158+
LL ~ 1 ..= isize::MAX => {}
159+
LL + _ => todo!()
160+
|
157161

158162
error[E0004]: non-exhaustive patterns: type `usize` is non-empty
159163
--> $DIR/pointer-sized-int.rs:48:11

src/test/ui/pattern/usefulness/issue-15129.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ LL | match (T::T1(()), V::V2(true)) {
55
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
66
|
77
= note: the matched value is of type `(T, V)`
8-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
8+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
9+
|
10+
LL ~ (T::T2(()), V::V2(b)) => (),
11+
LL ~ (T1(()), V2(_)) | (T2(()), V1(_)) => todo!(),
12+
|
913

1014
error: aborting due to previous error
1115

src/test/ui/pattern/usefulness/issue-2111.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ LL | match (a, b) {
55
| ^^^^^^ patterns `(None, None)` and `(Some(_), Some(_))` not covered
66
|
77
= note: the matched value is of type `(Option<usize>, Option<usize>)`
8-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
8+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
9+
|
10+
LL ~ (Some(_), None) | (None, Some(_)) => {}
11+
LL + (None, None) | (Some(_), Some(_)) => todo!()
12+
|
913

1014
error: aborting due to previous error
1115

src/test/ui/pattern/usefulness/issue-30240.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ LL | match "world" {
1818
| ^^^^^^^ pattern `&_` not covered
1919
|
2020
= note: the matched value is of type `&str`
21-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
21+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
22+
|
23+
LL ~ "hello" => {}
24+
LL + &_ => todo!()
25+
|
2226

2327
error: aborting due to 2 previous errors
2428

src/test/ui/pattern/usefulness/issue-35609.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,11 @@ LL | match Some(A) {
102102
| ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
103103
|
104104
= note: the matched value is of type `Option<Enum>`
105-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
105+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
106+
|
107+
LL ~ None => (),
108+
LL + _ => todo!()
109+
|
106110

107111
error: aborting due to 8 previous errors
108112

src/test/ui/pattern/usefulness/issue-39362.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ LL | match f {
1010
| ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
1111
|
1212
= note: the matched value is of type `Foo`
13-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
13+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
14+
|
15+
LL ~ Foo::Bar { bar: Bar::B, .. } => (),
16+
LL ~ _ => todo!(),
17+
|
1418

1519
error: aborting due to previous error
1620

src/test/ui/pattern/usefulness/issue-4321.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ LL | println!("foo {:}", match tup {
55
| ^^^ pattern `(true, false)` not covered
66
|
77
= note: the matched value is of type `(bool, bool)`
8-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
8+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
9+
|
10+
LL ~ (true, true) => "baz",
11+
LL + (true, false) => todo!()
12+
|
913

1014
error: aborting due to previous error
1115

src/test/ui/pattern/usefulness/issue-56379.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ LL | match Foo::A(true) {
1515
| ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
1616
|
1717
= note: the matched value is of type `Foo`
18-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
18+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
19+
|
20+
LL ~ Foo::C(true) => {}
21+
LL + A(false) | B(false) | C(false) => todo!()
22+
|
1923

2024
error: aborting due to previous error
2125

src/test/ui/pattern/usefulness/issue-72377.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ LL | match (x, y) {
55
| ^^^^^^ patterns `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 more not covered
66
|
77
= note: the matched value is of type `(X, Option<X>)`
8-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
8+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
9+
|
10+
LL ~ (X::A, Some(X::C)) | (X::C, Some(X::A)) => false,
11+
LL ~ _ => todo!(),
12+
|
913

1014
error: aborting due to previous error
1115

src/test/ui/pattern/usefulness/match-arm-statics-2.stderr

+15-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ LL | match (true, false) {
55
| ^^^^^^^^^^^^^ pattern `(true, false)` not covered
66
|
77
= note: the matched value is of type `(bool, bool)`
8-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
8+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
9+
|
10+
LL ~ (false, true) => (),
11+
LL + (true, false) => todo!()
12+
|
913

1014
error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered
1115
--> $DIR/match-arm-statics-2.rs:29:11
@@ -22,7 +26,11 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
2226
| not covered
2327
|
2428
= note: the matched value is of type `Option<Option<Direction>>`
25-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
29+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
30+
|
31+
LL ~ None => (),
32+
LL + Some(Some(West)) => todo!()
33+
|
2634

2735
error[E0004]: non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` not covered
2836
--> $DIR/match-arm-statics-2.rs:48:11
@@ -37,7 +45,11 @@ LL | match (Foo { bar: Some(North), baz: NewBool(true) }) {
3745
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered
3846
|
3947
= note: the matched value is of type `Foo`
40-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
48+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
49+
|
50+
LL ~ Foo { bar: Some(EAST), .. } => (),
51+
LL + Foo { bar: Some(North), baz: NewBool(true) } => todo!()
52+
|
4153

4254
error: aborting due to 3 previous errors
4355

src/test/ui/pattern/usefulness/match-privately-empty.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
1010
| ---- not covered
1111
|
1212
= note: the matched value is of type `Option<Private>`
13-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
13+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
14+
|
15+
LL ~ }) => {}
16+
LL + Some(Private { misc: true, .. }) => todo!()
17+
|
1418

1519
error: aborting due to previous error
1620

src/test/ui/pattern/usefulness/match-slice-patterns.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ LL | match list {
55
| ^^^^ pattern `&[_, Some(_), .., None, _]` not covered
66
|
77
= note: the matched value is of type `&[Option<()>]`
8-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
8+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
9+
|
10+
LL ~ &[.., Some(_), _] => {}
11+
LL ~ &[_, Some(_), .., None, _] => todo!(),
12+
|
913

1014
error: aborting due to previous error
1115

src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr

+10-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ LL | match (l1, l2) {
55
| ^^^^^^^^ pattern `(Some(&[]), Err(_))` not covered
66
|
77
= note: the matched value is of type `(Option<&[T]>, Result<&[T], ()>)`
8-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
8+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
9+
|
10+
LL ~ (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)",
11+
LL + (Some(&[]), Err(_)) => todo!()
12+
|
913

1014
error[E0004]: non-exhaustive patterns: `A(C)` not covered
1115
--> $DIR/non-exhaustive-match-nested.rs:15:11
@@ -20,7 +24,11 @@ LL | match x {
2024
| ^ pattern `A(C)` not covered
2125
|
2226
= note: the matched value is of type `T`
23-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
27+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
28+
|
29+
LL ~ T::B => { panic!("goodbye"); }
30+
LL + A(C) => todo!()
31+
|
2432

2533
error: aborting due to 2 previous errors
2634

src/test/ui/pattern/usefulness/non-exhaustive-match.stderr

+15-3
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,11 @@ LL | match (T::A, T::A) {
6767
| ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered
6868
|
6969
= note: the matched value is of type `(T, T)`
70-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
70+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
71+
|
72+
LL ~ (T::B, T::A) => {}
73+
LL + (A, A) | (B, B) => todo!()
74+
|
7175

7276
error[E0004]: non-exhaustive patterns: `B` not covered
7377
--> $DIR/non-exhaustive-match.rs:22:11
@@ -95,7 +99,11 @@ LL | match *vec {
9599
| ^^^^ pattern `[]` not covered
96100
|
97101
= note: the matched value is of type `[Option<isize>]`
98-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
102+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
103+
|
104+
LL ~ [None] => {}
105+
LL + [] => todo!()
106+
|
99107

100108
error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
101109
--> $DIR/non-exhaustive-match.rs:46:11
@@ -104,7 +112,11 @@ LL | match *vec {
104112
| ^^^^ pattern `[_, _, _, _, ..]` not covered
105113
|
106114
= note: the matched value is of type `[f32]`
107-
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
115+
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
116+
|
117+
LL ~ [] => (),
118+
LL + [_, _, _, _, ..] => todo!()
119+
|
108120

109121
error: aborting due to 8 previous errors
110122

0 commit comments

Comments
 (0)