Skip to content

Commit 3a0562b

Browse files
authored
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.
2 parents ea82b11 + 8997215 commit 3a0562b

File tree

4 files changed

+174
-77
lines changed

4 files changed

+174
-77
lines changed

compiler/rustc_ast_pretty/src/pprust/state.rs

+51-22
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod item;
77

88
use crate::pp::Breaks::{Consistent, Inconsistent};
99
use crate::pp::{self, Breaks};
10+
use crate::pprust::state::expr::FixupContext;
1011
use rustc_ast::attr::AttrIdGenerator;
1112
use rustc_ast::ptr::P;
1213
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
811812
}
812813

813814
fn expr_to_string(&self, e: &ast::Expr) -> String {
814-
Self::to_string(|s| s.print_expr(e))
815+
Self::to_string(|s| s.print_expr(e, FixupContext::default()))
815816
}
816817

817818
fn meta_item_lit_to_string(&self, lit: &ast::MetaItemLit) -> String {
@@ -916,7 +917,7 @@ impl<'a> State<'a> {
916917
}
917918

918919
fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
919-
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
920+
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e, FixupContext::default()), |e| e.span)
920921
}
921922

922923
pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
@@ -953,7 +954,7 @@ impl<'a> State<'a> {
953954
match generic_arg {
954955
GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
955956
GenericArg::Type(ty) => self.print_type(ty),
956-
GenericArg::Const(ct) => self.print_expr(&ct.value),
957+
GenericArg::Const(ct) => self.print_expr(&ct.value, FixupContext::default()),
957958
}
958959
}
959960

