Skip to content

Commit 6334394

Browse files
committed
add exhaustiveness/usefulness tests for deref patterns
1 parent 17127b4 commit 6334394

File tree

6 files changed

+269
-0
lines changed

6 files changed

+269
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//! Test that the place behind a deref pattern is treated as maybe-invalid, and thus empty arms
2+
//! cannot be omitted. This is handled the same as for refs and union fields, so this leaves the
3+
//! bulk of the testing to `tests/ui/pattern/usefulness/empty-types.rs`.
4+
// FIXME(deref_patterns): On stabilization, cases for deref patterns could be worked into that file
5+
// to keep the tests for empty types in one place and test more thoroughly.
6+
#![feature(deref_patterns)]
7+
#![expect(incomplete_features)]
8+
#![deny(unreachable_patterns)]
9+
10+
enum Void {}
11+
12+
fn main() {
13+
// Sanity check: matching on an empty type without pointer indirection lets us omit arms.
14+
let opt_void: Option<Void> = None;
15+
match opt_void {
16+
None => {}
17+
}
18+
19+
// But if we hide it behind a smart pointer, we need an arm.
20+
let box_opt_void: Box<Option<Void>> = Box::new(None);
21+
match box_opt_void {
22+
//~^ ERROR non-exhaustive patterns: `deref!(Some(_))` not covered
23+
None => {}
24+
}
25+
match box_opt_void {
26+
None => {}
27+
Some(_) => {}
28+
}
29+
match box_opt_void {
30+
None => {}
31+
_ => {}
32+
}
33+
34+
// For consistency, this behaves the same as if we manually dereferenced the scrutinee.
35+
match *box_opt_void {
36+
//~^ ERROR non-exhaustive patterns: `Some(_)` not covered
37+
None => {}
38+
}
39+
match *box_opt_void {
40+
None => {}
41+
Some(_) => {}
42+
}
43+
match *box_opt_void {
44+
None => {}
45+
_ => {}
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error[E0004]: non-exhaustive patterns: `deref!(Some(_))` not covered
2+
--> $DIR/empty-types.rs:21:11
3+
|
4+
LL | match box_opt_void {
5+
| ^^^^^^^^^^^^ pattern `deref!(Some(_))` not covered
6+
|
7+
note: `Box<Option<Void>>` defined here
8+
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
9+
= note: the matched value is of type `Box<Option<Void>>`
10+
= note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
11+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
12+
|
13+
LL ~ None => {},
14+
LL + deref!(Some(_)) => todo!()
15+
|
16+
17+
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
18+
--> $DIR/empty-types.rs:35:11
19+
|
20+
LL | match *box_opt_void {
21+
| ^^^^^^^^^^^^^ pattern `Some(_)` not covered
22+
|
23+
note: `Option<Void>` defined here
24+
--> $SRC_DIR/core/src/option.rs:LL:COL
25+
::: $SRC_DIR/core/src/option.rs:LL:COL
26+
|
27+
= note: not covered
28+
= note: the matched value is of type `Option<Void>`
29+
= note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
30+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
31+
|
32+
LL ~ None => {},
33+
LL + Some(_) => todo!()
34+
|
35+
36+
error: aborting due to 2 previous errors
37+
38+
For more information about this error, try `rustc --explain E0004`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//! Test non-exhaustive matches involving deref patterns.
2+
#![feature(deref_patterns)]
3+
#![expect(incomplete_features)]
4+
#![deny(unreachable_patterns)]
5+
6+
fn main() {
7+
match Box::new(false) {
8+
//~^ ERROR non-exhaustive patterns: `deref!(true)` not covered
9+
false => {}
10+
}
11+
12+
match Box::new(Box::new(false)) {
13+
//~^ ERROR non-exhaustive patterns: `deref!(deref!(false))` not covered
14+
true => {}
15+
}
16+
17+
match Box::new((true, Box::new(false))) {
18+
//~^ ERROR non-exhaustive patterns: `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered
19+
(true, false) => {}
20+
(false, true) => {}
21+
}
22+
23+
enum T { A, B, C }
24+
match Box::new((Box::new(T::A), Box::new(T::A))) {
25+
//~^ ERROR non-exhaustive patterns: `deref!((deref!(T::C), _))` not covered
26+
(T::A | T::B, T::C) => {}
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
error[E0004]: non-exhaustive patterns: `deref!(true)` not covered
2+
--> $DIR/non-exhaustive.rs:7:11
3+
|
4+
LL | match Box::new(false) {
5+
| ^^^^^^^^^^^^^^^ pattern `deref!(true)` not covered
6+
|
7+
note: `Box<bool>` defined here
8+
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
9+
= note: the matched value is of type `Box<bool>`
10+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
11+
|
12+
LL ~ false => {},
13+
LL + deref!(true) => todo!()
14+
|
15+
16+
error[E0004]: non-exhaustive patterns: `deref!(deref!(false))` not covered
17+
--> $DIR/non-exhaustive.rs:12:11
18+
|
19+
LL | match Box::new(Box::new(false)) {
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `deref!(deref!(false))` not covered
21+
|
22+
note: `Box<Box<bool>>` defined here
23+
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
24+
= note: the matched value is of type `Box<Box<bool>>`
25+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
26+
|
27+
LL ~ true => {},
28+
LL + deref!(deref!(false)) => todo!()
29+
|
30+
31+
error[E0004]: non-exhaustive patterns: `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered
32+
--> $DIR/non-exhaustive.rs:17:11
33+
|
34+
LL | match Box::new((true, Box::new(false))) {
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ patterns `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered
36+
|
37+
note: `Box<(bool, Box<bool>)>` defined here
38+
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
39+
= note: the matched value is of type `Box<(bool, Box<bool>)>`
40+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
41+
|
42+
LL ~ (false, true) => {},
43+
LL + deref!((false, deref!(false))) | deref!((true, deref!(true))) => todo!()
44+
|
45+
46+
error[E0004]: non-exhaustive patterns: `deref!((deref!(T::C), _))` not covered
47+
--> $DIR/non-exhaustive.rs:24:11
48+
|
49+
LL | match Box::new((Box::new(T::A), Box::new(T::A))) {
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `deref!((deref!(T::C), _))` not covered
51+
|
52+
note: `Box<(Box<T>, Box<T>)>` defined here
53+
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
54+
= note: the matched value is of type `Box<(Box<T>, Box<T>)>`
55+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
56+
|
57+
LL ~ (T::A | T::B, T::C) => {},
58+
LL + deref!((deref!(T::C), _)) => todo!()
59+
|
60+
61+
error: aborting due to 4 previous errors
62+
63+
For more information about this error, try `rustc --explain E0004`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//! Test unreachable patterns involving deref patterns.
2+
#![feature(deref_patterns)]
3+
#![expect(incomplete_features)]
4+
#![deny(unreachable_patterns)]
5+
6+
fn main() {
7+
match Box::new(false) {
8+
true => {}
9+
false => {}
10+
false => {} //~ ERROR unreachable pattern
11+
}
12+
13+
match Box::new(Box::new(false)) {
14+
true => {}
15+
false => {}
16+
true => {} //~ ERROR unreachable pattern
17+
}
18+
19+
match Box::new((true, Box::new(false))) {
20+
(true, _) => {}
21+
(_, true) => {}
22+
(false, false) => {}
23+
_ => {} //~ ERROR unreachable pattern
24+
}
25+
26+
enum T { A, B, C }
27+
match Box::new((Box::new(T::A), Box::new(T::A))) {
28+
(T::A | T::B, T::A | T::C) => {}
29+
(T::A, T::C) => {} //~ ERROR unreachable pattern
30+
(T::B, T::A) => {} //~ ERROR unreachable pattern
31+
_ => {}
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
error: unreachable pattern
2+
--> $DIR/unreachable-patterns.rs:10:9
3+
|
4+
LL | false => {}
5+
| ----- matches all the relevant values
6+
LL | false => {}
7+
| ^^^^^ no value can reach this
8+
|
9+
note: the lint level is defined here
10+
--> $DIR/unreachable-patterns.rs:4:9
11+
|
12+
LL | #![deny(unreachable_patterns)]
13+
| ^^^^^^^^^^^^^^^^^^^^
14+
15+
error: unreachable pattern
16+
--> $DIR/unreachable-patterns.rs:16:9
17+
|
18+
LL | true => {}
19+
| ---- matches all the relevant values
20+
LL | false => {}
21+
LL | true => {}
22+
| ^^^^ no value can reach this
23+
24+
error: unreachable pattern
25+
--> $DIR/unreachable-patterns.rs:23:9
26+
|
27+
LL | _ => {}
28+
| ^ no value can reach this
29+
|
30+
note: multiple earlier patterns match some of the same values
31+
--> $DIR/unreachable-patterns.rs:23:9
32+
|
33+
LL | (true, _) => {}
34+
| --------- matches some of the same values
35+
LL | (_, true) => {}
36+
| --------- matches some of the same values
37+
LL | (false, false) => {}
38+
| -------------- matches some of the same values
39+
LL | _ => {}
40+
| ^ collectively making this unreachable
41+
42+
error: unreachable pattern
43+
--> $DIR/unreachable-patterns.rs:29:9
44+
|
45+
LL | (T::A | T::B, T::A | T::C) => {}
46+
| -------------------------- matches all the relevant values
47+
LL | (T::A, T::C) => {}
48+
| ^^^^^^^^^^^^ no value can reach this
49+
50+
error: unreachable pattern
51+
--> $DIR/unreachable-patterns.rs:30:9
52+
|
53+
LL | (T::A | T::B, T::A | T::C) => {}
54+
| -------------------------- matches all the relevant values
55+
LL | (T::A, T::C) => {}
56+
LL | (T::B, T::A) => {}
57+
| ^^^^^^^^^^^^ no value can reach this
58+
59+
error: aborting due to 5 previous errors
60+

0 commit comments

Comments
 (0)