### Constructor grouping and splitting
The pattern-only constructors (`_`, ranges and variable-length slices) each stand for a set of
normal constructors, e.g. `_: Option<T>` stands for the set {`None`, `Some`} and `[_, .., _]` stands
for the infinite set {`[,]`, `[,,]`, `[,,,]`, ...} of the slice constructors of arity >= 2.
In order to manage these constructors, we keep them as grouped as possible. For example:
```rust
match (0, false) {
(0 ..=100, true) => {}
(50..=150, false) => {}
(0 ..=200, _) => {}
}
```
In this example, all of `0`, `1`, .., `49` match the same arms, and thus can be treated as a group.
In fact, in this match, the only ranges we need to consider are: `0..50`, `50..=100`,
`101..=150`,`151..=200` and `201..`. Similarly:
```rust
enum Direction { North, South, East, West }
# let wind = (Direction::North, 0u8);
match wind {
(Direction::North, 50..) => {}
(_, _) => {}
}
```
Here we can treat all the non-`North` constructors as a group, giving us only two cases to handle:
`North`, and everything else.
This is called "constructor splitting" and is crucial to having exhaustiveness run in reasonable
time.
### Usefulness vs reachability in the presence of empty types
This is likely the subtlest aspect of exhaustiveness. To be fully precise, a match doesn't operate
on a value, it operates on a place. In certain unsafe circumstances, it is possible for a place to
not contain valid data for its type. This has subtle consequences for empty types. Take the
following:
```rust
enum Void {}
let x: u8 = 0;
let ptr: *const Void = &x as *const u8 as *const Void;
unsafe {
match *ptr {
_ => println!("Reachable!"),
}
}
```
In this example, `ptr` is a valid pointer pointing to a place with invalid data. The `_` pattern
does not look at the contents of the place `*ptr`, so this code is ok and the arm is taken. In other
words, despite the place we are inspecting being of type `Void`, there is a reachable arm. If the
arm had a binding however:
```rust
# #[derive(Copy, Clone)]
# enum Void {}
# let x: u8 = 0;
# let ptr: *const Void = &x as *const u8 as *const Void;
# unsafe {
match *ptr {
_a => println!("Unreachable!"),
}
# }
```
Here the binding loads the value of type `Void` from the `*ptr` place. In this example, this causes
UB since the data is not valid. In the general case, this asserts validity of the data at `*ptr`.
Either way, this arm will never be taken.
Finally, let's consider the empty match `match *ptr {}`. If we consider this exhaustive, then
having invalid data at `*ptr` is invalid. In other words, the empty match is semantically
equivalent to the `_a => ...` match. In the interest of explicitness, we prefer the case with an
arm, hence we won't tell the user to remove the `_a` arm. In other words, the `_a` arm is
unreachable yet not redundant. This is why we lint on redundant arms rather than unreachable
arms, despite the fact that the lint says "unreachable".
These considerations only affects certain places, namely those that can contain non-valid data
without UB. These are: pointer dereferences, reference dereferences, and union field accesses. We
track during exhaustiveness checking whether a given place is known to contain valid data.
Having said all that, the current implementation of exhaustiveness checking does not follow the
above considerations. On stable, empty types are for the most part treated as non-empty. The
[`exhaustive_patterns`] feature errs on the other end: it allows omitting arms that could be
reachable in unsafe situations. The [`never_patterns`] experimental feature aims to fix this and
permit the correct behavior of empty types in patterns.