Skip to content

Commit 3fc0f08

Browse files
authored
Rollup merge of #134833 - dtolnay:leftmostwithdot, r=compiler-errors
Skip parenthesis if `.` makes statement boundary unambiguous There is a rule in the parser that statements and match-arms never end in front of a `.` or `?` token (except when the `.` is really `..` or `..=` or `...`). So some of the leading subexpressions that need parentheses inserted when followed by some other operator like `-` or `+`, do not need parentheses when followed by `.` or `?`. Example: ```rust fn main() { loop {}.to_string() + ""; match () { _ => loop {}.to_string() + "", }; } ``` `-Zunpretty=expanded` before: ```console #![feature(prelude_import)] #[prelude_import] use std::prelude::rust_2021::*; #[macro_use] extern crate std; fn main() { (loop {}).to_string() + ""; match () { _ => (loop {}).to_string() + "", }; } ``` After: ```console #![feature(prelude_import)] #[prelude_import] use std::prelude::rust_2021::*; #[macro_use] extern crate std; fn main() { loop {}.to_string() + ""; match () { _ => loop {}.to_string() + "", }; } ```
2 parents 2d96f2a + e67fe36 commit 3fc0f08

File tree

3 files changed

+35
-11
lines changed

3 files changed

+35
-11
lines changed

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

+17-11
Original file line numberDiff line numberDiff line change
@@ -245,19 +245,21 @@ impl<'a> State<'a> {
245245
base_args: &[P<ast::Expr>],
246246
fixup: FixupContext,
247247
) {
248-
// Unlike in `print_expr_call`, no change to fixup here because
248+
// The fixup here is different than in `print_expr_call` because
249249
// statement boundaries never occur in front of a `.` (or `?`) token.
250250
//
251-
// match () { _ => f }.method();
251+
// Needs parens:
252+
//
253+
// (loop { break x; })();
254+
//
255+
// Does not need parens:
256+
//
257+
// loop { break x; }.method();
252258
//
253-
// Parenthesizing only for precedence and not with regard to statement
254-
// boundaries, `$receiver.method()` can be parsed back as a statement
255-
// containing an expression if and only if `$receiver` can be parsed as
256-
// a statement containing an expression.
257259
self.print_expr_cond_paren(
258260
receiver,
259261
receiver.precedence() < ExprPrecedence::Unambiguous,
260-
fixup,
262+
fixup.leftmost_subexpression_with_dot(),
261263
);
262264

263265
self.word(".");
@@ -503,7 +505,7 @@ impl<'a> State<'a> {
503505
self.print_expr_cond_paren(
504506
expr,
505507
expr.precedence() < ExprPrecedence::Unambiguous,
506-
fixup,
508+
fixup.leftmost_subexpression_with_dot(),
507509
);
508510
self.word_nbsp(".match");
509511
}
@@ -567,7 +569,7 @@ impl<'a> State<'a> {
567569
self.print_expr_cond_paren(
568570
expr,
569571
expr.precedence() < ExprPrecedence::Unambiguous,
570-
fixup,
572+
fixup.leftmost_subexpression_with_dot(),
571573
);
572574
self.word(".await");
573575
}
@@ -606,7 +608,7 @@ impl<'a> State<'a> {
606608
self.print_expr_cond_paren(
607609
expr,
608610
expr.precedence() < ExprPrecedence::Unambiguous,
609-
fixup,
611+
fixup.leftmost_subexpression_with_dot(),
610612
);
611613
self.word(".");
612614
self.print_ident(*ident);
@@ -763,7 +765,11 @@ impl<'a> State<'a> {
763765
}
764766
}
765767
ast::ExprKind::Try(e) => {
766-
self.print_expr_cond_paren(e, e.precedence() < ExprPrecedence::Unambiguous, fixup);
768+
self.print_expr_cond_paren(
769+
e,
770+
e.precedence() < ExprPrecedence::Unambiguous,
771+
fixup.leftmost_subexpression_with_dot(),
772+
);
767773
self.word("?")
768774
}
769775
ast::ExprKind::TryBlock(blk) => {

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

+14
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@ impl FixupContext {
138138
}
139139
}
140140

141+
/// Transform this fixup into the one that should apply when printing a
142+
/// leftmost subexpression followed by a `.` or `?` token, which confer
143+
/// different statement boundary rules compared to other leftmost
144+
/// subexpressions.
145+
pub(crate) fn leftmost_subexpression_with_dot(self) -> Self {
146+
FixupContext {
147+
stmt: self.stmt || self.leftmost_subexpression_in_stmt,
148+
leftmost_subexpression_in_stmt: false,
149+
match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm,
150+
leftmost_subexpression_in_match_arm: false,
151+
..self
152+
}
153+
}
154+
141155
/// Transform this fixup into the one that should apply when printing any
142156
/// subexpression that is neither a leftmost subexpression nor surrounded in
143157
/// delimiters.

tests/ui-fulldeps/pprust-parenthesis-insertion.rs

+4
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ static EXPRS: &[&str] = &[
108108
"{ (match 2 {})() - 1 }",
109109
"{ (match 2 {})[0] - 1 }",
110110
"{ (loop {}) - 1 }",
111+
"match 2 { _ => (loop {}) - 1 }",
112+
// No eager statement boundary if followed by `.` or `?`.
113+
"{ loop {}.to_string() - 1 }",
114+
"match 2 { _ => loop {}.to_string() - 1 }",
111115
// Angle bracket is eagerly parsed as a path's generic argument list.
112116
"(2 as T) < U",
113117
"(2 as T<U>) < V", // FIXME: no parentheses needed.

0 commit comments

Comments
 (0)