|
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