Skip to content

Commit 4911756

Browse files
authored
Unrolled build for rust-lang#121619
Rollup merge of rust-lang#121619 - RossSmyth:pfix_match, r=petrochenkov Experimental feature postfix match This has a basic experimental implementation for the RFC postfix match (rust-lang/rfcs#3295, rust-lang#121618). [Liaison is](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Postfix.20Match.20Liaison/near/423301844) ```@scottmcm``` with the lang team's [experimental feature gate process](https://github.com/rust-lang/lang-team/blob/master/src/how_to/experiment.md). This feature has had an RFC for a while, and there has been discussion on it for a while. It would probably be valuable to see it out in the field rather than continue discussing it. This feature also allows to see how popular postfix expressions like this are for the postfix macros RFC, as those will take more time to implement. It is entirely implemented in the parser, so it should be relatively easy to remove if needed. This PR is split in to 5 commits to ease review. 1. The implementation of the feature & gating. 2. Add a MatchKind field, fix uses, fix pretty. 3. Basic rustfmt impl, as rustfmt crashes upon seeing this syntax without a fix. 4. Add new MatchSource to HIR for Clippy & other HIR consumers
2 parents eff958c + 567c98b commit 4911756

File tree

34 files changed

+367
-41
lines changed

34 files changed

+367
-41
lines changed

