Skip to content

Commit 62f97c3

Browse files
RossSmythcuviper
andcommitted
Add postfix-match experimental feature
Co-authored-by: Josh Stone <[email protected]>
1 parent 0ecbd06 commit 62f97c3

File tree

13 files changed

+209
-1
lines changed

13 files changed

+209
-1
lines changed

compiler/rustc_ast_passes/src/feature_gate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
565565
gate_all!(generic_const_items, "generic const items are experimental");
566566
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
567567
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
568+
gate_all!(postfix_match, "postfix match is experimental");
568569

569570
if !visitor.features.never_patterns {
570571
if let Some(spans) = spans.get(&sym::never_patterns) {

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,8 @@ declare_features! (
555555
(unstable, offset_of_nested, "1.77.0", Some(120140)),
556556
/// Allows using `#[optimize(X)]`.
557557
(unstable, optimize_attribute, "1.34.0", Some(54882)),
558+
/// Allows postfix match `expr.match { ... }`
559+
(unstable, postfix_match, "CURRENT_RUSTC_VERSION", Some(121618)),
558560
/// Allows macro attributes on expressions, statements and non-inline modules.
559561
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
560562
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.

compiler/rustc_parse/src/parser/expr.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,12 @@ impl<'a> Parser<'a> {
13751375
return Ok(self.mk_await_expr(self_arg, lo));
13761376
}
13771377

1378+
if self.eat_keyword(kw::Match) {
1379+
let match_span = self.prev_token.span;
1380+
self.sess.gated_spans.gate(sym::postfix_match, match_span);
1381+
return self.parse_match_block(lo, match_span, self_arg);
1382+
}
1383+
13781384
let fn_span_lo = self.token.span;
13791385
let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
13801386
self.check_trailing_angle_brackets(&seg, &[&token::OpenDelim(Delimiter::Parenthesis)]);
@@ -2887,8 +2893,19 @@ impl<'a> Parser<'a> {
28872893
/// Parses a `match ... { ... }` expression (`match` token already eaten).
28882894
fn parse_expr_match(&mut self) -> PResult<'a, P<Expr>> {
28892895
let match_span = self.prev_token.span;
2890-
let lo = self.prev_token.span;
28912896
let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
2897+
2898+
self.parse_match_block(match_span, match_span, scrutinee)
2899+
}
2900+
2901+
/// Parses a `match expr { ... }` or a `expr.match { ... }` expression.
2902+
/// This is after the match token and scrutinee are eaten
2903+
fn parse_match_block(
2904+
&mut self,
2905+
lo: Span,
2906+
match_span: Span,
2907+
scrutinee: P<Expr>,
2908+
) -> PResult<'a, P<Expr>> {
28922909
if let Err(mut e) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
28932910
if self.token == token::Semi {
28942911
e.span_suggestion_short(

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,7 @@ symbols! {
12321232
poll,
12331233
poll_next,
12341234
post_dash_lto: "post-lto",
1235+
postfix_match,
12351236
powerpc_target_feature,
12361237
powf32,
12371238
powf64,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# `postfix-match`
2+
3+
`postfix-match` adds the feature for matching upon values postfix
4+
the expressions that generate the values.
5+
6+
```rust,edition2021
7+
#![feature(postfix_match)]
8+
9+
enum Foo {
10+
Bar,
11+
Baz
12+
}
13+
14+
fn get_foo() -> Foo {
15+
Foo::Bar
16+
}
17+
18+
get_foo().match {
19+
Foo::Bar => {},
20+
Foo::Baz => panic!(),
21+
}
22+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Testing that postfix match doesn't work without enabling the feature
2+
3+
fn main() {
4+
let val = Some(42);
5+
6+
val.match { //~ ERROR postfix match is experimental
7+
Some(42) => "the answer to life, the universe, and everything",
8+
_ => "might be the answer to something"
9+
};
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0658]: postfix match is experimental
2+
--> $DIR/feature-gate-postfix_match.rs:6:9
3+
|
4+
LL | val.match {
5+
| ^^^^^
6+
|
7+
= note: see issue #121618 <https://github.com/rust-lang/rust/issues/121618> for more information
8+
= help: add `#![feature(postfix_match)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error: aborting due to 1 previous error
12+
13+
For more information about this error, try `rustc --explain E0658`.
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//@ run-pass
2+
3+
#![feature(postfix_match)]
4+
5+
fn main() {
6+
1.match {
7+
2 => Some(0),
8+
_ => None,
9+
}.match {
10+
None => Ok(true),
11+
Some(_) => Err("nope")
12+
}.match {
13+
Ok(_) => (),
14+
Err(_) => panic!()
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(postfix_match)]
2+
3+
fn main() {
4+
Some(1).match { //~ non-exhaustive patterns
5+
None => {},
6+
}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
2+
--> $DIR/pf-match-exhaustiveness.rs:4:5
3+
|
4+
LL | Some(1).match {
5+
| ^^^^^^^ pattern `Some(_)` not covered
6+
|
7+
note: `Option<i32>` defined here
8+
--> $SRC_DIR/core/src/option.rs:LL:COL
9+
::: $SRC_DIR/core/src/option.rs:LL:COL
10+
|
11+
= note: not covered
12+
= note: the matched value is of type `Option<i32>`
13+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
14+
|
15+
LL ~ None => {},
16+
LL ~ Some(_) => todo!(),
17+
|
18+
19+
error: aborting due to 1 previous error
20+
21+
For more information about this error, try `rustc --explain E0004`.
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(postfix_match)]
2+
3+
fn main() {
4+
Some(10).match {
5+
//~^ NOTE `match` arms have incompatible types
6+
Some(5) => false,
7+
//~^ NOTE this is found to be of type `bool`
8+
Some(2) => true,
9+
//~^ NOTE this is found to be of type `bool`
10+
None => (),
11+
//~^ ERROR `match` arms have incompatible types
12+
//~| NOTE expected `bool`, found `()`
13+
_ => true
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0308]: `match` arms have incompatible types
2+
--> $DIR/pf-match-types.rs:10:20
3+
|
4+
LL | / Some(10).match {
5+
LL | |
6+
LL | | Some(5) => false,
7+
| | ----- this is found to be of type `bool`
8+
LL | |
9+
LL | | Some(2) => true,
10+
| | ---- this is found to be of type `bool`
11+
LL | |
12+
LL | | None => (),
13+
| | ^^ expected `bool`, found `()`
14+
... |
15+
LL | | _ => true
16+
LL | | }
17+
| |_____- `match` arms have incompatible types
18+
19+
error: aborting due to 1 previous error
20+
21+
For more information about this error, try `rustc --explain E0308`.
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//@ run-pass
2+
3+
#![feature(postfix_match)]
4+
5+
struct Bar {
6+
foo: u8,
7+
baz: u8,
8+
}
9+
10+
pub fn main() {
11+
let thing = Some("thing");
12+
13+
thing.match {
14+
Some("nothing") => {},
15+
Some(text) if text.eq_ignore_ascii_case("tapir") => {},
16+
Some("true") | Some("false") => {},
17+
Some("thing") => {},
18+
Some(_) => {},
19+
None => {}
20+
};
21+
22+
let num = 2u8;
23+
24+
num.match {
25+
0 => {},
26+
1..=5 => {},
27+
_ => {},
28+
};
29+
30+
let slic = &[1, 2, 3, 4][..];
31+
32+
slic.match {
33+
[1] => {},
34+
[2, _tail @ ..] => {},
35+
[1, _] => {},
36+
_ => {},
37+
};
38+
39+
slic[0].match {
40+
1 => 0,
41+
i => i,
42+
};
43+
44+
let out = (1, 2).match {
45+
(1, 3) => 0,
46+
(_, 1) => 0,
47+
(1, i) => i,
48+
_ => 3,
49+
};
50+
assert!(out == 2);
51+
52+
let strct = Bar {
53+
foo: 3,
54+
baz: 4
55+
};
56+
57+
strct.match {
58+
Bar { foo: 1, .. } => {},
59+
Bar { baz: 2, .. } => {},
60+
_ => (),
61+
};
62+
}

0 commit comments

Comments
 (0)