@@ -1020,12 +1021,12 @@ impl<'a> State<'a> {
10201021
self.word("[");
10211022
self.print_type(ty);
10221023
self.word("; ");
1023-
self.print_expr(&length.value);
1024+
self.print_expr(&length.value, FixupContext::default());
10241025
self.word("]");
10251026
}
10261027
ast::TyKind::Typeof(e) => {
10271028
self.word("typeof(");
1028-
self.print_expr(&e.value);
1029+
self.print_expr(&e.value, FixupContext::default());
10291030
self.word(")");
10301031
}
10311032
ast::TyKind::Infer => {
@@ -1081,7 +1082,7 @@ impl<'a> State<'a> {
10811082
if let Some((init, els)) = loc.kind.init_else_opt() {
10821083
self.nbsp();
10831084
self.word_space("=");
1084-
self.print_expr(init);
1085+
self.print_expr(init, FixupContext::default());
10851086
if let Some(els) = els {
10861087
self.cbox(INDENT_UNIT);
10871088
self.ibox(INDENT_UNIT);
@@ -1095,14 +1096,14 @@ impl<'a> State<'a> {
10951096
ast::StmtKind::Item(item) => self.print_item(item),
10961097
ast::StmtKind::Expr(expr) => {
10971098
self.space_if_not_bol();
1098-
self.print_expr_outer_attr_style(expr, false);
1099+
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
10991100
if classify::expr_requires_semi_to_be_stmt(expr) {
11001101
self.word(";");
11011102
}
11021103
}
11031104
ast::StmtKind::Semi(expr) => {
11041105
self.space_if_not_bol();
1105-
self.print_expr_outer_attr_style(expr, false);
1106+
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
11061107
self.word(";");
11071108
}
11081109
ast::StmtKind::Empty => {
@@ -1154,7 +1155,7 @@ impl<'a> State<'a> {
11541155
ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => {
11551156
self.maybe_print_comment(st.span.lo());
11561157
self.space_if_not_bol();
1157-
self.print_expr_outer_attr_style(expr, false);
1158+
self.print_expr_outer_attr_style(expr, false, FixupContext::default());
11581159
self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
11591160
}
11601161
_ => self.print_stmt(st),
@@ -1167,13 +1168,41 @@ impl<'a> State<'a> {
11671168
}
11681169

11691170
/// Print a `let pat = expr` expression.
1170-
fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) {
1171+
///
1172+
/// Parentheses are inserted surrounding `expr` if a round-trip through the
1173+
/// parser would otherwise work out the wrong way in a condition position.
1174+
///
1175+
/// For example each of the following would mean the wrong thing without
1176+
/// parentheses.
1177+
///
1178+
/// ```ignore (illustrative)
1179+
/// if let _ = (Struct {}) {}
1180+
///
1181+
/// if let _ = (true && false) {}
1182+
/// ```
1183+
///
1184+
/// In a match guard, the second case still requires parens, but the first
1185+
/// case no longer does because anything until `=>` is considered part of
1186+
/// the match guard expression. Parsing of the expression is not terminated
1187+
/// by `{` in that position.
1188+
///
1189+
/// ```ignore (illustrative)
1190+
/// match () {
1191+
/// () if let _ = Struct {} => {}
1192+
/// () if let _ = (true && false) => {}
1193+
/// }
1194+
/// ```
1195+
fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, fixup: FixupContext) {
11711196
self.word("let ");
11721197
self.print_pat(pat);
11731198
self.space();
11741199
self.word_space("=");
1175-
let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order());
1176-
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
1200+
self.print_expr_cond_paren(
1201+
expr,
1202+
fixup.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
1203+
|| parser::needs_par_as_let_scrutinee(expr.precedence().order()),
1204+
FixupContext::default(),
1205+
);
11771206
}
11781207

11791208
fn print_mac(&mut self, m: &ast::MacCall) {
@@ -1220,7 +1249,7 @@ impl<'a> State<'a> {
12201249
print_reg_or_class(s, reg);
12211250
s.pclose();
12221251
s.space();
1223-
s.print_expr(expr);
1252+
s.print_expr(expr, FixupContext::default());
12241253
}
12251254
InlineAsmOperand::Out { reg, late, expr } => {
12261255
s.word(if *late { "lateout" } else { "out" });
@@ -1229,7 +1258,7 @@ impl<'a> State<'a> {
12291258
s.pclose();
12301259
s.space();
12311260
match expr {
1232-
Some(expr) => s.print_expr(expr),
1261+
Some(expr) => s.print_expr(expr, FixupContext::default()),
12331262
None => s.word("_"),
12341263
}
12351264
}
@@ -1239,26 +1268,26 @@ impl<'a> State<'a> {
12391268
print_reg_or_class(s, reg);
12401269
s.pclose();
12411270
s.space();
1242-
s.print_expr(expr);
1271+
s.print_expr(expr, FixupContext::default());
12431272
}
12441273
InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
12451274
s.word(if *late { "inlateout" } else { "inout" });
12461275
s.popen();
12471276
print_reg_or_class(s, reg);
12481277
s.pclose();
12491278
s.space();
1250-
s.print_expr(in_expr);
1279+
s.print_expr(in_expr, FixupContext::default());
12511280
s.space();
12521281
s.word_space("=>");
12531282
match out_expr {
1254-
Some(out_expr) => s.print_expr(out_expr),
1283+
Some(out_expr) => s.print_expr(out_expr, FixupContext::default()),
12551284
None => s.word("_"),
12561285
}
12571286
}
12581287
InlineAsmOperand::Const { anon_const } => {
12591288
s.word("const");
12601289
s.space();
1261-
s.print_expr(&anon_const.value);
1290+
s.print_expr(&anon_const.value, FixupContext::default());
12621291
}
12631292
InlineAsmOperand::Sym { sym } => {
12641293
s.word("sym");
@@ -1452,18 +1481,18 @@ impl<'a> State<'a> {
14521481
self.print_pat(inner);
14531482
}
14541483
}
1455-
PatKind::Lit(e) => self.print_expr(e),
1484+
PatKind::Lit(e) => self.print_expr(e, FixupContext::default()),
14561485
PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => {
14571486
if let Some(e) = begin {
1458-
self.print_expr(e);
1487+
self.print_expr(e, FixupContext::default());
14591488
}
14601489
match end_kind {
14611490
RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."),
14621491
RangeEnd::Included(RangeSyntax::DotDotEq) => self.word("..="),
14631492
RangeEnd::Excluded => self.word(".."),
14641493
}
14651494
if let Some(e) = end {
1466-
self.print_expr(e);
1495+
self.print_expr(e, FixupContext::default());
14671496
}
14681497
}
14691498
PatKind::Slice(elts) => {
@@ -1617,7 +1646,7 @@ impl<'a> State<'a> {
16171646
if let Some(default) = default {
16181647
s.space();
16191648
s.word_space("=");
1620-
s.print_expr(&default.value);
1649+
s.print_expr(&default.value, FixupContext::default());
16211650
}
16221651
}
16231652
}

0 commit comments

Comments
 (0)