Rollup merge of #118157 - Nadrieril:never_pat-feature-gate, r=compiler-errors

Add `never_patterns` feature gate

This PR adds the feature gate and most basic parsing for the experimental `never_patterns` feature. See the tracking issue (https://github.com/rust-lang/rust/issues/118155) for details on the experiment.

`@scottmcm` has agreed to be my lang-team liaison for this experiment.
This commit is contained in:
Matthias Krüger 2023-11-29 12:34:47 +01:00 committed by GitHub
commit c03f8917ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 325 additions and 18 deletions

View file

@ -0,0 +1,27 @@
// Check that never patterns require the feature gate.
use std::ptr::NonNull;
enum Void {}
fn main() {
let res: Result<u32, Void> = Ok(0);
let (Ok(_x) | Err(&!)) = res.as_ref();
//~^ ERROR `!` patterns are experimental
//~| ERROR: is not bound in all patterns
unsafe {
let ptr: *const Void = NonNull::dangling().as_ptr();
match *ptr {
! => {} //~ ERROR `!` patterns are experimental
}
}
// Check that the gate operates even behind `cfg`.
#[cfg(FALSE)]
unsafe {
let ptr: *const Void = NonNull::dangling().as_ptr();
match *ptr {
! => {} //~ ERROR `!` patterns are experimental
}
}
}

View file

@ -0,0 +1,39 @@
error[E0408]: variable `_x` is not bound in all patterns
--> $DIR/feature-gate-never_patterns.rs:8:19
|
LL | let (Ok(_x) | Err(&!)) = res.as_ref();
| -- ^^^^^^^ pattern doesn't bind `_x`
| |
| variable not in all patterns
error[E0658]: `!` patterns are experimental
--> $DIR/feature-gate-never_patterns.rs:8:24
|
LL | let (Ok(_x) | Err(&!)) = res.as_ref();
| ^
|
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
error[E0658]: `!` patterns are experimental
--> $DIR/feature-gate-never_patterns.rs:15:13
|
LL | ! => {}
| ^
|
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
error[E0658]: `!` patterns are experimental
--> $DIR/feature-gate-never_patterns.rs:24:13
|
LL | ! => {}
| ^
|
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0408, E0658.
For more information about an error, try `rustc --explain E0408`.

View file

@ -11,6 +11,7 @@
#![feature(decl_macro)]
#![feature(explicit_tail_calls)]
#![feature(more_qualified_paths)]
#![feature(never_patterns)]
#![feature(raw_ref_op)]
#![feature(trait_alias)]
#![feature(try_blocks)]
@ -635,6 +636,10 @@ fn test_pat() {
// PatKind::Rest
c1!(pat, [ .. ], "..");
// PatKind::Never
c1!(pat, [ Some(!) ], "Some(!)");
c1!(pat, [ None | Some(!) ], "None | Some(!)");
// PatKind::Paren
c1!(pat, [ (pat) ], "(pat)");

View file

@ -0,0 +1,99 @@
#![feature(never_patterns)]
#![allow(incomplete_features)]
enum Void {}
fn main() {}
// The classic use for empty types.
fn safe_unwrap_result<T>(res: Result<T, Void>) {
let Ok(_x) = res;
// FIXME(never_patterns): These should be allowed
let (Ok(_x) | Err(!)) = &res;
//~^ ERROR: is not bound in all patterns
let (Ok(_x) | Err(&!)) = res.as_ref();
//~^ ERROR: is not bound in all patterns
}
// Check we only accept `!` where we want to.
fn never_pattern_location(void: Void) {
// FIXME(never_patterns): Don't accept on a non-empty type.
match Some(0) {
None => {}
Some(!) => {}
}
// FIXME(never_patterns): Don't accept on an arbitrary type, even if there are no more branches.
match () {
() => {}
! => {}
}
// FIXME(never_patterns): Don't accept even on an empty branch.
match None::<Void> {
None => {}
! => {}
}
// FIXME(never_patterns): Let alone if the emptiness is behind a reference.
match None::<&Void> {
None => {}
! => {}
}
// Participate in match ergonomics.
match &void {
! => {}
}
match &&void {
! => {}
}
match &&void {
&! => {}
}
match &None::<Void> {
None => {}
Some(!) => {}
}
match None::<&Void> {
None => {}
Some(!) => {}
}
// Accept on a composite empty type.
match None::<&(u32, Void)> {
None => {}
Some(&!) => {}
}
// Accept on an simple empty type.
match None::<Void> {
None => {}
Some(!) => {}
}
match None::<&Void> {
None => {}
Some(&!) => {}
}
match None::<&(u32, Void)> {
None => {}
Some(&(_, !)) => {}
}
}
fn never_and_bindings() {
let x: Result<bool, &(u32, Void)> = Ok(false);
// FIXME(never_patterns): Never patterns in or-patterns don't need to share the same bindings.
match x {
Ok(_x) | Err(&!) => {}
//~^ ERROR: is not bound in all patterns
}
let (Ok(_x) | Err(&!)) = x;
//~^ ERROR: is not bound in all patterns
// FIXME(never_patterns): A never pattern mustn't have bindings.
match x {
Ok(_) => {}
Err(&(_b, !)) => {}
}
match x {
Ok(_a) | Err(&(_b, !)) => {}
//~^ ERROR: is not bound in all patterns
//~| ERROR: is not bound in all patterns
}
}

View file

@ -0,0 +1,51 @@
error[E0408]: variable `_x` is not bound in all patterns
--> $DIR/never_patterns.rs:12:19
|
LL | let (Ok(_x) | Err(!)) = &res;
| -- ^^^^^^ pattern doesn't bind `_x`
| |
| variable not in all patterns
error[E0408]: variable `_x` is not bound in all patterns
--> $DIR/never_patterns.rs:14:19
|
LL | let (Ok(_x) | Err(&!)) = res.as_ref();
| -- ^^^^^^^ pattern doesn't bind `_x`
| |
| variable not in all patterns
error[E0408]: variable `_x` is not bound in all patterns
--> $DIR/never_patterns.rs:83:18
|
LL | Ok(_x) | Err(&!) => {}
| -- ^^^^^^^ pattern doesn't bind `_x`
| |
| variable not in all patterns
error[E0408]: variable `_x` is not bound in all patterns
--> $DIR/never_patterns.rs:86:19
|
LL | let (Ok(_x) | Err(&!)) = x;
| -- ^^^^^^^ pattern doesn't bind `_x`
| |
| variable not in all patterns
error[E0408]: variable `_b` is not bound in all patterns
--> $DIR/never_patterns.rs:95:9
|
LL | Ok(_a) | Err(&(_b, !)) => {}
| ^^^^^^ -- variable not in all patterns
| |
| pattern doesn't bind `_b`
error[E0408]: variable `_a` is not bound in all patterns
--> $DIR/never_patterns.rs:95:18
|
LL | Ok(_a) | Err(&(_b, !)) => {}
| -- ^^^^^^^^^^^^^ pattern doesn't bind `_a`
| |
| variable not in all patterns
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0408`.