mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-21 12:13:12 +00:00
Rollup merge of #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, #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
This commit is contained in:
commit
783778c631
@ -1441,7 +1441,7 @@ pub enum ExprKind {
|
||||
/// `'label: loop { block }`
|
||||
Loop(P<Block>, Option<Label>, Span),
|
||||
/// A `match` block.
|
||||
Match(P<Expr>, ThinVec<Arm>),
|
||||
Match(P<Expr>, ThinVec<Arm>, MatchKind),
|
||||
/// A closure (e.g., `move |a, b, c| a + b + c`).
|
||||
Closure(Box<Closure>),
|
||||
/// A block (`'label: { ... }`).
|
||||
@ -1766,6 +1766,15 @@ pub enum StrStyle {
|
||||
Raw(u8),
|
||||
}
|
||||
|
||||
/// The kind of match expression
|
||||
#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq)]
|
||||
pub enum MatchKind {
|
||||
/// match expr { ... }
|
||||
Prefix,
|
||||
/// expr.match { ... }
|
||||
Postfix,
|
||||
}
|
||||
|
||||
/// A literal in a meta item.
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct MetaItemLit {
|
||||
|
@ -1425,7 +1425,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::Match(expr, arms) => {
|
||||
ExprKind::Match(expr, arms, _kind) => {
|
||||
vis.visit_expr(expr);
|
||||
arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
|
||||
}
|
||||
|
@ -923,7 +923,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
||||
visit_opt!(visitor, visit_label, opt_label);
|
||||
try_visit!(visitor.visit_block(block));
|
||||
}
|
||||
ExprKind::Match(subexpression, arms) => {
|
||||
ExprKind::Match(subexpression, arms, _kind) => {
|
||||
try_visit!(visitor.visit_expr(subexpression));
|
||||
walk_list!(visitor, visit_arm, arms);
|
||||
}
|
||||
|
@ -181,10 +181,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
)
|
||||
}),
|
||||
ExprKind::TryBlock(body) => self.lower_expr_try_block(body),
|
||||
ExprKind::Match(expr, arms) => hir::ExprKind::Match(
|
||||
ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(
|
||||
self.lower_expr(expr),
|
||||
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
|
||||
hir::MatchSource::Normal,
|
||||
match kind {
|
||||
MatchKind::Prefix => hir::MatchSource::Normal,
|
||||
MatchKind::Postfix => hir::MatchSource::Postfix,
|
||||
},
|
||||
),
|
||||
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
|
||||
ExprKind::Closure(box Closure {
|
||||
|
@ -564,6 +564,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
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) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::pp::Breaks::Inconsistent;
|
||||
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
|
||||
use ast::ForLoopKind;
|
||||
use ast::{ForLoopKind, MatchKind};
|
||||
use itertools::{Itertools, Position};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
@ -589,12 +589,22 @@ impl<'a> State<'a> {
|
||||
self.word_nbsp("loop");
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
}
|
||||
ast::ExprKind::Match(expr, arms) => {
|
||||
ast::ExprKind::Match(expr, arms, match_kind) => {
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
self.word_nbsp("match");
|
||||
self.print_expr_as_cond(expr);
|
||||
self.space();
|
||||
|
||||
match match_kind {
|
||||
MatchKind::Prefix => {
|
||||
self.word_nbsp("match");
|
||||
self.print_expr_as_cond(expr);
|
||||
self.space();
|
||||
}
|
||||
MatchKind::Postfix => {
|
||||
self.print_expr_as_cond(expr);
|
||||
self.word_nbsp(".match");
|
||||
}
|
||||
}
|
||||
|
||||
self.bopen();
|
||||
self.print_inner_attributes_no_trailing_hardbreak(attrs);
|
||||
for arm in arms {
|
||||
|
@ -245,7 +245,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||
ExprKind::Let(_, local_expr, _, _) => {
|
||||
self.manage_cond_expr(local_expr);
|
||||
}
|
||||
ExprKind::Match(local_expr, _) => {
|
||||
ExprKind::Match(local_expr, ..) => {
|
||||
self.manage_cond_expr(local_expr);
|
||||
}
|
||||
ExprKind::MethodCall(call) => {
|
||||
|
@ -132,7 +132,7 @@ fn cs_partial_cmp(
|
||||
// Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
|
||||
|
||||
if !tag_then_data
|
||||
&& let ExprKind::Match(_, arms) = &mut expr1.kind
|
||||
&& let ExprKind::Match(_, arms, _) = &mut expr1.kind
|
||||
&& let Some(last) = arms.last_mut()
|
||||
&& let PatKind::Wild = last.pat.kind
|
||||
{
|
||||
|
@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::deriving::path_std;
|
||||
|
||||
use ast::EnumDef;
|
||||
use rustc_ast::{self as ast, MetaItem};
|
||||
use rustc_ast::{self as ast, EnumDef, MetaItem};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::base::ExtCtxt;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, PatKind, UnOp};
|
||||
use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp};
|
||||
use rustc_ast::{attr, token, util::literal};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
@ -524,7 +524,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
}
|
||||
|
||||
pub fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: ThinVec<ast::Arm>) -> P<Expr> {
|
||||
self.expr(span, ast::ExprKind::Match(arg, arms))
|
||||
self.expr(span, ast::ExprKind::Match(arg, arms, MatchKind::Prefix))
|
||||
}
|
||||
|
||||
pub fn expr_if(
|
||||
|
@ -559,6 +559,8 @@ declare_features! (
|
||||
(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.
|
||||
|
@ -2019,6 +2019,8 @@ pub enum LocalSource {
|
||||
pub enum MatchSource {
|
||||
/// A `match _ { .. }`.
|
||||
Normal,
|
||||
/// A `expr.match { .. }`.
|
||||
Postfix,
|
||||
/// A desugared `for _ in _ { .. }` loop.
|
||||
ForLoopDesugar,
|
||||
/// A desugared `?` operator.
|
||||
@ -2035,6 +2037,7 @@ impl MatchSource {
|
||||
use MatchSource::*;
|
||||
match self {
|
||||
Normal => "match",
|
||||
Postfix => ".match",
|
||||
ForLoopDesugar => "for",
|
||||
TryDesugar(_) => "?",
|
||||
AwaitDesugar => ".await",
|
||||
|
@ -865,7 +865,7 @@ trait UnusedDelimLint {
|
||||
(iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true)
|
||||
}
|
||||
|
||||
Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
|
||||
Match(ref head, ..) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
|
||||
let left = e.span.lo() + rustc_span::BytePos(5);
|
||||
(head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None, true)
|
||||
}
|
||||
@ -1133,7 +1133,7 @@ impl EarlyLintPass for UnusedParens {
|
||||
}
|
||||
return;
|
||||
}
|
||||
ExprKind::Match(ref _expr, ref arm) => {
|
||||
ExprKind::Match(ref _expr, ref arm, _) => {
|
||||
for a in arm {
|
||||
if let Some(body) = &a.body {
|
||||
self.check_unused_delims_expr(
|
||||
|
@ -481,6 +481,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||
// when the iterator is an uninhabited type. unreachable_code will trigger instead.
|
||||
hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {}
|
||||
hir::MatchSource::ForLoopDesugar
|
||||
| hir::MatchSource::Postfix
|
||||
| hir::MatchSource::Normal
|
||||
| hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report),
|
||||
// Unreachable patterns in try and await expressions occur when one of
|
||||
|
@ -11,7 +11,7 @@ use crate::errors;
|
||||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||
use ast::mut_visit::{noop_visit_expr, MutVisitor};
|
||||
use ast::token::IdentIsRaw;
|
||||
use ast::{CoroutineKind, ForLoopKind, GenBlockKind, Pat, Path, PathSegment};
|
||||
use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment};
|
||||
use core::mem;
|
||||
use core::ops::ControlFlow;
|
||||
use rustc_ast::ptr::P;
|
||||
@ -1379,6 +1379,13 @@ impl<'a> Parser<'a> {
|
||||
return Ok(self.mk_await_expr(self_arg, lo));
|
||||
}
|
||||
|
||||
// Post-fix match
|
||||
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, MatchKind::Postfix);
|
||||
}
|
||||
|
||||
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)]);
|
||||
@ -2894,8 +2901,20 @@ impl<'a> Parser<'a> {
|
||||
/// 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, MatchKind::Prefix)
|
||||
}
|
||||
|
||||
/// Parses the block of 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>,
|
||||
match_kind: MatchKind,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
if let Err(mut e) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
|
||||
if self.token == token::Semi {
|
||||
e.span_suggestion_short(
|
||||
@ -2938,7 +2957,7 @@ impl<'a> Parser<'a> {
|
||||
});
|
||||
return Ok(self.mk_expr_with_attrs(
|
||||
span,
|
||||
ExprKind::Match(scrutinee, arms),
|
||||
ExprKind::Match(scrutinee, arms, match_kind),
|
||||
attrs,
|
||||
));
|
||||
}
|
||||
@ -2946,7 +2965,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
let hi = self.token.span;
|
||||
self.bump();
|
||||
Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms), attrs))
|
||||
Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms, match_kind), attrs))
|
||||
}
|
||||
|
||||
/// Attempt to recover from match arm body with statements and no surrounding braces.
|
||||
@ -3955,7 +3974,7 @@ impl MutVisitor for CondChecker<'_> {
|
||||
| ExprKind::While(_, _, _)
|
||||
| ExprKind::ForLoop { .. }
|
||||
| ExprKind::Loop(_, _, _)
|
||||
| ExprKind::Match(_, _)
|
||||
| ExprKind::Match(_, _, _)
|
||||
| ExprKind::Closure(_)
|
||||
| ExprKind::Block(_, _)
|
||||
| ExprKind::Gen(_, _, _)
|
||||
|
@ -48,7 +48,7 @@ impl NonConstExpr {
|
||||
Self::Match(TryDesugar(_)) => &[sym::const_try],
|
||||
|
||||
// All other expressions are allowed.
|
||||
Self::Loop(Loop | While) | Self::Match(Normal | FormatArgs) => &[],
|
||||
Self::Loop(Loop | While) | Self::Match(Normal | Postfix | FormatArgs) => &[],
|
||||
};
|
||||
|
||||
Some(gates)
|
||||
|
@ -1335,6 +1335,7 @@ symbols! {
|
||||
poll,
|
||||
poll_next,
|
||||
post_dash_lto: "post-lto",
|
||||
postfix_match,
|
||||
powerpc_target_feature,
|
||||
powf128,
|
||||
powf16,
|
||||
|
22
src/doc/unstable-book/src/language-features/postfix-match.md
Normal file
22
src/doc/unstable-book/src/language-features/postfix-match.md
Normal 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!(),
|
||||
}
|
||||
```
|
@ -105,7 +105,7 @@ impl<'ast> Visitor<'ast> for BreakVisitor {
|
||||
fn visit_expr(&mut self, expr: &'ast Expr) {
|
||||
self.is_break = match expr.kind {
|
||||
ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) => true,
|
||||
ExprKind::Match(_, ref arms) => arms.iter().all(|arm|
|
||||
ExprKind::Match(_, ref arms, _) => arms.iter().all(|arm|
|
||||
arm.body.is_none() || arm.body.as_deref().is_some_and(|body| self.check_expr(body))
|
||||
),
|
||||
ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els),
|
||||
|
@ -552,7 +552,7 @@ fn ident_difference_expr_with_base_location(
|
||||
| (Gen(_, _, _), Gen(_, _, _))
|
||||
| (Block(_, _), Block(_, _))
|
||||
| (Closure(_), Closure(_))
|
||||
| (Match(_, _), Match(_, _))
|
||||
| (Match(_, _, _), Match(_, _, _))
|
||||
| (Loop(_, _, _), Loop(_, _, _))
|
||||
| (ForLoop { .. }, ForLoop { .. })
|
||||
| (While(_, _, _), While(_, _, _))
|
||||
|
@ -198,7 +198,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
||||
},
|
||||
(AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
|
||||
(Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
|
||||
(Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm),
|
||||
(Match(ls, la, lkind), Match(rs, ra, rkind)) => (lkind == rkind) && eq_expr(ls, rs) && over(la, ra, eq_arm),
|
||||
(
|
||||
Closure(box ast::Closure {
|
||||
binder: lb,
|
||||
|
@ -3,7 +3,7 @@ use std::cmp::min;
|
||||
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::token::{Delimiter, Lit, LitKind};
|
||||
use rustc_ast::{ast, ptr, token, ForLoopKind};
|
||||
use rustc_ast::{ast, ptr, token, ForLoopKind, MatchKind};
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
||||
use crate::chains::rewrite_chain;
|
||||
@ -170,8 +170,8 @@ pub(crate) fn format_expr(
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Match(ref cond, ref arms) => {
|
||||
rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs)
|
||||
ast::ExprKind::Match(ref cond, ref arms, kind) => {
|
||||
rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs, kind)
|
||||
}
|
||||
ast::ExprKind::Path(ref qself, ref path) => {
|
||||
rewrite_path(context, PathContext::Expr, qself, path, shape)
|
||||
@ -625,7 +625,7 @@ pub(crate) fn rewrite_cond(
|
||||
shape: Shape,
|
||||
) -> Option<String> {
|
||||
match expr.kind {
|
||||
ast::ExprKind::Match(ref cond, _) => {
|
||||
ast::ExprKind::Match(ref cond, _, MatchKind::Prefix) => {
|
||||
// `match `cond` {`
|
||||
let cond_shape = match context.config.indent_style() {
|
||||
IndentStyle::Visual => shape.shrink_left(6).and_then(|s| s.sub_width(2))?,
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use std::iter::repeat;
|
||||
|
||||
use rustc_ast::{ast, ptr};
|
||||
use rustc_ast::{ast, ptr, MatchKind};
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
||||
use crate::comment::{combine_strs_with_missing_comments, rewrite_comment};
|
||||
@ -72,6 +72,7 @@ pub(crate) fn rewrite_match(
|
||||
shape: Shape,
|
||||
span: Span,
|
||||
attrs: &[ast::Attribute],
|
||||
match_kind: MatchKind,
|
||||
) -> Option<String> {
|
||||
// Do not take the rhs overhead from the upper expressions into account
|
||||
// when rewriting match condition.
|
||||
@ -131,15 +132,27 @@ pub(crate) fn rewrite_match(
|
||||
}
|
||||
} else {
|
||||
let span_after_cond = mk_sp(cond.span.hi(), span.hi());
|
||||
Some(format!(
|
||||
"match {}{}{{\n{}{}{}\n{}}}",
|
||||
cond_str,
|
||||
block_sep,
|
||||
inner_attrs_str,
|
||||
nested_indent_str,
|
||||
rewrite_match_arms(context, arms, shape, span_after_cond, open_brace_pos)?,
|
||||
shape.indent.to_string(context.config),
|
||||
))
|
||||
|
||||
match match_kind {
|
||||
MatchKind::Prefix => Some(format!(
|
||||
"match {}{}{{\n{}{}{}\n{}}}",
|
||||
cond_str,
|
||||
block_sep,
|
||||
inner_attrs_str,
|
||||
nested_indent_str,
|
||||
rewrite_match_arms(context, arms, shape, span_after_cond, open_brace_pos)?,
|
||||
shape.indent.to_string(context.config),
|
||||
)),
|
||||
MatchKind::Postfix => Some(format!(
|
||||
"{}.match{}{{\n{}{}{}\n{}}}",
|
||||
cond_str,
|
||||
block_sep,
|
||||
inner_attrs_str,
|
||||
nested_indent_str,
|
||||
rewrite_match_arms(context, arms, shape, span_after_cond, open_brace_pos)?,
|
||||
shape.indent.to_string(context.config),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
20
src/tools/rustfmt/tests/source/postfix-match/pf-match.rs
Normal file
20
src/tools/rustfmt/tests/source/postfix-match/pf-match.rs
Normal file
@ -0,0 +1,20 @@
|
||||
#![feature(postfix_match)]
|
||||
|
||||
fn main() {
|
||||
let val = Some(42);
|
||||
|
||||
val.match {
|
||||
Some(_) => 2,
|
||||
_ => 1
|
||||
};
|
||||
|
||||
Some(2).match {
|
||||
Some(_) => true,
|
||||
None => false
|
||||
}.match {
|
||||
false => "ferris is cute",
|
||||
true => "I turn cats in to petted cats",
|
||||
}.match {
|
||||
_ => (),
|
||||
}
|
||||
}
|
20
src/tools/rustfmt/tests/target/postfix-match/pf-match.rs
Normal file
20
src/tools/rustfmt/tests/target/postfix-match/pf-match.rs
Normal file
@ -0,0 +1,20 @@
|
||||
#![feature(postfix_match)]
|
||||
|
||||
fn main() {
|
||||
let val = Some(42);
|
||||
|
||||
val.match {
|
||||
Some(_) => 2,
|
||||
_ => 1,
|
||||
};
|
||||
|
||||
Some(2).match {
|
||||
Some(_) => true,
|
||||
None => false,
|
||||
}.match {
|
||||
false => "ferris is cute",
|
||||
true => "I turn cats in to petted cats",
|
||||
}.match {
|
||||
_ => (),
|
||||
}
|
||||
}
|
21
tests/pretty/postfix-match.rs
Normal file
21
tests/pretty/postfix-match.rs
Normal file
@ -0,0 +1,21 @@
|
||||
#![feature(postfix_match)]
|
||||
|
||||
fn main() {
|
||||
let val = Some(42);
|
||||
|
||||
val.match {
|
||||
Some(_) => 2,
|
||||
_ => 1
|
||||
};
|
||||
|
||||
|
||||
Some(2).match {
|
||||
Some(_) => true,
|
||||
None => false
|
||||
}.match {
|
||||
false => "ferris is cute",
|
||||
true => "I turn cats in to petted cats",
|
||||
}.match {
|
||||
_ => (),
|
||||
}
|
||||
}
|
17
tests/ui/feature-gates/feature-gate-postfix_match.rs
Normal file
17
tests/ui/feature-gates/feature-gate-postfix_match.rs
Normal 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"
|
||||
};
|
||||
}
|
23
tests/ui/feature-gates/feature-gate-postfix_match.stderr
Normal file
23
tests/ui/feature-gates/feature-gate-postfix_match.stderr
Normal 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`.
|
16
tests/ui/match/postfix-match/pf-match-chain.rs
Normal file
16
tests/ui/match/postfix-match/pf-match-chain.rs
Normal 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!()
|
||||
}
|
||||
}
|
7
tests/ui/match/postfix-match/pf-match-exhaustiveness.rs
Normal file
7
tests/ui/match/postfix-match/pf-match-exhaustiveness.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#![feature(postfix_match)]
|
||||
|
||||
fn main() {
|
||||
Some(1).match { //~ non-exhaustive patterns
|
||||
None => {},
|
||||
}
|
||||
}
|
21
tests/ui/match/postfix-match/pf-match-exhaustiveness.stderr
Normal file
21
tests/ui/match/postfix-match/pf-match-exhaustiveness.stderr
Normal 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`.
|
15
tests/ui/match/postfix-match/pf-match-types.rs
Normal file
15
tests/ui/match/postfix-match/pf-match-types.rs
Normal 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
|
||||
}
|
||||
}
|
21
tests/ui/match/postfix-match/pf-match-types.stderr
Normal file
21
tests/ui/match/postfix-match/pf-match-types.stderr
Normal 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`.
|
62
tests/ui/match/postfix-match/postfix-match.rs
Normal file
62
tests/ui/match/postfix-match/postfix-match.rs
Normal 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, .. } => {},
|
||||
_ => (),
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user