Skip to content

Commit ada57a3

Browse files
NadrierilJoshua Nelson
authored andcommitted
Explain pattern exhaustiveness checking
1 parent 7f9c36b commit ada57a3

File tree

1 file changed

+81
-1
lines changed

1 file changed

+81
-1
lines changed

src/pat-exhaustive-checking.md

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,84 @@ In Rust, pattern matching and bindings have a few very helpful properties. The
44
compiler will check that bindings are irrefutable when made and that match arms
55
are exhaustive.
66

7-
**TODO**: write this chapter.
7+
## Pattern usefulness
8+
9+
The central question that usefulness checking answers is:
10+
"in this match expression, is that branch reachable?".
11+
More precisely, it boils down to computing whether,
12+
given a list of patterns we have already seen,
13+
a given new pattern might match any new value.
14+
15+
For example, in the following match expression,
16+
we ask in turn whether each pattern might match something
17+
that wasn't matched by the patterns above it.
18+
Here we see the 4th pattern is redundant with the 1st;
19+
that branch will get an "unreachable" warning.
20+
The 3rd pattern may or may not be useful,
21+
depending on whether `Foo` has other variants than `Bar`.
22+
Finally, we can ask whether the whole match is exhaustive
23+
by asking whether the wildcard pattern (`_`)
24+
is useful relative to the list of all the patterns in that match.
25+
Here we can see that `_` is useful (it would catch `(false, None)`);
26+
this expression would therefore get a "non-exhaustive match" error.
27+
28+
```rust
29+
// x: (bool, Option<Foo>)
30+
match x {
31+
(true, _) => {} // 1
32+
(false, Some(Foo::Bar)) => {} // 2
33+
(false, Some(_)) => {} // 3
34+
(true, None) => {} // 4
35+
}
36+
```
37+
38+
Thus usefulness is used for two purposes:
39+
detecting unreachable code (which is useful to the user),
40+
and ensuring that matches are exhaustive (which is important for soundness).
41+
42+
## Where it happens
43+
44+
This check is done to any expression that desugars to a match expression in MIR.
45+
That includes actual `match` expressions,
46+
but also anything that looks like pattern matching,
47+
including `if let`, destructuring `let`, and similar expressions.
48+
49+
```rust
50+
// `match`
51+
// Usefulness can detect unreachable branches and forbid non-exhaustive matches.
52+
match foo() {
53+
Ok(x) => x,
54+
Err(_) => panic!(),
55+
}
56+
57+
// `if let`
58+
// Usefulness can detect unreachable branches.
59+
if let Some(x) = foo() {
60+
// ...
61+
}
62+
63+
// `while let`
64+
// Usefulness can detect infinite loops and dead loops.
65+
while let Some(x) = it.next() {
66+
// ...
67+
}
68+
69+
// Destructuring `let`
70+
// Usefulness can forbid non-exhaustive patterns.
71+
let Foo::Bar(x, y) = foo();
72+
73+
// Destructuring function arguments
74+
// Usefulness can forbid non-exhaustive patterns.
75+
fn foo(Foo { x, y }: Foo) {
76+
// ...
77+
}
78+
```
79+
80+
## The algorithm
81+
82+
Exhaustiveness checking is implemented in [check_match].
83+
The core of the algorithm is in [_match].
84+
That file contains a detailed description of the algorithm.
85+
86+
[check_match]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/thir/pattern/check_match/index.html
87+
[_match]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/thir/pattern/_match/index.html

0 commit comments

Comments
 (0)