1
Fork 0

Add MatchKind member to the Match expr for pretty printing & fmt

This commit is contained in:
Ross Smyth 2024-02-17 12:43:54 -05:00
parent 68a58f255a
commit 78b3bf98c3
17 changed files with 76 additions and 33 deletions

View file

@ -1436,7 +1436,7 @@ pub enum ExprKind {
/// `'label: loop { block }` /// `'label: loop { block }`
Loop(P<Block>, Option<Label>, Span), Loop(P<Block>, Option<Label>, Span),
/// A `match` block. /// 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`). /// A closure (e.g., `move |a, b, c| a + b + c`).
Closure(Box<Closure>), Closure(Box<Closure>),
/// A block (`'label: { ... }`). /// A block (`'label: { ... }`).
@ -1761,6 +1761,15 @@ pub enum StrStyle {
Raw(u8), 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. /// A literal in a meta item.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct MetaItemLit { pub struct MetaItemLit {

View file

@ -1423,7 +1423,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
visit_opt(label, |label| vis.visit_label(label)); visit_opt(label, |label| vis.visit_label(label));
vis.visit_span(span); vis.visit_span(span);
} }
ExprKind::Match(expr, arms) => { ExprKind::Match(expr, arms, _kind) => {
vis.visit_expr(expr); vis.visit_expr(expr);
arms.flat_map_in_place(|arm| vis.flat_map_arm(arm)); arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
} }

View file

@ -919,7 +919,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
visit_opt!(visitor, visit_label, opt_label); visit_opt!(visitor, visit_label, opt_label);
try_visit!(visitor.visit_block(block)); try_visit!(visitor.visit_block(block));
} }
ExprKind::Match(subexpression, arms) => { ExprKind::Match(subexpression, arms, _kind) => {
try_visit!(visitor.visit_expr(subexpression)); try_visit!(visitor.visit_expr(subexpression));
walk_list!(visitor, visit_arm, arms); walk_list!(visitor, visit_arm, arms);
} }

View file

@ -181,7 +181,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
) )
}), }),
ExprKind::TryBlock(body) => self.lower_expr_try_block(body), ExprKind::TryBlock(body) => self.lower_expr_try_block(body),
ExprKind::Match(expr, arms) => hir::ExprKind::Match( ExprKind::Match(expr, arms, _) => hir::ExprKind::Match(
self.lower_expr(expr), self.lower_expr(expr),
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))), self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
hir::MatchSource::Normal, hir::MatchSource::Normal,

View file

