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
This commit is contained in:
commit
8291d68d92
100 changed files with 1131 additions and 1005 deletions
|
@ -28,6 +28,7 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(allocator_api)]
|
||||
|
@ -48,7 +49,6 @@
|
|||
#![feature(iter_from_coroutine)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(macro_metavar_expr)]
|
||||
#![feature(min_exhaustive_patterns)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(never_type)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue