rust/compiler/rustc_middle/src
bors 8291d68d92 Auto merge of #122792 - Nadrieril:stabilize-min-exh-pats2, r=fee1-dead
Stabilize `min_exhaustive_patterns`

## Stabilisation report

I propose we stabilize the [`min_exhaustive_patterns`](https://github.com/rust-lang/rust/issues/119612) language feature.

With this feature, patterns of empty types are considered unreachable when matched by-value. This allows:
```rust
enum Void {}
fn foo() -> Result<u32, Void>;

fn main() {
  let Ok(x) = foo();
  // also
  match foo() {
    Ok(x) => ...,
  }
}
```

This is a subset of the long-unstable [`exhaustive_patterns`](https://github.com/rust-lang/rust/issues/51085) feature. That feature is blocked because omitting empty patterns is tricky when *not* matched by-value. This PR stabilizes the by-value case, which is not tricky.

The not-by-value cases (behind references, pointers, and unions) stay as they are today, e.g.
```rust
enum Void {}
fn foo() -> Result<u32, &Void>;

fn main() {
  let Ok(x) = foo(); // ERROR: missing `Err(_)`
}
```

The consequence on existing code is some extra "unreachable pattern" warnings. This is fully backwards-compatible.

### Comparison with today's rust

This proposal only affects match checking of empty types (i.e. types with no valid values). Non-empty types behave the same with or without this feature. Note that everything below is phrased in terms of `match` but applies equallly to `if let` and other pattern-matching expressions.

To be precise, a visibly empty type is:
- an enum with no variants;
- the never type `!`;
- a struct with a *visible* field of a visibly empty type (and no #[non_exhaustive] annotation);
- a tuple where one of the types is visibly empty;
- en enum with all variants visibly empty (and no `#[non_exhaustive]` annotation);
- a `[T; N]` with `N != 0` and `T` visibly empty;
- all other types are nonempty.

(An extra change was proposed below: that we ignore #[non_exhaustive] for structs since adding fields cannot turn an empty struct into a non-empty one)

For normal types, exhaustiveness checking requires that we list all variants (or use a wildcard). For empty types it's more subtle: in some cases we require a `_` pattern even though there are no valid values that can match it. This is where the difference lies regarding this feature.

#### Today's rust

Under today's rust, a `_` is required for all empty types, except specifically: if the matched expression is of type `!` (the never type) or `EmptyEnum` (where `EmptyEnum` is an enum with no variants), then the `_` is not required.

```rust
let foo: Result<u32, !> = ...;
match foo {
    Ok(x) => ...,
    Err(_) => ..., // required
}
let foo: Result<u32, &!> = ...;
match foo {
    Ok(x) => ...,
    Err(_) => ..., // required
}
let foo: &! = ...;
match foo {
    _ => ..., // required
}
fn blah(foo: (u32, !)) {
    match foo {
        _ => ..., // required
    }
}
unsafe {
    let ptr: *const ! = ...;
    match *ptr {} // allowed
    let ptr: *const (u32, !) = ...;
    match *ptr {
        (x, _) => { ... } // required
    }
    let ptr: *const Result<u32, !> = ...;
    match *ptr {
        Ok(x) => { ... }
        Err(_) => { ... } // required
    }
}
```

#### After this PR

After this PR, a pattern of an empty type can be omitted if (and only if):
- the match scrutinee expression has type  `!` or `EmptyEnum` (like before);
- *or* the empty type is matched by value (that's the new behavior).

In all other cases, a `_` is required to match on an empty type.

```rust
let foo: Result<u32, !> = ...;
match foo {
    Ok(x) => ..., // `Err` not required
}
let foo: Result<u32, &!> = ...;
match foo {
    Ok(x) => ...,
    Err(_) => ..., // required because `!` is under a dereference
}
let foo: &! = ...;
match foo {
    _ => ..., // required because `!` is under a dereference
}
fn blah(foo: (u32, !)) {
    match foo {} // allowed
}
unsafe {
    let ptr: *const ! = ...;
    match *ptr {} // allowed
    let ptr: *const (u32, !) = ...;
    match *ptr {
        (x, _) => { ... } // required because the matched place is under a (pointer) dereference
    }
    let ptr: *const Result<u32, !> = ...;
    match *ptr {
        Ok(x) => { ... }
        Err(_) => { ... } // required because the matched place is under a (pointer) dereference
    }
}
```

### Documentation

The reference does not say anything specific about exhaustiveness checking, hence there is nothing to update there. The nomicon does, I opened https://github.com/rust-lang/nomicon/pull/445 to reflect the changes.

### Tests

The relevant tests are in `tests/ui/pattern/usefulness/empty-types.rs`.

### Unresolved Questions

None that I know of.

try-job: dist-aarch64-apple
2024-08-10 12:48:29 +00:00
..
dep_graph Reformat use declarations. 2024-07-29 08:26:52 +10:00
hir Delegation: second attempt to improve perf 2024-07-31 18:58:04 +03:00
hooks Reformat use declarations. 2024-07-29 08:26:52 +10:00
infer Reformat use declarations. 2024-07-29 08:26:52 +10:00
middle Hide implicit target features from diagnostics when possible 2024-08-07 00:43:52 -04:00
mir Rollup merge of #128494 - RalfJung:mir-lazy-lists, r=compiler-errors 2024-08-02 06:43:44 +02:00
query Auto merge of #128746 - compiler-errors:cache-super-outlives, r=lcnr 2024-08-10 10:22:06 +00:00
thir Track mutability of deref patterns 2024-04-20 15:59:54 +02:00
traits Reformat use declarations. 2024-07-29 08:26:52 +10:00
ty Auto merge of #128740 - compiler-errors:generic-preds, r=estebank 2024-08-10 07:54:26 +00:00
util Reformat use declarations. 2024-07-29 08:26:52 +10:00
arena.rs Uplift PredefinedOpaquesData 2024-06-18 10:40:30 -04:00
error.rs Reformat use declarations. 2024-07-29 08:26:52 +10:00
lib.rs Update std and compiler 2024-08-10 12:07:17 +02:00
lint.rs Only suggest #[allow] for --warn and --deny lint level flags 2024-08-08 13:09:58 +00:00
macros.rs lift_to_tcx -> lift_to_interner 2024-07-17 10:46:10 -04:00
metadata.rs Reformat use declarations. 2024-07-29 08:26:52 +10:00
tests.rs Give an item related to issue 27438 a more meaningful name 2024-04-30 22:27:19 +02:00
thir.rs Use a separate pattern type for rustc_pattern_analysis diagnostics 2024-07-31 16:03:27 +10:00
values.rs Reformat use declarations. 2024-07-29 08:26:52 +10:00