@ -1,6 +1,6 @@
use crate::pp::Breaks::Inconsistent; use crate::pp::Breaks::Inconsistent;
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
use ast::ForLoopKind; use ast::{ForLoopKind, MatchKind};
use itertools::{Itertools, Position}; use itertools::{Itertools, Position};
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token; use rustc_ast::token;
@ -589,12 +589,22 @@ impl<'a> State<'a> {
self.word_nbsp("loop"); self.word_nbsp("loop");
self.print_block_with_attrs(blk, attrs); self.print_block_with_attrs(blk, attrs);
} }
ast::ExprKind::Match(expr, arms) => { ast::ExprKind::Match(expr, arms, match_kind) => {
self.cbox(0); self.cbox(0);
self.ibox(0); self.ibox(0);
match match_kind {
MatchKind::Prefix => {
self.word_nbsp("match"); self.word_nbsp("match");
self.print_expr_as_cond(expr); self.print_expr_as_cond(expr);
self.space(); self.space();
}
MatchKind::Postfix => {
self.print_expr_as_cond(expr);
self.word_nbsp(".match");
}
}
self.bopen(); self.bopen();
self.print_inner_attributes_no_trailing_hardbreak(attrs); self.print_inner_attributes_no_trailing_hardbreak(attrs);
for arm in arms { for arm in arms {

View file

@ -245,7 +245,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
ExprKind::Let(_, local_expr, _, _) => { ExprKind::Let(_, local_expr, _, _) => {
self.manage_cond_expr(local_expr); self.manage_cond_expr(local_expr);
} }
ExprKind::Match(local_expr, _) => { ExprKind::Match(local_expr, ..) => {
self.manage_cond_expr(local_expr); self.manage_cond_expr(local_expr);
} }
ExprKind::MethodCall(call) => { ExprKind::MethodCall(call) => {

View file

@ -132,7 +132,7 @@ fn cs_partial_cmp(
// Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354 // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
if !tag_then_data 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 Some(last) = arms.last_mut()
&& let PatKind::Wild = last.pat.kind && let PatKind::Wild = last.pat.kind
{ {

View file

@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
use crate::deriving::generic::*; use crate::deriving::generic::*;
use crate::deriving::path_std; use crate::deriving::path_std;
use ast::EnumDef; use rustc_ast::{self as ast, EnumDef, MetaItem};
use rustc_ast::{self as ast, MetaItem};
use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span; use rustc_span::Span;

View file

@ -1,6 +1,6 @@
use crate::base::ExtCtxt; use crate::base::ExtCtxt;
use rustc_ast::ptr::P; 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_ast::{attr, token, util::literal};
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol}; 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> { 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( pub fn expr_if(

View file

@ -865,7 +865,7 @@ trait UnusedDelimLint {
(iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true) (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); let left = e.span.lo() + rustc_span::BytePos(5);
(head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None, true) (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None, true)
} }
@ -1133,7 +1133,7 @@ impl EarlyLintPass for UnusedParens {
} }
return; return;
} }
ExprKind::Match(ref _expr, ref arm) => { ExprKind::Match(ref _expr, ref arm, _) => {
for a in arm { for a in arm {
if let Some(body) = &a.body { if let Some(body) = &a.body {
self.check_unused_delims_expr( self.check_unused_delims_expr(

View file

@ -11,7 +11,7 @@ use crate::errors;
use crate::maybe_recover_from_interpolated_ty_qpath; use crate::maybe_recover_from_interpolated_ty_qpath;
use ast::mut_visit::{noop_visit_expr, MutVisitor}; use ast::mut_visit::{noop_visit_expr, MutVisitor};
use ast::token::IdentIsRaw; 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::mem;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::token::{self, Delimiter, Token, TokenKind};
@ -1375,10 +1375,11 @@ impl<'a> Parser<'a> {
return Ok(self.mk_await_expr(self_arg, lo)); return Ok(self.mk_await_expr(self_arg, lo));
} }
// Post-fix match
if self.eat_keyword(kw::Match) { if self.eat_keyword(kw::Match) {
let match_span = self.prev_token.span; let match_span = self.prev_token.span;
self.psess.gated_spans.gate(sym::postfix_match, match_span); self.psess.gated_spans.gate(sym::postfix_match, match_span);
return self.parse_match_block(lo, match_span, self_arg); return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
} }
let fn_span_lo = self.token.span; let fn_span_lo = self.token.span;
@ -2897,16 +2898,17 @@ impl<'a> Parser<'a> {
let match_span = self.prev_token.span; let match_span = self.prev_token.span;
let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
self.parse_match_block(match_span, match_span, scrutinee) self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
} }
/// Parses a `match expr { ... }` or a `expr.match { ... }` expression. /// Parses the block of a `match expr { ... }` or a `expr.match { ... }`
/// This is after the match token and scrutinee are eaten /// expression. This is after the match token and scrutinee are eaten
fn parse_match_block( fn parse_match_block(
&mut self, &mut self,
lo: Span, lo: Span,
match_span: Span, match_span: Span,
scrutinee: P<Expr>, scrutinee: P<Expr>,
match_kind: MatchKind,
) -> PResult<'a, P<Expr>> { ) -> PResult<'a, P<Expr>> {
if let Err(mut e) = self.expect(&token::OpenDelim(Delimiter::Brace)) { if let Err(mut e) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
if self.token == token::Semi { if self.token == token::Semi {
@ -2950,7 +2952,7 @@ impl<'a> Parser<'a> {
}); });
return Ok(self.mk_expr_with_attrs( return Ok(self.mk_expr_with_attrs(
span, span,
ExprKind::Match(scrutinee, arms), ExprKind::Match(scrutinee, arms, match_kind),
attrs, attrs,
)); ));
} }
@ -2958,7 +2960,7 @@ impl<'a> Parser<'a> {
} }
let hi = self.token.span; let hi = self.token.span;
self.bump(); 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. /// Attempt to recover from match arm body with statements and no surrounding braces.
@ -3967,7 +3969,7 @@ impl MutVisitor for CondChecker<'_> {
| ExprKind::While(_, _, _) | ExprKind::While(_, _, _)
| ExprKind::ForLoop { .. } | ExprKind::ForLoop { .. }
| ExprKind::Loop(_, _, _) | ExprKind::Loop(_, _, _)
| ExprKind::Match(_, _) | ExprKind::Match(_, _, _)
| ExprKind::Closure(_) | ExprKind::Closure(_)
| ExprKind::Block(_, _) | ExprKind::Block(_, _)
| ExprKind::Gen(_, _, _) | ExprKind::Gen(_, _, _)

View file

@ -105,7 +105,7 @@ impl<'ast> Visitor<'ast> for BreakVisitor {
fn visit_expr(&mut self, expr: &'ast Expr) { fn visit_expr(&mut self, expr: &'ast Expr) {
self.is_break = match expr.kind { self.is_break = match expr.kind {
ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) => true, 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)) 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), ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els),

View file

@ -552,7 +552,7 @@ fn ident_difference_expr_with_base_location(
| (Gen(_, _, _), Gen(_, _, _)) | (Gen(_, _, _), Gen(_, _, _))
| (Block(_, _), Block(_, _)) | (Block(_, _), Block(_, _))
| (Closure(_), Closure(_)) | (Closure(_), Closure(_))
| (Match(_, _), Match(_, _)) | (Match(_, _, _), Match(_, _, _))
| (Loop(_, _, _), Loop(_, _, _)) | (Loop(_, _, _), Loop(_, _, _))
| (ForLoop { .. }, ForLoop { .. }) | (ForLoop { .. }, ForLoop { .. })
| (While(_, _, _), While(_, _, _)) | (While(_, _, _), While(_, _, _))

View file

@ -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), (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), (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 { Closure(box ast::Closure {
binder: lb, binder: lb,

View file

@ -3,7 +3,7 @@ use std::cmp::min;
use itertools::Itertools; use itertools::Itertools;
use rustc_ast::token::{Delimiter, Lit, LitKind}; use rustc_ast::token::{Delimiter, Lit, LitKind};
use rustc_ast::{ast, ptr, token, ForLoopKind}; use rustc_ast::{ast, MatchKind, ptr, token, ForLoopKind};
use rustc_span::{BytePos, Span}; use rustc_span::{BytePos, Span};
use crate::chains::rewrite_chain; use crate::chains::rewrite_chain;
@ -170,8 +170,8 @@ pub(crate) fn format_expr(
} }
} }
} }
ast::ExprKind::Match(ref cond, ref arms) => { ast::ExprKind::Match(ref cond, ref arms, kind) => {
rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs) rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs, kind)
} }
ast::ExprKind::Path(ref qself, ref path) => { ast::ExprKind::Path(ref qself, ref path) => {
rewrite_path(context, PathContext::Expr, qself, path, shape) rewrite_path(context, PathContext::Expr, qself, path, shape)
@ -625,7 +625,7 @@ pub(crate) fn rewrite_cond(
shape: Shape, shape: Shape,
) -> Option<String> { ) -> Option<String> {
match expr.kind { match expr.kind {
ast::ExprKind::Match(ref cond, _) => { ast::ExprKind::Match(ref cond, _, MatchKind::Prefix) => {
// `match `cond` {` // `match `cond` {`
let cond_shape = match context.config.indent_style() { let cond_shape = match context.config.indent_style() {
IndentStyle::Visual => shape.shrink_left(6).and_then(|s| s.sub_width(2))?, IndentStyle::Visual => shape.shrink_left(6).and_then(|s| s.sub_width(2))?,

View file

@ -2,7 +2,7 @@
use std::iter::repeat; use std::iter::repeat;
use rustc_ast::{ast, ptr}; use rustc_ast::{ast, MatchKind, ptr};
use rustc_span::{BytePos, Span}; use rustc_span::{BytePos, Span};
use crate::comment::{combine_strs_with_missing_comments, rewrite_comment}; use crate::comment::{combine_strs_with_missing_comments, rewrite_comment};
@ -72,6 +72,8 @@ pub(crate) fn rewrite_match(
shape: Shape, shape: Shape,
span: Span, span: Span,
attrs: &[ast::Attribute], attrs: &[ast::Attribute],
// TODO: Use this
_: MatchKind,
) -> Option<String> { ) -> Option<String> {
// Do not take the rhs overhead from the upper expressions into account // Do not take the rhs overhead from the upper expressions into account
// when rewriting match condition. // when rewriting match condition.

View 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 {
_ => (),
}
}