Add postfix-match experimental feature

Co-authored-by: Josh Stone <jistone@redhat.com>
This commit is contained in:
Ross Smyth 2024-02-15 19:54:35 -05:00
parent 62415e2a95
commit 68a58f255a
13 changed files with 226 additions and 1 deletions

View File

@ -565,6 +565,7 @@ macro_rules! gate_all {
gate_all!(generic_const_items, "generic const items are experimental");
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
gate_all!(postfix_match, "postfix match is experimental");
if !visitor.features.never_patterns {
if let Some(spans) = spans.get(&sym::never_patterns) {

View File

@ -555,6 +555,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, offset_of_nested, "1.77.0", Some(120140)),
/// Allows using `#[optimize(X)]`.
(unstable, optimize_attribute, "1.34.0", Some(54882)),
/// Allows postfix match `expr.match { ... }`
(unstable, postfix_match, "CURRENT_RUSTC_VERSION", Some(121618)),
/// Allows macro attributes on expressions, statements and non-inline modules.
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.

View File

@ -1375,6 +1375,12 @@ fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Exp
return Ok(self.mk_await_expr(self_arg, lo));
}
if self.eat_keyword(kw::Match) {
let match_span = self.prev_token.span;
self.psess.gated_spans.gate(sym::postfix_match, match_span);
return self.parse_match_block(lo, match_span, self_arg);
}
let fn_span_lo = self.token.span;
let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
self.check_trailing_angle_brackets(&seg, &[&token::OpenDelim(Delimiter::Parenthesis)]);
@ -2889,8 +2895,19 @@ pub(crate) fn eat_label(&mut self) -> Option<Label> {
/// Parses a `match ... { ... }` expression (`match` token already eaten).
fn parse_expr_match(&mut self) -> PResult<'a, P<Expr>> {
let match_span = self.prev_token.span;
let lo = self.prev_token.span;
let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
self.parse_match_block(match_span, match_span, scrutinee)
}
/// Parses a `match expr { ... }` or a `expr.match { ... }` expression.
/// This is after the match token and scrutinee are eaten
fn parse_match_block(
&mut self,
lo: Span,
match_span: Span,
scrutinee: P<Expr>,
) -> PResult<'a, P<Expr>> {
if let Err(mut e) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
if self.token == token::Semi {
e.span_suggestion_short(

View File

@ -1319,6 +1319,7 @@
poll,
poll_next,
post_dash_lto: "post-lto",
postfix_match,
powerpc_target_feature,
powf128,
powf16,

View File

@ -0,0 +1,22 @@
# `postfix-match`
`postfix-match` adds the feature for matching upon values postfix
the expressions that generate the values.
```rust,edition2021
#![feature(postfix_match)]
enum Foo {
Bar,
Baz
}
fn get_foo() -> Foo {
Foo::Bar
}
get_foo().match {
Foo::Bar => {},
Foo::Baz => panic!(),
}
```

View File

@ -0,0 +1,17 @@
// Testing that postfix match doesn't work without enabling the feature
fn main() {
let val = Some(42);
val.match { //~ ERROR postfix match is experimental
Some(42) => "the answer to life, the universe, and everything",
_ => "might be the answer to something"
};
// Test that the gate works behind a cfg
#[cfg(FALSE)]
val.match { //~ ERROR postfix match is experimental
Some(42) => "the answer to life, the universe, and everything",
_ => "might be the answer to something"
};
}

View File

@ -0,0 +1,23 @@
error[E0658]: postfix match is experimental
--> $DIR/feature-gate-postfix_match.rs:6:9
|
LL | val.match {
| ^^^^^
|
= note: see issue #121618 <https://github.com/rust-lang/rust/issues/121618> for more information
= help: add `#![feature(postfix_match)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: postfix match is experimental
--> $DIR/feature-gate-postfix_match.rs:13:9
|
LL | val.match {
| ^^^^^
|
= note: see issue #121618 <https://github.com/rust-lang/rust/issues/121618> for more information
= help: add `#![feature(postfix_match)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,16 @@
//@ run-pass
#![feature(postfix_match)]
fn main() {
1.match {
2 => Some(0),
_ => None,
}.match {
None => Ok(true),
Some(_) => Err("nope")
}.match {
Ok(_) => (),
Err(_) => panic!()
}
}

View File

@ -0,0 +1,7 @@
#![feature(postfix_match)]
fn main() {
Some(1).match { //~ non-exhaustive patterns
None => {},
}
}

View File

@ -0,0 +1,21 @@
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
--> $DIR/pf-match-exhaustiveness.rs:4:5
|
LL | Some(1).match {
| ^^^^^^^ pattern `Some(_)` not covered
|
note: `Option<i32>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
::: $SRC_DIR/core/src/option.rs:LL:COL
|
= note: not covered
= note: the matched value is of type `Option<i32>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ None => {},
LL ~ Some(_) => todo!(),
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0004`.

View File

@ -0,0 +1,15 @@
#![feature(postfix_match)]
fn main() {
Some(10).match {
//~^ NOTE `match` arms have incompatible types
Some(5) => false,
//~^ NOTE this is found to be of type `bool`
Some(2) => true,
//~^ NOTE this is found to be of type `bool`
None => (),
//~^ ERROR `match` arms have incompatible types
//~| NOTE expected `bool`, found `()`
_ => true
}
}

View File

@ -0,0 +1,21 @@
error[E0308]: `match` arms have incompatible types
--> $DIR/pf-match-types.rs:10:20
|
LL | / Some(10).match {
LL | |
LL | | Some(5) => false,
| | ----- this is found to be of type `bool`
LL | |
LL | | Some(2) => true,
| | ---- this is found to be of type `bool`
LL | |
LL | | None => (),
| | ^^ expected `bool`, found `()`
... |
LL | | _ => true
LL | | }
| |_____- `match` arms have incompatible types
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,62 @@
//@ run-pass
#![feature(postfix_match)]
struct Bar {
foo: u8,
baz: u8,
}
pub fn main() {
let thing = Some("thing");
thing.match {
Some("nothing") => {},
Some(text) if text.eq_ignore_ascii_case("tapir") => {},
Some("true") | Some("false") => {},
Some("thing") => {},
Some(_) => {},
None => {}
};
let num = 2u8;
num.match {
0 => {},
1..=5 => {},
_ => {},
};
let slic = &[1, 2, 3, 4][..];
slic.match {
[1] => {},
[2, _tail @ ..] => {},
[1, _] => {},
_ => {},
};
slic[0].match {
1 => 0,
i => i,
};
let out = (1, 2).match {
(1, 3) => 0,
(_, 1) => 0,
(1, i) => i,
_ => 3,
};
assert!(out == 2);
let strct = Bar {
foo: 3,
baz: 4
};
strct.match {
Bar { foo: 1, .. } => {},
Bar { baz: 2, .. } => {},
_ => (),
};
}