11# Pattern and exhaustiveness checking
22
3- In Rust, pattern matching and bindings have a few very helpful properties. The
4- compiler will check that bindings are irrefutable when made and that match arms
3+ In Rust, pattern matching and bindings have a few very helpful properties.
4+ The compiler will check that bindings are irrefutable when made and that match arms
55are exhaustive.
66
77## Pattern usefulness
@@ -35,8 +35,7 @@ match x {
3535}
3636```
3737
38- Thus usefulness is used for two purposes:
39- detecting unreachable code (which is useful to the user),
38+ Thus usefulness is used for two purposes: detecting unreachable code (which is useful to the user),
4039and ensuring that matches are exhaustive (which is important for soundness,
4140because a match expression can return a value).
4241
@@ -88,22 +87,26 @@ That file contains a detailed description of the algorithm.
8887### Constructors and fields
8988
9089In the value ` Pair(Some(0), true) ` , ` Pair ` is called the constructor of the value, and ` Some(0) ` and
91- ` true ` are its fields. Every matchable value can be decomposed in this way. Examples of
92- constructors are: ` Some ` , ` None ` , ` (,) ` (the 2-tuple constructor), ` Foo {..} ` (the constructor for
93- a struct ` Foo ` ), and ` 2 ` (the constructor for the number ` 2 ` ).
94-
95- Each constructor takes a fixed number of fields; this is called its arity. ` Pair ` and ` (,) ` have
96- arity 2, ` Some ` has arity 1, ` None ` and ` 42 ` have arity 0. Each type has a known set of
97- constructors. Some types have many constructors (like ` u64 ` ) or even an infinitely many (like ` &str `
98- and ` &[T] ` ).
99-
100- Patterns are similar: ` Pair(Some(_), _) ` has constructor ` Pair ` and two fields. The difference is
101- that we get some extra pattern-only constructors, namely: the wildcard ` _ ` , variable bindings,
102- integer ranges like ` 0..=10 ` , and variable-length slices like ` [_, .., _] ` . We treat or-patterns
103- separately.
90+ ` true ` are its fields.
91+ Every matchable value can be decomposed in this way.
92+ Examples of constructors are:
93+ ` Some ` , ` None ` , ` (,) ` (the 2-tuple constructor), ` Foo {..} ` (the constructor for a struct ` Foo ` ),
94+ and ` 2 ` (the constructor for the number ` 2 ` ).
95+
96+ Each constructor takes a fixed number of fields; this is called its arity.
97+ ` Pair ` and ` (,) ` have arity 2, ` Some ` has arity 1, ` None ` and ` 42 ` have arity 0.
98+ Each type has a known set of constructors.
99+ Some types have many constructors (like ` u64 ` ) or even an infinitely many (like ` &str ` and ` &[T] ` ).
100+
101+ Patterns are similar: ` Pair(Some(_), _) ` has constructor ` Pair ` and two fields.
102+ The difference is that we get some extra pattern-only constructors, namely:
103+ the wildcard ` _ ` , variable bindings,
104+ integer ranges like ` 0..=10 ` , and variable-length slices like ` [_, .., _] ` .
105+ We treat or-patterns separately.
104106
105107Now to check if a value ` v ` matches a pattern ` p ` , we check if ` v ` 's constructor matches ` p ` 's
106- constructor, then recursively compare their fields if necessary. A few representative examples:
108+ constructor, then recursively compare their fields if necessary.
109+ A few representative examples:
107110
108111- ` matches!(v, _) := true `
109112- ` matches!((v0, v1), (p0, p1)) := matches!(v0, p0) && matches!(v1, p1) `
@@ -114,8 +117,9 @@ constructor, then recursively compare their fields if necessary. A few represent
114117- ` matches!([v0], [p0, .., p1]) := false ` (incompatible lengths)
115118- ` matches!([v0, v1, v2], [p0, .., p1]) := matches!(v0, p0) && matches!(v2, p1) `
116119
117- This concept is absolutely central to pattern analysis. The [ ` constructor ` ] module provides
118- functions to extract, list and manipulate constructors. This is a useful enough concept that
120+ This concept is absolutely central to pattern analysis.
121+ The [ ` constructor ` ] module provides functions to extract, list, and manipulate constructors.
122+ This is a useful enough concept that
119123variations of it can be found in other places of the compiler, like in the MIR-lowering of a match
120124expression and in some clippy lints.
121125
@@ -125,7 +129,8 @@ The pattern-only constructors (`_`, ranges and variable-length slices) each stan
125129normal constructors, e.g. ` _: Option<T> ` stands for the set {` None ` , ` Some ` } and ` [_, .., _] ` stands
126130for the infinite set {` [,] ` , ` [,,] ` , ` [,,,] ` , ...} of the slice constructors of arity >= 2.
127131
128- In order to manage these constructors, we keep them as grouped as possible. For example:
132+ In order to manage these constructors, we keep them as grouped as possible.
133+ For example:
129134
130135``` rust
131136match (0 , false ) {
@@ -137,7 +142,8 @@ match (0, false) {
137142
138143In this example, all of ` 0 ` , ` 1 ` , .., ` 49 ` match the same arms, and thus can be treated as a group.
139144In fact, in this match, the only ranges we need to consider are: ` 0..50 ` , ` 50..=100 ` ,
140- ` 101..=150 ` ,` 151..=200 ` and ` 201.. ` . Similarly:
145+ ` 101..=150 ` ,` 151..=200 ` and ` 201.. ` .
146+ Similarly:
141147
142148``` rust
143149enum Direction { North , South , East , West }
@@ -156,10 +162,11 @@ time.
156162
157163### Usefulness vs reachability in the presence of empty types
158164
159- This is likely the subtlest aspect of exhaustiveness. To be fully precise, a match doesn't operate
160- on a value, it operates on a place. In certain unsafe circumstances, it is possible for a place to
161- not contain valid data for its type. This has subtle consequences for empty types. Take the
162- following:
165+ This is likely the subtlest aspect of exhaustiveness.
166+ To be fully precise, a match doesn't operate on a value; it operates on a place.
167+ In certain unsafe circumstances, it is possible for a place to not contain valid data for its type.
168+ This has subtle consequences for empty types.
169+ Take the following:
163170
164171``` rust
165172enum Void {}
@@ -172,10 +179,11 @@ unsafe {
172179}
173180```
174181
175- In this example, ` ptr ` is a valid pointer pointing to a place with invalid data. The ` _ ` pattern
176- does not look at the contents of the place ` *ptr ` , so this code is ok and the arm is taken. In other
177- words, despite the place we are inspecting being of type ` Void ` , there is a reachable arm. If the
178- arm had a binding however:
182+ In this example, ` ptr ` is a valid pointer pointing to a place with invalid data.
183+ The ` _ ` pattern does not look at the contents of the place ` *ptr ` ,
184+ so this code is ok and the arm is taken.
185+ In other words, despite the place we are inspecting being of type ` Void ` , there is a reachable arm.
186+ If the arm had a binding however:
179187
180188``` rust
181189# #[derive(Copy , Clone )]
@@ -189,25 +197,31 @@ match *ptr {
189197# }
190198```
191199
192- Here the binding loads the value of type ` Void ` from the ` *ptr ` place. In this example, this causes
193- UB since the data is not valid. In the general case, this asserts validity of the data at ` *ptr ` .
200+ Here the binding loads the value of type ` Void ` from the ` *ptr ` place.
201+ In this example, this causes UB since the data is not valid.
202+ In the general case, this asserts validity of the data at ` *ptr ` .
194203Either way, this arm will never be taken.
195204
196- Finally, let's consider the empty match ` match *ptr {} ` . If we consider this exhaustive, then
197- having invalid data at ` *ptr ` is invalid. In other words, the empty match is semantically
198- equivalent to the ` _a => ... ` match. In the interest of explicitness, we prefer the case with an
199- arm, hence we won't tell the user to remove the ` _a ` arm. In other words, the ` _a ` arm is
200- unreachable yet not redundant. This is why we lint on redundant arms rather than unreachable
205+ Finally, let's consider the empty match ` match *ptr {} ` .
206+ If we consider this exhaustive, then having invalid data at ` *ptr ` is invalid.
207+ In other words, the empty match is semantically equivalent to the ` _a => ... ` match.
208+ In the interest of explicitness, we prefer the case with an
209+ arm, hence we won't tell the user to remove the ` _a ` arm.
210+ In other words, the ` _a ` arm is unreachable yet not redundant.
211+ This is why we lint on redundant arms rather than unreachable
201212arms, despite the fact that the lint says "unreachable".
202213
203214These considerations only affects certain places, namely those that can contain non-valid data
204- without UB. These are: pointer dereferences, reference dereferences, and union field accesses. We
205- track during exhaustiveness checking whether a given place is known to contain valid data.
215+ without UB.
216+ These are: pointer dereferences, reference dereferences, and union field accesses.
217+ We track during exhaustiveness checking whether a given place is known to contain valid data.
206218
207219Having said all that, the current implementation of exhaustiveness checking does not follow the
208- above considerations. On stable, empty types are for the most part treated as non-empty. The
209- [ ` exhaustive_patterns ` ] feature errs on the other end: it allows omitting arms that could be
210- reachable in unsafe situations. The [ ` never_patterns ` ] experimental feature aims to fix this and
220+ above considerations.
221+ On stable, empty types are for the most part treated as non-empty.
222+ The [ ` exhaustive_patterns ` ] feature errs on the other end: it allows omitting arms that could be
223+ reachable in unsafe situations.
224+ The [ ` never_patterns ` ] experimental feature aims to fix this and
211225permit the correct behavior of empty types in patterns.
212226
213227[ `check_match` ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/thir/pattern/check_match/index.html
0 commit comments