mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Rollup merge of #118726 - dtolnay:matchguardlet, r=compiler-errors
Do not parenthesize exterior struct lit inside match guards Before this PR, the AST pretty-printer injects parentheses around expressions any time parens _could_ be needed depending on what else is in the code that surrounds that expression. But the pretty-printer did not pass around enough context to understand whether parentheses really _are_ needed on any particular expression. As a consequence, there are false positives where unneeded parentheses are being inserted. Example: ```rust #![feature(if_let_guard)] macro_rules! pp { ($e:expr) => { stringify!($e) }; } fn main() { println!("{}", pp!(match () { () if let _ = Struct {} => {} })); } ``` **Before:** ```console match () { () if let _ = (Struct {}) => {} } ``` **After:** ```console match () { () if let _ = Struct {} => {} } ``` This PR introduces a bit of state that is passed across various expression printing methods to help understand accurately whether particular situations require parentheses injected by the pretty printer, and it fixes one such false positive involving match guards as shown above. There are other parenthesization false positive cases not fixed by this PR. I intend to address these in follow-up PRs. For example here is one: the expression `{ let _ = match x {} + 1; }` is pretty-printed as `{ let _ = (match x {}) + 1; }` despite there being no reason for parentheses to appear there.
This commit is contained in:
commit
3a0562b93c
@ -7,6 +7,7 @@ mod item;
|
||||
|
||||
use crate::pp::Breaks::{Consistent, Inconsistent};
|
||||
use crate::pp::{self, Breaks};
|
||||
use crate::pprust::state::expr::FixupContext;
|
||||
use rustc_ast::attr::AttrIdGenerator;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind};
|
||||
@ -811,7 +812,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||
}
|
||||
|
||||
fn expr_to_string(&self, e: &ast::Expr) -> String {
|
||||
Self::to_string(|s| s.print_expr(e))
|
||||
Self::to_string(|s| s.print_expr(e, FixupContext::default()))
|
||||
}
|
||||
|
||||
fn meta_item_lit_to_string(&self, lit: &ast::MetaItemLit) -> String {
|
||||
@ -916,7 +917,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
|
||||
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
|
||||
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e, FixupContext::default()), |e| e.span)
|
||||
}
|
||||
|
||||
pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
|
||||
@ -953,7 +954,7 @@ impl<'a> State<'a> {
|
||||
match generic_arg {
|
||||
GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
|
||||
GenericArg::Type(ty) => self.print_type(ty),
|
||||
GenericArg::Const(ct) => self.print_expr(&ct.value),
|
||||
GenericArg::Const(ct) => self.print_expr(&ct.value, FixupContext::default()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1020,12 +1021,12 @@ impl<'a> State<'a> {
|
||||
self.word("[");
|
||||
self.print_type(ty);
|
||||
self.word("; ");
|
||||
self.print_expr(&length.value);
|
||||
self.print_expr(&length.value, FixupContext::default());
|
||||
self.word("]");
|
||||
}
|
||||
ast::TyKind::Typeof(e) => {
|
||||
self.word("typeof(");
|
||||
self.print_expr(&e.value);
|
||||
self.print_expr(&e.value, FixupContext::default());
|
||||
self.word(")");
|
||||
}
|
||||
ast::TyKind::Infer => {
|
||||
@ -1081,7 +1082,7 @@ impl<'a> State<'a> {
|
||||
if let Some((init, els)) = loc.kind.init_else_opt() {
|
||||
self.nbsp();
|
||||
self.word_space("=");
|
||||
self.print_expr(init);
|
||||
self.print_expr(init, FixupContext::default());
|
||||
if let Some(els) = els {
|
||||
self.cbox(INDENT_UNIT);
|
||||
self.ibox(INDENT_UNIT);
|
||||
@ -1095,14 +1096,14 @@ impl<'a> State<'a> {
|
||||
ast::StmtKind::Item(item) => self.print_item(item),
|
||||
ast::StmtKind::Expr(expr) => {
|
||||
self.space_if_not_bol();
|
||||
self.print_expr_outer_attr_style(expr, false);
|
||||
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
|
||||
if classify::expr_requires_semi_to_be_stmt(expr) {
|
||||
self.word(";");
|
||||
}
|
||||
}
|
||||
ast::StmtKind::Semi(expr) => {
|
||||
self.space_if_not_bol();
|
||||
self.print_expr_outer_attr_style(expr, false);
|
||||
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
|
||||
self.word(";");
|
||||
}
|
||||
ast::StmtKind::Empty => {
|
||||
@ -1154,7 +1155,7 @@ impl<'a> State<'a> {
|
||||
ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => {
|
||||
self.maybe_print_comment(st.span.lo());
|
||||
self.space_if_not_bol();
|
||||
self.print_expr_outer_attr_style(expr, false);
|
||||
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
|
||||
self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
|
||||
}
|
||||
_ => self.print_stmt(st),
|
||||
@ -1167,13 +1168,41 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
/// Print a `let pat = expr` expression.
|
||||
fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) {
|
||||
///
|
||||
/// Parentheses are inserted surrounding `expr` if a round-trip through the
|
||||
/// parser would otherwise work out the wrong way in a condition position.
|
||||
///
|
||||
/// For example each of the following would mean the wrong thing without
|
||||
/// parentheses.
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// if let _ = (Struct {}) {}
|
||||
///
|
||||
/// if let _ = (true && false) {}
|
||||
/// ```
|
||||
///
|
||||
/// In a match guard, the second case still requires parens, but the first
|
||||
/// case no longer does because anything until `=>` is considered part of
|
||||
/// the match guard expression. Parsing of the expression is not terminated
|
||||
/// by `{` in that position.
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// match () {
|
||||
/// () if let _ = Struct {} => {}
|
||||
/// () if let _ = (true && false) => {}
|
||||
/// }
|
||||
/// ```
|
||||
fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, fixup: FixupContext) {
|
||||
self.word("let ");
|
||||
self.print_pat(pat);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order());
|
||||
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
fixup.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
|
||||
|| parser::needs_par_as_let_scrutinee(expr.precedence().order()),
|
||||
FixupContext::default(),
|
||||
);
|
||||
}
|
||||
|
||||
fn print_mac(&mut self, m: &ast::MacCall) {
|
||||
@ -1220,7 +1249,7 @@ impl<'a> State<'a> {
|
||||
print_reg_or_class(s, reg);
|
||||
s.pclose();
|
||||
s.space();
|
||||
s.print_expr(expr);
|
||||
s.print_expr(expr, FixupContext::default());
|
||||
}
|
||||
InlineAsmOperand::Out { reg, late, expr } => {
|
||||
s.word(if *late { "lateout" } else { "out" });
|
||||
@ -1229,7 +1258,7 @@ impl<'a> State<'a> {
|
||||
s.pclose();
|
||||
s.space();
|
||||
match expr {
|
||||
Some(expr) => s.print_expr(expr),
|
||||
Some(expr) => s.print_expr(expr, FixupContext::default()),
|
||||
None => s.word("_"),
|
||||
}
|
||||
}
|
||||
@ -1239,7 +1268,7 @@ impl<'a> State<'a> {
|
||||
print_reg_or_class(s, reg);
|
||||
s.pclose();
|
||||
s.space();
|
||||
s.print_expr(expr);
|
||||
s.print_expr(expr, FixupContext::default());
|
||||
}
|
||||
InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
|
||||
s.word(if *late { "inlateout" } else { "inout" });
|
||||
@ -1247,18 +1276,18 @@ impl<'a> State<'a> {
|
||||
print_reg_or_class(s, reg);
|
||||
s.pclose();
|
||||
s.space();
|
||||
s.print_expr(in_expr);
|
||||
s.print_expr(in_expr, FixupContext::default());
|
||||
s.space();
|
||||
s.word_space("=>");
|
||||
match out_expr {
|
||||
Some(out_expr) => s.print_expr(out_expr),
|
||||
Some(out_expr) => s.print_expr(out_expr, FixupContext::default()),
|
||||
None => s.word("_"),
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Const { anon_const } => {
|
||||
s.word("const");
|
||||
s.space();
|
||||
s.print_expr(&anon_const.value);
|
||||
s.print_expr(&anon_const.value, FixupContext::default());
|
||||
}
|
||||
InlineAsmOperand::Sym { sym } => {
|
||||
s.word("sym");
|
||||
@ -1452,10 +1481,10 @@ impl<'a> State<'a> {
|
||||
self.print_pat(inner);
|
||||
}
|
||||
}
|
||||
PatKind::Lit(e) => self.print_expr(e),
|
||||
PatKind::Lit(e) => self.print_expr(e, FixupContext::default()),
|
||||
PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => {
|
||||
if let Some(e) = begin {
|
||||
self.print_expr(e);
|
||||
self.print_expr(e, FixupContext::default());
|
||||
}
|
||||
match end_kind {
|
||||
RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."),
|
||||
@ -1463,7 +1492,7 @@ impl<'a> State<'a> {
|
||||
RangeEnd::Excluded => self.word(".."),
|
||||
}
|
||||
if let Some(e) = end {
|
||||
self.print_expr(e);
|
||||
self.print_expr(e, FixupContext::default());
|
||||
}
|
||||
}
|
||||
PatKind::Slice(elts) => {
|
||||
@ -1617,7 +1646,7 @@ impl<'a> State<'a> {
|
||||
if let Some(default) = default {
|
||||
s.space();
|
||||
s.word_space("=");
|
||||
s.print_expr(&default.value);
|
||||
s.print_expr(&default.value, FixupContext::default());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,19 @@ use rustc_ast::{
|
||||
};
|
||||
use std::fmt::Write;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct FixupContext {
|
||||
pub parenthesize_exterior_struct_lit: bool,
|
||||
}
|
||||
|
||||
/// The default amount of fixing is minimal fixing. Fixups should be turned on
|
||||
/// in a targetted fashion where needed.
|
||||
impl Default for FixupContext {
|
||||
fn default() -> Self {
|
||||
FixupContext { parenthesize_exterior_struct_lit: false }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> State<'a> {
|
||||
fn print_else(&mut self, els: Option<&ast::Expr>) {
|
||||
if let Some(_else) = els {
|
||||
@ -55,21 +68,22 @@ impl<'a> State<'a> {
|
||||
self.pclose()
|
||||
}
|
||||
|
||||
fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
|
||||
self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
|
||||
fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8, fixup: FixupContext) {
|
||||
self.print_expr_cond_paren(expr, expr.precedence().order() < prec, fixup);
|
||||
}
|
||||
|
||||
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
|
||||
/// `if cond { ... }`.
|
||||
fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
|
||||
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
|
||||
let fixup = FixupContext { parenthesize_exterior_struct_lit: true };
|
||||
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr), fixup)
|
||||
}
|
||||
|
||||
/// Does `expr` need parentheses when printed in a condition position?
|
||||
///
|
||||
/// These cases need parens due to the parse error observed in #26461: `if return {}`
|
||||
/// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
|
||||
pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool {
|
||||
fn cond_needs_par(expr: &ast::Expr) -> bool {
|
||||
match expr.kind {
|
||||
ast::ExprKind::Break(..)
|
||||
| ast::ExprKind::Closure(..)
|
||||
@ -80,11 +94,32 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
/// Prints `expr` or `(expr)` when `needs_par` holds.
|
||||
pub(super) fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
|
||||
pub(super) fn print_expr_cond_paren(
|
||||
&mut self,
|
||||
expr: &ast::Expr,
|
||||
needs_par: bool,
|
||||
fixup: FixupContext,
|
||||
) {
|
||||
if needs_par {
|
||||
self.popen();
|
||||
}
|
||||
self.print_expr(expr);
|
||||
|
||||
// If we are surrounding the whole cond in parentheses, such as:
|
||||
//
|
||||
// if (return Struct {}) {}
|
||||
//
|
||||
// then there is no need for parenthesizing the individual struct
|
||||
// expressions within. On the other hand if the whole cond is not
|
||||
// parenthesized, then print_expr must parenthesize exterior struct
|
||||
// literals.
|
||||
//
|
||||
// if x == (Struct {}) {}
|
||||
//
|
||||
let fixup = FixupContext {
|
||||
parenthesize_exterior_struct_lit: fixup.parenthesize_exterior_struct_lit && !needs_par,
|
||||
};
|
||||
self.print_expr(expr, fixup);
|
||||
|
||||
if needs_par {
|
||||
self.pclose();
|
||||
}
|
||||
@ -111,7 +146,7 @@ impl<'a> State<'a> {
|
||||
self.ibox(0);
|
||||
self.print_block_with_attrs(block, attrs);
|
||||
} else {
|
||||
self.print_expr(&expr.value);
|
||||
self.print_expr(&expr.value, FixupContext::default());
|
||||
}
|
||||
self.end();
|
||||
}
|
||||
@ -119,9 +154,9 @@ impl<'a> State<'a> {
|
||||
fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.word("[");
|
||||
self.print_expr(element);
|
||||
self.print_expr(element, FixupContext::default());
|
||||
self.word_space(";");
|
||||
self.print_expr(&count.value);
|
||||
self.print_expr(&count.value, FixupContext::default());
|
||||
self.word("]");
|
||||
self.end();
|
||||
}
|
||||
@ -161,7 +196,7 @@ impl<'a> State<'a> {
|
||||
self.print_ident(field.ident);
|
||||
self.word_nbsp(":");
|
||||
}
|
||||
self.print_expr(&field.expr);
|
||||
self.print_expr(&field.expr, FixupContext::default());
|
||||
if !is_last || has_rest {
|
||||
self.word_space(",");
|
||||
} else {
|
||||
@ -174,7 +209,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
self.word("..");
|
||||
if let ast::StructRest::Base(expr) = rest {
|
||||
self.print_expr(expr);
|
||||
self.print_expr(expr, FixupContext::default());
|
||||
}
|
||||
self.space();
|
||||
}
|
||||
@ -192,13 +227,13 @@ impl<'a> State<'a> {
|
||||
self.pclose()
|
||||
}
|
||||
|
||||
fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
|
||||
fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
|
||||
let prec = match func.kind {
|
||||
ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
|
||||
_ => parser::PREC_POSTFIX,
|
||||
};
|
||||
|
||||
self.print_expr_maybe_paren(func, prec);
|
||||
self.print_expr_maybe_paren(func, prec, fixup);
|
||||
self.print_call_post(args)
|
||||
}
|
||||
|
||||
@ -207,8 +242,9 @@ impl<'a> State<'a> {
|
||||
segment: &ast::PathSegment,
|
||||
receiver: &ast::Expr,
|
||||
base_args: &[P<ast::Expr>],
|
||||
fixup: FixupContext,
|
||||
) {
|
||||
self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX);
|
||||
self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX, fixup);
|
||||
self.word(".");
|
||||
self.print_ident(segment.ident);
|
||||
if let Some(args) = &segment.args {
|
||||
@ -217,7 +253,13 @@ impl<'a> State<'a> {
|
||||
self.print_call_post(base_args)
|
||||
}
|
||||
|
||||
fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
|
||||
fn print_expr_binary(
|
||||
&mut self,
|
||||
op: ast::BinOp,
|
||||
lhs: &ast::Expr,
|
||||
rhs: &ast::Expr,
|
||||
fixup: FixupContext,
|
||||
) {
|
||||
let assoc_op = AssocOp::from_ast_binop(op.node);
|
||||
let prec = assoc_op.precedence() as i8;
|
||||
let fixity = assoc_op.fixity();
|
||||
@ -253,15 +295,15 @@ impl<'a> State<'a> {
|
||||
_ => left_prec,
|
||||
};
|
||||
|
||||
self.print_expr_maybe_paren(lhs, left_prec);
|
||||
self.print_expr_maybe_paren(lhs, left_prec, fixup);
|
||||
self.space();
|
||||
self.word_space(op.node.as_str());
|
||||
self.print_expr_maybe_paren(rhs, right_prec)
|
||||
self.print_expr_maybe_paren(rhs, right_prec, fixup)
|
||||
}
|
||||
|
||||
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
|
||||
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
|
||||
self.word(op.as_str());
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup)
|
||||
}
|
||||
|
||||
fn print_expr_addr_of(
|
||||
@ -269,6 +311,7 @@ impl<'a> State<'a> {
|
||||
kind: ast::BorrowKind,
|
||||
mutability: ast::Mutability,
|
||||
expr: &ast::Expr,
|
||||
fixup: FixupContext,
|
||||
) {
|
||||
self.word("&");
|
||||
match kind {
|
||||
@ -278,14 +321,19 @@ impl<'a> State<'a> {
|
||||
self.print_mutability(mutability, true);
|
||||
}
|
||||
}
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup)
|
||||
}
|
||||
|
||||
pub(super) fn print_expr(&mut self, expr: &ast::Expr) {
|
||||
self.print_expr_outer_attr_style(expr, true)
|
||||
pub(super) fn print_expr(&mut self, expr: &ast::Expr, fixup: FixupContext) {
|
||||
self.print_expr_outer_attr_style(expr, true, fixup)
|
||||
}
|
||||
|
||||
pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
|
||||
pub(super) fn print_expr_outer_attr_style(
|
||||
&mut self,
|
||||
expr: &ast::Expr,
|
||||
is_inline: bool,
|
||||
fixup: FixupContext,
|
||||
) {
|
||||
self.maybe_print_comment(expr.span.lo());
|
||||
|
||||
let attrs = &expr.attrs;
|
||||
@ -314,19 +362,19 @@ impl<'a> State<'a> {
|
||||
self.print_expr_tup(exprs);
|
||||
}
|
||||
ast::ExprKind::Call(func, args) => {
|
||||
self.print_expr_call(func, args);
|
||||
self.print_expr_call(func, args, fixup);
|
||||
}
|
||||
ast::ExprKind::MethodCall(box ast::MethodCall { seg, receiver, args, .. }) => {
|
||||
self.print_expr_method_call(seg, receiver, args);
|
||||
self.print_expr_method_call(seg, receiver, args, fixup);
|
||||
}
|
||||
ast::ExprKind::Binary(op, lhs, rhs) => {
|
||||
self.print_expr_binary(*op, lhs, rhs);
|
||||
self.print_expr_binary(*op, lhs, rhs, fixup);
|
||||
}
|
||||
ast::ExprKind::Unary(op, expr) => {
|
||||
self.print_expr_unary(*op, expr);
|
||||
self.print_expr_unary(*op, expr, fixup);
|
||||
}
|
||||
ast::ExprKind::AddrOf(k, m, expr) => {
|
||||
self.print_expr_addr_of(*k, *m, expr);
|
||||
self.print_expr_addr_of(*k, *m, expr, fixup);
|
||||
}
|
||||
ast::ExprKind::Lit(token_lit) => {
|
||||
self.print_token_literal(*token_lit, expr.span);
|
||||
@ -337,7 +385,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
ast::ExprKind::Cast(expr, ty) => {
|
||||
let prec = AssocOp::As.precedence() as i8;
|
||||
self.print_expr_maybe_paren(expr, prec);
|
||||
self.print_expr_maybe_paren(expr, prec, fixup);
|
||||
self.space();
|
||||
self.word_space("as");
|
||||
self.print_type(ty);
|
||||
@ -345,7 +393,7 @@ impl<'a> State<'a> {
|
||||
ast::ExprKind::Type(expr, ty) => {
|
||||
self.word("type_ascribe!(");
|
||||
self.ibox(0);
|
||||
self.print_expr(expr);
|
||||
self.print_expr(expr, FixupContext::default());
|
||||
|
||||
self.word(",");
|
||||
self.space_if_not_bol();
|
||||
@ -355,7 +403,7 @@ impl<'a> State<'a> {
|
||||
self.word(")");
|
||||
}
|
||||
ast::ExprKind::Let(pat, scrutinee, _, _) => {
|
||||
self.print_let(pat, scrutinee);
|
||||
self.print_let(pat, scrutinee, fixup);
|
||||
}
|
||||
ast::ExprKind::If(test, blk, elseopt) => self.print_if(test, blk, elseopt.as_deref()),
|
||||
ast::ExprKind::While(test, blk, opt_label) => {
|
||||
@ -428,7 +476,7 @@ impl<'a> State<'a> {
|
||||
|
||||
self.print_fn_params_and_ret(fn_decl, true);
|
||||
self.space();
|
||||
self.print_expr(body);
|
||||
self.print_expr(body, FixupContext::default());
|
||||
self.end(); // need to close a box
|
||||
|
||||
// a box will be closed by print_expr, but we didn't want an overall
|
||||
@ -456,33 +504,33 @@ impl<'a> State<'a> {
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
}
|
||||
ast::ExprKind::Await(expr, _) => {
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
|
||||
self.word(".await");
|
||||
}
|
||||
ast::ExprKind::Assign(lhs, rhs, _) => {
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_maybe_paren(lhs, prec + 1);
|
||||
self.print_expr_maybe_paren(lhs, prec + 1, fixup);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_expr_maybe_paren(rhs, prec);
|
||||
self.print_expr_maybe_paren(rhs, prec, fixup);
|
||||
}
|
||||
ast::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_maybe_paren(lhs, prec + 1);
|
||||
self.print_expr_maybe_paren(lhs, prec + 1, fixup);
|
||||
self.space();
|
||||
self.word(op.node.as_str());
|
||||
self.word_space("=");
|
||||
self.print_expr_maybe_paren(rhs, prec);
|
||||
self.print_expr_maybe_paren(rhs, prec, fixup);
|
||||
}
|
||||
ast::ExprKind::Field(expr, ident) => {
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
|
||||
self.word(".");
|
||||
self.print_ident(*ident);
|
||||
}
|
||||
ast::ExprKind::Index(expr, index, _) => {
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
|
||||
self.word("[");
|
||||
self.print_expr(index);
|
||||
self.print_expr(index, FixupContext::default());
|
||||
self.word("]");
|
||||
}
|
||||
ast::ExprKind::Range(start, end, limits) => {
|
||||
@ -492,14 +540,14 @@ impl<'a> State<'a> {
|
||||
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
|
||||
let fake_prec = AssocOp::LOr.precedence() as i8;
|
||||
if let Some(e) = start {
|
||||
self.print_expr_maybe_paren(e, fake_prec);
|
||||
self.print_expr_maybe_paren(e, fake_prec, fixup);
|
||||
}
|
||||
match limits {
|
||||
ast::RangeLimits::HalfOpen => self.word(".."),
|
||||
ast::RangeLimits::Closed => self.word("..="),
|
||||
}
|
||||
if let Some(e) = end {
|
||||
self.print_expr_maybe_paren(e, fake_prec);
|
||||
self.print_expr_maybe_paren(e, fake_prec, fixup);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Underscore => self.word("_"),
|
||||
@ -513,7 +561,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
if let Some(expr) = opt_expr {
|
||||
self.space();
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Continue(opt_label) => {
|
||||
@ -527,7 +575,7 @@ impl<'a> State<'a> {
|
||||
self.word("return");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Yeet(result) => {
|
||||
@ -536,13 +584,13 @@ impl<'a> State<'a> {
|
||||
self.word("yeet");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Become(result) => {
|
||||
self.word("become");
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(result, parser::PREC_JUMP);
|
||||
self.print_expr_maybe_paren(result, parser::PREC_JUMP, fixup);
|
||||
}
|
||||
ast::ExprKind::InlineAsm(a) => {
|
||||
// FIXME: This should have its own syntax, distinct from a macro invocation.
|
||||
@ -557,7 +605,7 @@ impl<'a> State<'a> {
|
||||
self.word(reconstruct_format_args_template_string(&fmt.template));
|
||||
for arg in fmt.arguments.all_args() {
|
||||
self.word_space(",");
|
||||
self.print_expr(&arg.expr);
|
||||
self.print_expr(&arg.expr, FixupContext::default());
|
||||
}
|
||||
self.end();
|
||||
self.pclose();
|
||||
@ -584,7 +632,7 @@ impl<'a> State<'a> {
|
||||
ast::ExprKind::MacCall(m) => self.print_mac(m),
|
||||
ast::ExprKind::Paren(e) => {
|
||||
self.popen();
|
||||
self.print_expr(e);
|
||||
self.print_expr(e, FixupContext::default());
|
||||
self.pclose();
|
||||
}
|
||||
ast::ExprKind::Yield(e) => {
|
||||
@ -592,11 +640,11 @@ impl<'a> State<'a> {
|
||||
|
||||
if let Some(expr) = e {
|
||||
self.space();
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Try(e) => {
|
||||
self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
|
||||
self.print_expr_maybe_paren(e, parser::PREC_POSTFIX, fixup);
|
||||
self.word("?")
|
||||
}
|
||||
ast::ExprKind::TryBlock(blk) => {
|
||||
@ -628,7 +676,7 @@ impl<'a> State<'a> {
|
||||
self.space();
|
||||
if let Some(e) = &arm.guard {
|
||||
self.word_space("if");
|
||||
self.print_expr(e);
|
||||
self.print_expr(e, FixupContext::default());
|
||||
self.space();
|
||||
}
|
||||
|
||||
@ -652,7 +700,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
_ => {
|
||||
self.end(); // Close the ibox for the pattern.
|
||||
self.print_expr(body);
|
||||
self.print_expr(body, FixupContext::default());
|
||||
self.word(",");
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::pp::Breaks::Inconsistent;
|
||||
use crate::pprust::state::expr::FixupContext;
|
||||
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
|
||||
|
||||
use ast::StaticItem;
|
||||
@ -97,7 +98,7 @@ impl<'a> State<'a> {
|
||||
self.end(); // end the head-ibox
|
||||
if let Some(body) = body {
|
||||
self.word_space("=");
|
||||
self.print_expr(body);
|
||||
self.print_expr(body, FixupContext::default());
|
||||
}
|
||||
self.print_where_clause(&generics.where_clause);
|
||||
self.word(";");
|
||||
@ -514,7 +515,7 @@ impl<'a> State<'a> {
|
||||
if let Some(d) = &v.disr_expr {
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_expr(&d.value)
|
||||
self.print_expr(&d.value, FixupContext::default())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
#![feature(coroutines)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(explicit_tail_calls)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(more_qualified_paths)]
|
||||
#![feature(never_patterns)]
|
||||
#![feature(raw_ref_op)]
|
||||
@ -47,7 +49,7 @@ macro_rules! c1 {
|
||||
// easy to find the cases where the two pretty-printing approaches give
|
||||
// different results.
|
||||
macro_rules! c2 {
|
||||
($frag:ident, [$($tt:tt)*], $s1:literal, $s2:literal) => {
|
||||
($frag:ident, [$($tt:tt)*], $s1:literal, $s2:literal $(,)?) => {
|
||||
assert_ne!($s1, $s2, "should use `c1!` instead");
|
||||
assert_eq!($frag!($($tt)*), $s1);
|
||||
assert_eq!(stringify!($($tt)*), $s2);
|
||||
@ -127,6 +129,23 @@ fn test_expr() {
|
||||
|
||||
// ExprKind::Let
|
||||
c1!(expr, [ if let Some(a) = b { c } else { d } ], "if let Some(a) = b { c } else { d }");
|
||||
c1!(expr, [ if let _ = true && false {} ], "if let _ = true && false {}");
|
||||
c1!(expr, [ if let _ = (true && false) {} ], "if let _ = (true && false) {}");
|
||||
macro_rules! c2_if_let {
|
||||
($expr:expr, $expr_expected:expr, $tokens_expected:expr $(,)?) => {
|
||||
c2!(expr, [ if let _ = $expr {} ], $expr_expected, $tokens_expected);
|
||||
};
|
||||
}
|
||||
c2_if_let!(
|
||||
true && false,
|
||||
"if let _ = (true && false) {}",
|
||||
"if let _ = true && false {}",
|
||||
);
|
||||
c2!(expr,
|
||||
[ match () { _ if let _ = Struct {} => {} } ],
|
||||
"match () { _ if let _ = Struct {} => {} }",
|
||||
"match() { _ if let _ = Struct {} => {} }",
|
||||
);
|
||||
|
||||
// ExprKind::If
|
||||
c1!(expr, [ if true {} ], "if true {}");
|
||||
|
Loading…
Reference in New Issue
Block a user