compiler/rustc_ast/src/ast.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1437,7 +1437,7 @@ pub enum ExprKind {
14371437
/// `'label: loop { block }`
14381438
Loop(P<Block>, Option<Label>, Span),
14391439
/// A `match` block.
1440-
Match(P<Expr>, ThinVec<Arm>),
1440+
Match(P<Expr>, ThinVec<Arm>, MatchKind),
14411441
/// A closure (e.g., `move |a, b, c| a + b + c`).
14421442
Closure(Box<Closure>),
14431443
/// A block (`'label: { ... }`).
@@ -1762,6 +1762,15 @@ pub enum StrStyle {
17621762
Raw(u8),
17631763
}
17641764

1765+
/// The kind of match expression
1766+
#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq)]
1767+
pub enum MatchKind {
1768+
/// match expr { ... }
1769+
Prefix,
1770+
/// expr.match { ... }
1771+
Postfix,
1772+
}
1773+
17651774
/// A literal in a meta item.
17661775
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
17671776
pub struct MetaItemLit {

compiler/rustc_ast/src/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1425,7 +1425,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
14251425
visit_opt(label, |label| vis.visit_label(label));
14261426
vis.visit_span(span);
14271427
}
1428-
ExprKind::Match(expr, arms) => {
1428+
ExprKind::Match(expr, arms, _kind) => {
14291429
vis.visit_expr(expr);
14301430
arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
14311431
}

compiler/rustc_ast/src/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
923923
visit_opt!(visitor, visit_label, opt_label);
924924
try_visit!(visitor.visit_block(block));
925925
}
926-
ExprKind::Match(subexpression, arms) => {
926+
ExprKind::Match(subexpression, arms, _kind) => {
927927
try_visit!(visitor.visit_expr(subexpression));
928928
walk_list!(visitor, visit_arm, arms);
929929
}

compiler/rustc_ast_lowering/src/expr.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
181181
)
182182
}),
183183
ExprKind::TryBlock(body) => self.lower_expr_try_block(body),
184-
ExprKind::Match(expr, arms) => hir::ExprKind::Match(
184+
ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(
185185
self.lower_expr(expr),
186186
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
187-
hir::MatchSource::Normal,
187+
match kind {
188+
MatchKind::Prefix => hir::MatchSource::Normal,
189+
MatchKind::Postfix => hir::MatchSource::Postfix,
190+
},
188191
),
189192
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
190193
ExprKind::Closure(box Closure {

compiler/rustc_ast_passes/src/feature_gate.rs

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

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

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::pp::Breaks::Inconsistent;
22
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
3-
use ast::ForLoopKind;
3+
use ast::{ForLoopKind, MatchKind};
44
use itertools::{Itertools, Position};
55
use rustc_ast::ptr::P;
66
use rustc_ast::token;
@@ -589,12 +589,22 @@ impl<'a> State<'a> {
589589
self.word_nbsp("loop");
590590
self.print_block_with_attrs(blk, attrs);
591591
}
592-
ast::ExprKind::Match(expr, arms) => {
592+
ast::ExprKind::Match(expr, arms, match_kind) => {
593593
self.cbox(0);
594594
self.ibox(0);
595-
self.word_nbsp("match");
596-
self.print_expr_as_cond(expr);
597-
self.space();
595+
596+
match match_kind {
597+
MatchKind::Prefix => {
598+
self.word_nbsp("match");
599+
self.print_expr_as_cond(expr);
600+
self.space();
601+
}
602+
MatchKind::Postfix => {
603+
self.print_expr_as_cond(expr);
604+
self.word_nbsp(".match");
605+
}
606+
}
607+
598608
self.bopen();
599609
self.print_inner_attributes_no_trailing_hardbreak(attrs);
600610
for arm in arms {

compiler/rustc_builtin_macros/src/assert/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
245245
ExprKind::Let(_, local_expr, _, _) => {
246246
self.manage_cond_expr(local_expr);
247247
}
248-
ExprKind::Match(local_expr, _) => {
248+
ExprKind::Match(local_expr, ..) => {
249249
self.manage_cond_expr(local_expr);
250250
}
251251
ExprKind::MethodCall(call) => {

compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ fn cs_partial_cmp(
132132
// Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
133133

134134
if !tag_then_data
135-
&& let ExprKind::Match(_, arms) = &mut expr1.kind
135+
&& let ExprKind::Match(_, arms, _) = &mut expr1.kind
136136
&& let Some(last) = arms.last_mut()
137137
&& let PatKind::Wild = last.pat.kind
138138
{

compiler/rustc_builtin_macros/src/deriving/debug.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
22
use crate::deriving::generic::*;
33
use crate::deriving::path_std;
44

5-
use ast::EnumDef;
6-
use rustc_ast::{self as ast, MetaItem};
5+
use rustc_ast::{self as ast, EnumDef, MetaItem};
76
use rustc_expand::base::{Annotatable, ExtCtxt};
87
use rustc_span::symbol::{sym, Ident, Symbol};
98
use rustc_span::Span;

compiler/rustc_expand/src/build.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::base::ExtCtxt;
22
use rustc_ast::ptr::P;
3-
use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, PatKind, UnOp};
3+
use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp};
44
use rustc_ast::{attr, token, util::literal};
55
use rustc_span::source_map::Spanned;
66
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -524,7 +524,7 @@ impl<'a> ExtCtxt<'a> {
524524
}
525525

526526
pub fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: ThinVec<ast::Arm>) -> P<Expr> {
527-
self.expr(span, ast::ExprKind::Match(arg, arms))
527+
self.expr(span, ast::ExprKind::Match(arg, arms, MatchKind::Prefix))
528528
}
529529

530530
pub fn expr_if(

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,8 @@ declare_features! (
559559
(unstable, offset_of_nested, "1.77.0", Some(120140)),
560560
/// Allows using `#[optimize(X)]`.
561561
(unstable, optimize_attribute, "1.34.0", Some(54882)),
562+
/// Allows postfix match `expr.match { ... }`
563+
(unstable, postfix_match, "CURRENT_RUSTC_VERSION", Some(121618)),
562564
/// Allows macro attributes on expressions, statements and non-inline modules.
563565
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
564566
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.

compiler/rustc_hir/src/hir.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2015,6 +2015,8 @@ pub enum LocalSource {
20152015
pub enum MatchSource {
20162016
/// A `match _ { .. }`.
20172017
Normal,
2018+
/// A `expr.match { .. }`.
2019+
Postfix,
20182020
/// A desugared `for _ in _ { .. }` loop.
20192021
ForLoopDesugar,
20202022
/// A desugared `?` operator.
@@ -2031,6 +2033,7 @@ impl MatchSource {
20312033
use MatchSource::*;
20322034
match self {
20332035
Normal => "match",
2036+
Postfix => ".match",
20342037
ForLoopDesugar => "for",
20352038
TryDesugar(_) => "?",
20362039
AwaitDesugar => ".await",

compiler/rustc_lint/src/unused.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ trait UnusedDelimLint {
865865
(iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true)
866866
}
867867

868-
Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
868+
Match(ref head, ..) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
869869
let left = e.span.lo() + rustc_span::BytePos(5);
870870
(head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None, true)
871871
}
@@ -1133,7 +1133,7 @@ impl EarlyLintPass for UnusedParens {
11331133
}
11341134
return;
11351135
}
1136-
ExprKind::Match(ref _expr, ref arm) => {
1136+
ExprKind::Match(ref _expr, ref arm, _) => {
11371137
for a in arm {
11381138
if let Some(body) = &a.body {
11391139
self.check_unused_delims_expr(

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+1
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
481481
// when the iterator is an uninhabited type. unreachable_code will trigger instead.
482482
hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {}
483483
hir::MatchSource::ForLoopDesugar
484+
| hir::MatchSource::Postfix
484485
| hir::MatchSource::Normal
485486
| hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report),
486487
// Unreachable patterns in try and await expressions occur when one of

compiler/rustc_parse/src/parser/expr.rs

+24-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::errors;
1111
use crate::maybe_recover_from_interpolated_ty_qpath;
1212
use ast::mut_visit::{noop_visit_expr, MutVisitor};
1313
use ast::token::IdentIsRaw;
14-
use ast::{CoroutineKind, ForLoopKind, GenBlockKind, Pat, Path, PathSegment};
14+
use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment};
1515
use core::mem;
1616
use core::ops::ControlFlow;
1717
use rustc_ast::ptr::P;
@@ -1379,6 +1379,13 @@ impl<'a> Parser<'a> {
13791379
return Ok(self.mk_await_expr(self_arg, lo));
13801380
}
13811381

1382+
// Post-fix match
1383+
if self.eat_keyword(kw::Match) {
1384+
let match_span = self.prev_token.span;
1385+
self.psess.gated_spans.gate(sym::postfix_match, match_span);
1386+
return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
1387+
}
1388+
13821389
let fn_span_lo = self.token.span;
13831390
let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
13841391
self.check_trailing_angle_brackets(&seg, &[&token::OpenDelim(Delimiter::Parenthesis)]);
@@ -2894,8 +2901,20 @@ impl<'a> Parser<'a> {
28942901
/// Parses a `match ... { ... }` expression (`match` token already eaten).
28952902
fn parse_expr_match(&mut self) -> PResult<'a, P<Expr>> {
28962903
let match_span = self.prev_token.span;
2897-
let lo = self.prev_token.span;
28982904
let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
2905+
2906+
self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
2907+
}
2908+
2909+
/// Parses the block of a `match expr { ... }` or a `expr.match { ... }`
2910+
/// expression. This is after the match token and scrutinee are eaten
2911+
fn parse_match_block(
2912+
&mut self,
2913+
lo: Span,
2914+
match_span: Span,
2915+
scrutinee: P<Expr>,
2916+
match_kind: MatchKind,
2917+
) -> PResult<'a, P<Expr>> {
28992918
if let Err(mut e) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
29002919
if self.token == token::Semi {
29012920
e.span_suggestion_short(
@@ -2938,15 +2957,15 @@ impl<'a> Parser<'a> {
29382957
});
29392958
return Ok(self.mk_expr_with_attrs(
29402959
span,
2941-
ExprKind::Match(scrutinee, arms),
2960+
ExprKind::Match(scrutinee, arms, match_kind),
29422961
attrs,
29432962
));
29442963
}
29452964
}
29462965
}
29472966
let hi = self.token.span;
29482967
self.bump();
2949-
Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms), attrs))
2968+
Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms, match_kind), attrs))
29502969
}
29512970

29522971
/// Attempt to recover from match arm body with statements and no surrounding braces.
@@ -3955,7 +3974,7 @@ impl MutVisitor for CondChecker<'_> {
39553974
| ExprKind::While(_, _, _)
39563975
| ExprKind::ForLoop { .. }
39573976
| ExprKind::Loop(_, _, _)
3958-
| ExprKind::Match(_, _)
3977+
| ExprKind::Match(_, _, _)
39593978
| ExprKind::Closure(_)
39603979
| ExprKind::Block(_, _)
39613980
| ExprKind::Gen(_, _, _)

compiler/rustc_passes/src/check_const.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl NonConstExpr {
4848
Self::Match(TryDesugar(_)) => &[sym::const_try],
4949

5050
// All other expressions are allowed.
51-
Self::Loop(Loop | While) | Self::Match(Normal | FormatArgs) => &[],
51+
Self::Loop(Loop | While) | Self::Match(Normal | Postfix | FormatArgs) => &[],
5252
};
5353

5454
Some(gates)

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,7 @@ symbols! {
13351335
poll,
13361336
poll_next,
13371337
post_dash_lto: "post-lto",
1338+
postfix_match,
13381339
powerpc_target_feature,
13391340
powf128,
13401341
powf16,
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+
```

src/tools/clippy/clippy_lints/src/redundant_else.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl<'ast> Visitor<'ast> for BreakVisitor {
105105
fn visit_expr(&mut self, expr: &'ast Expr) {
106106
self.is_break = match expr.kind {
107107
ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) => true,
108-
ExprKind::Match(_, ref arms) => arms.iter().all(|arm|
108+
ExprKind::Match(_, ref arms, _) => arms.iter().all(|arm|
109109
arm.body.is_none() || arm.body.as_deref().is_some_and(|body| self.check_expr(body))
110110
),
111111
ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els),

src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ fn ident_difference_expr_with_base_location(
552552
| (Gen(_, _, _), Gen(_, _, _))
553553
| (Block(_, _), Block(_, _))
554554
| (Closure(_), Closure(_))
555-
| (Match(_, _), Match(_, _))
555+
| (Match(_, _, _), Match(_, _, _))
556556
| (Loop(_, _, _), Loop(_, _, _))
557557
| (ForLoop { .. }, ForLoop { .. })
558558
| (While(_, _, _), While(_, _, _))

src/tools/clippy/clippy_utils/src/ast_utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
198198
},
199199
(AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
200200
(Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
201-
(Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm),
201+
(Match(ls, la, lkind), Match(rs, ra, rkind)) => (lkind == rkind) && eq_expr(ls, rs) && over(la, ra, eq_arm),
202202
(
203203
Closure(box ast::Closure {
204204
binder: lb,

src/tools/rustfmt/src/expr.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::cmp::min;
33

44
use itertools::Itertools;
55
use rustc_ast::token::{Delimiter, Lit, LitKind};
6-
use rustc_ast::{ast, ptr, token, ForLoopKind};
6+
use rustc_ast::{ast, ptr, token, ForLoopKind, MatchKind};
77
use rustc_span::{BytePos, Span};
88

99
use crate::chains::rewrite_chain;
@@ -170,8 +170,8 @@ pub(crate) fn format_expr(
170170
}
171171
}
172172
}
173-
ast::ExprKind::Match(ref cond, ref arms) => {
174-
rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs)
173+
ast::ExprKind::Match(ref cond, ref arms, kind) => {
174+
rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs, kind)
175175
}
176176
ast::ExprKind::Path(ref qself, ref path) => {
177177
rewrite_path(context, PathContext::Expr, qself, path, shape)
@@ -625,7 +625,7 @@ pub(crate) fn rewrite_cond(
625625
shape: Shape,
626626
) -> Option<String> {
627627
match expr.kind {
628-
ast::ExprKind::Match(ref cond, _) => {
628+
ast::ExprKind::Match(ref cond, _, MatchKind::Prefix) => {
629629
// `match `cond` {`
630630
let cond_shape = match context.config.indent_style() {
631631
IndentStyle::Visual => shape.shrink_left(6).and_then(|s| s.sub_width(2))?,

0 commit comments

Comments
 (0)