rust/compiler
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
..
rustc The rustc crate feature is called jemalloc 2024-07-15 13:01:20 -04:00
rustc_abi interpret: simplify pointer arithmetic logic 2024-08-01 14:25:19 +02:00
rustc_arena Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_ast Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_ast_ir
rustc_ast_lowering minor effects cleanups 2024-07-31 03:29:10 +00:00
rustc_ast_passes Rollup merge of #127921 - spastorino:stabilize-unsafe-extern-blocks, r=compiler-errors 2024-08-03 20:51:51 +02:00
rustc_ast_pretty Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_attr Rollup merge of #128341 - Alexendoo:parse-version-pub, r=compiler-errors 2024-07-29 17:46:44 +02:00
rustc_baked_icu_data
rustc_borrowck use stable sort to sort multipart diagnostics 2024-08-09 09:45:01 +02:00
rustc_builtin_macros Make Span optional in BufferedEarlyLint 2024-08-07 14:08:34 +02:00
rustc_codegen_cranelift Fixes in various places 2024-08-10 12:08:46 +02:00
rustc_codegen_gcc Fixes in various places 2024-08-10 12:08:46 +02:00
rustc_codegen_llvm Rename struct_tail_erasing_lifetimes to struct_tail_for_codegen 2024-08-08 12:15:16 -04:00
rustc_codegen_ssa Rename struct_tail_erasing_lifetimes to struct_tail_for_codegen 2024-08-08 12:15:16 -04:00
rustc_const_eval Rename struct_tail_erasing_lifetimes to struct_tail_for_codegen 2024-08-08 12:15:16 -04:00
rustc_data_structures Tweak wording 2024-08-08 21:51:50 +02:00
rustc_driver
rustc_driver_impl Add -Zerror-metrics=PATH to save diagnostic metadata to disk 2024-08-07 11:16:55 -07:00
rustc_error_codes Update E0517 message to reflect RFC 2195. 2024-08-07 23:11:30 -05:00
rustc_error_messages Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_errors Update std and compiler 2024-08-10 12:07:17 +02:00
rustc_expand refactor(rustc_expand::mbe): Don't require full ExtCtxt when not necessary 2024-08-07 21:58:05 +02:00
rustc_feature Stabilize min_exhaustive_patterns 2024-08-10 12:07:17 +02:00
rustc_fluent_macro Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_fs_util Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_graphviz Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_hir Rollup merge of #128377 - veera-sivarajan:fix-128249, r=davidtwco 2024-08-06 20:23:39 +02:00
rustc_hir_analysis Auto merge of #128746 - compiler-errors:cache-super-outlives, r=lcnr 2024-08-10 10:22:06 +00:00
rustc_hir_pretty Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_hir_typeck Auto merge of #128714 - camelid:wf-struct-exprs, r=BoxyUwU 2024-08-10 05:27:17 +00:00
rustc_incremental Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_index Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_index_macros
rustc_infer Use Vec in instantiate_binder_with_fresh_vars 2024-07-29 14:38:33 +03:00
rustc_interface Rollup merge of #128851 - compiler-errors:validate-mir-opt-mir, r=matthiaskrgr 2024-08-09 00:03:39 +02:00
rustc_lexer Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_lint Auto merge of #128796 - matthiaskrgr:rollup-r7l68ph, r=matthiaskrgr 2024-08-07 20:00:29 +00:00
rustc_lint_defs Disallow setting built-in cfgs via set the command-line 2024-08-07 14:08:34 +02:00
rustc_llvm Enable zstd for debug compression. 2024-08-09 05:55:23 -07:00
rustc_log Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_macros Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_metadata Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_middle Auto merge of #122792 - Nadrieril:stabilize-min-exh-pats2, r=fee1-dead 2024-08-10 12:48:29 +00:00
rustc_mir_build Stabilize min_exhaustive_patterns 2024-08-10 12:07:17 +02:00
rustc_mir_dataflow Stop using MoveDataParamEnv for places that don't need a param-env 2024-07-29 11:59:47 -04:00
rustc_mir_transform Don't inline tainted MIR bodies 2024-08-08 20:53:25 -04:00
rustc_monomorphize Rename struct_tail_erasing_lifetimes to struct_tail_for_codegen 2024-08-08 12:15:16 -04:00
rustc_next_trait_solver Don't implement AsyncFn for FnDef/FnPtr that wouldnt implement Fn 2024-08-08 14:07:31 -04:00
rustc_parse parser: ensure let stmt compound assignment removal suggestion respect codepoint boundaries 2024-08-09 05:56:50 +00:00
rustc_parse_format Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_passes Rollup merge of #128552 - s7tya:check-no-sanitize-attribute-pos, r=BoxyUwU 2024-08-07 20:49:02 -05:00
rustc_pattern_analysis Stabilize min_exhaustive_patterns 2024-08-10 12:07:17 +02:00
rustc_privacy Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_query_impl Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_query_system chore: use shorthand initializer 2024-08-02 13:22:28 -04:00
rustc_resolve rm declared_features field in resolver 2024-08-08 20:30:20 +08:00
rustc_sanitizers Use ParamEnv::reveal_all in CFI 2024-08-02 23:24:50 -04:00
rustc_serialize Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_session Rollup merge of #128806 - estebank:color-config, r=jieyouxu 2024-08-09 00:03:36 +02:00
rustc_smir Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_span Rollup merge of #125048 - dingxiangfei2009:stable-deref, r=amanieu 2024-08-07 00:34:11 +02:00
rustc_symbol_mangling Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_target Update std and compiler 2024-08-10 12:07:17 +02:00
rustc_trait_selection Auto merge of #128746 - compiler-errors:cache-super-outlives, r=lcnr 2024-08-10 10:22:06 +00:00
rustc_traits Reformat use declarations. 2024-07-29 08:26:52 +10:00
rustc_transmute Update std and compiler 2024-08-10 12:07:17 +02:00
rustc_ty_utils Rename struct_tail_erasing_lifetimes to struct_tail_for_codegen 2024-08-08 12:15:16 -04:00
rustc_type_ir Update std and compiler 2024-08-10 12:07:17 +02:00
rustc_type_ir_macros Reformat use declarations. 2024-07-29 08:26:52 +10:00
stable_mir Reformat use declarations. 2024-07-29 08:26:52 +10:00