|
1 | 1 | //! Note: tests specific to this file can be found in: |
2 | | -//! - ui/pattern/usefulness |
3 | | -//! - ui/or-patterns |
4 | | -//! - ui/consts/const_in_pattern |
5 | | -//! - ui/rfc-2008-non-exhaustive |
6 | | -//! - ui/half-open-range-patterns |
7 | | -//! - probably many others |
| 2 | +//! |
| 3 | +//! - `ui/pattern/usefulness` |
| 4 | +//! - `ui/or-patterns` |
| 5 | +//! - `ui/consts/const_in_pattern` |
| 6 | +//! - `ui/rfc-2008-non-exhaustive` |
| 7 | +//! - `ui/half-open-range-patterns` |
| 8 | +//! - probably many others |
| 9 | +//! |
8 | 10 | //! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific |
9 | | -//! reason not to, for example if they depend on a particular feature like or_patterns. |
| 11 | +//! reason not to, for example if they depend on a particular feature like `or_patterns`. |
| 12 | +//! |
| 13 | +//! ----- |
10 | 14 | //! |
11 | 15 | //! This file includes the logic for exhaustiveness and usefulness checking for |
12 | 16 | //! pattern-matching. Specifically, given a list of patterns for a type, we can |
13 | 17 | //! tell whether: |
14 | 18 | //! (a) the patterns cover every possible constructor for the type (exhaustiveness) |
15 | 19 | //! (b) each pattern is necessary (usefulness) |
16 | 20 | //! |
17 | | -//! The algorithm implemented here is a modified version of the one described in: |
18 | | -//! <http://moscova.inria.fr/~maranget/papers/warn/index.html> |
| 21 | +//! The algorithm implemented here is a modified version of the one described in |
| 22 | +//! [this paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). |
19 | 23 | //! However, to save future implementors from reading the original paper, we |
20 | 24 | //! summarise the algorithm here to hopefully save time and be a little clearer |
21 | 25 | //! (without being so rigorous). |
|
131 | 135 | //! |
132 | 136 | //! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` |
133 | 137 | //! on top of the stack, and we have four cases: |
134 | | -//! 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We |
135 | | -//! push onto the stack the arguments of this constructor, and return the result: |
136 | | -//! r_1, .., r_a, p_2, .., p_n |
137 | | -//! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and |
138 | | -//! return nothing. |
| 138 | +//! |
| 139 | +//! 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We |
| 140 | +//! push onto the stack the arguments of this constructor, and return the result: |
| 141 | +//! `r_1, .., r_a, p_2, .., p_n` |
| 142 | +//! |
| 143 | +//! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and |
| 144 | +//! return nothing. |
| 145 | +//! |
139 | 146 | //! 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has |
140 | 147 | //! arguments (its arity), and return the resulting stack: |
141 | | -//! _, .., _, p_2, .., p_n |
| 148 | +//! `_, .., _, p_2, .., p_n` |
| 149 | +//! |
142 | 150 | //! 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting |
143 | 151 | //! stack: |
144 | | -//! S(c, (r_1, p_2, .., p_n)) |
145 | | -//! S(c, (r_2, p_2, .., p_n)) |
| 152 | +//! - `S(c, (r_1, p_2, .., p_n))` |
| 153 | +//! - `S(c, (r_2, p_2, .., p_n))` |
146 | 154 | //! |
147 | 155 | //! 2. We can pop a wildcard off the top of the stack. This is called `S(_, p)`, where `p` is |
148 | 156 | //! a pattern-stack. Note: the paper calls this `D(p)`. |
|
157 | 165 | //! p_2, .., p_n |
158 | 166 | //! 2.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting |
159 | 167 | //! stack. |
160 | | -//! S(_, (r_1, p_2, .., p_n)) |
161 | | -//! S(_, (r_2, p_2, .., p_n)) |
| 168 | +//! - `S(_, (r_1, p_2, .., p_n))` |
| 169 | +//! - `S(_, (r_2, p_2, .., p_n))` |
162 | 170 | //! |
163 | 171 | //! Note that the OR-patterns are not always used directly in Rust, but are used to derive the |
164 | 172 | //! exhaustive integer matching rules, so they're written here for posterity. |
|
198 | 206 | //! ] |
199 | 207 | //! ``` |
200 | 208 | //! |
201 | | -//! and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only |
| 209 | +//! and `p` is `[Some(false), 0]`, then we don't care about row 2 since we know `p` only |
202 | 210 | //! matches values that row 2 doesn't. For row 1 however, we need to dig into the |
203 | 211 | //! arguments of `Some` to know whether some new value is covered. So we compute |
204 | 212 | //! `U([[true, _]], [false, 0])`. |
|
222 | 230 | //! ] |
223 | 231 | //! ``` |
224 | 232 | //! |
225 | | -//! and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we |
| 233 | +//! and `p` is `[_, false, _]`, the `Some` constructor doesn't appear in `P`. So if we |
226 | 234 | //! only had row 2, we'd know that `p` is useful. However row 1 starts with a |
227 | 235 | //! wildcard, so we need to check whether `U([[true, _]], [false, 1])`. |
228 | 236 | //! |
|
243 | 251 | //! ] |
244 | 252 | //! ``` |
245 | 253 | //! |
246 | | -//! and `p` is [_, false], both `None` and `Some` constructors appear in the first |
| 254 | +//! and `p` is `[_, false]`, both `None` and `Some` constructors appear in the first |
247 | 255 | //! components of `P`. We will therefore try popping both constructors in turn: we |
248 | 256 | //! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]], |
249 | 257 | //! [false])` for the `None` constructor. The first case returns true, so we know that |
|
294 | 302 | //! + If some constructors are missing from the matrix, it turns out we don't need to do |
295 | 303 | //! anything special (because we know none of the integers are actually wildcards: i.e., we |
296 | 304 | //! can't span wildcards using ranges). |
| 305 | +
|
297 | 306 | use self::Constructor::*; |
298 | 307 | use self::SliceKind::*; |
299 | 308 | use self::Usefulness::*; |
|
0 commit comments