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() + "", }; } ```
This commit is contained in:
commit
3fc0f08b89
3 changed files with 35 additions and 11 deletions
|
@ -245,19 +245,21 @@ impl<'a> State<'a> {
|
||||||
base_args: &[P<ast::Expr>],
|
base_args: &[P<ast::Expr>],
|
||||||
fixup: FixupContext,
|
fixup: FixupContext,
|
||||||
) {
|
) {
|
||||||
// Unlike in `print_expr_call`, no change to fixup here because
|
// The fixup here is different than in `print_expr_call` because
|
||||||
// statement boundaries never occur in front of a `.` (or `?`) token.
|
// statement boundaries never occur in front of a `.` (or `?`) token.
|
||||||
//
|
//
|
||||||
// match () { _ => f }.method();
|
// Needs parens:
|
||||||
|
//
|
||||||
|
// (loop { break x; })();
|
||||||
|
//
|
||||||
|
// Does not need parens:
|
||||||
|
//
|
||||||
|
// loop { break x; }.method();
|
||||||
//
|
//
|
||||||
// Parenthesizing only for precedence and not with regard to statement
|
|
||||||
// boundaries, `$receiver.method()` can be parsed back as a statement
|
|
||||||
// containing an expression if and only if `$receiver` can be parsed as
|
|
||||||
// a statement containing an expression.
|
|
||||||
self.print_expr_cond_paren(
|
self.print_expr_cond_paren(
|
||||||
receiver,
|
receiver,
|
||||||
receiver.precedence() < ExprPrecedence::Unambiguous,
|
receiver.precedence() < ExprPrecedence::Unambiguous,
|
||||||
fixup,
|
fixup.leftmost_subexpression_with_dot(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.word(".");
|
self.word(".");
|
||||||
|
@ -503,7 +505,7 @@ impl<'a> State<'a> {
|
||||||
self.print_expr_cond_paren(
|
self.print_expr_cond_paren(
|
||||||
expr,
|
expr,
|
||||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||||
fixup,
|
fixup.leftmost_subexpression_with_dot(),
|
||||||
);
|
);
|
||||||
self.word_nbsp(".match");
|
self.word_nbsp(".match");
|
||||||
}
|
}
|
||||||
|
@ -567,7 +569,7 @@ impl<'a> State<'a> {
|
||||||
self.print_expr_cond_paren(
|
self.print_expr_cond_paren(
|
||||||
expr,
|
expr,
|
||||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||||
fixup,
|
fixup.leftmost_subexpression_with_dot(),
|
||||||
);
|
);
|
||||||
self.word(".await");
|
self.word(".await");
|
||||||
}
|
}
|
||||||
|
@ -606,7 +608,7 @@ impl<'a> State<'a> {
|
||||||
self.print_expr_cond_paren(
|
self.print_expr_cond_paren(
|
||||||
expr,
|
expr,
|
||||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||||
fixup,
|
fixup.leftmost_subexpression_with_dot(),
|
||||||
);
|
);
|
||||||
self.word(".");
|
self.word(".");
|
||||||
self.print_ident(*ident);
|
self.print_ident(*ident);
|
||||||
|
@ -763,7 +765,11 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ExprKind::Try(e) => {
|
ast::ExprKind::Try(e) => {
|
||||||
self.print_expr_cond_paren(e, e.precedence() < ExprPrecedence::Unambiguous, fixup);
|
self.print_expr_cond_paren(
|
||||||
|
e,
|
||||||
|
e.precedence() < ExprPrecedence::Unambiguous,
|
||||||
|
fixup.leftmost_subexpression_with_dot(),
|
||||||
|
);
|
||||||
self.word("?")
|
self.word("?")
|
||||||
}
|
}
|
||||||
ast::ExprKind::TryBlock(blk) => {
|
ast::ExprKind::TryBlock(blk) => {
|
||||||
|
|
|
@ -138,6 +138,20 @@ impl FixupContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transform this fixup into the one that should apply when printing a
|
||||||
|
/// leftmost subexpression followed by a `.` or `?` token, which confer
|
||||||
|
/// different statement boundary rules compared to other leftmost
|
||||||
|
/// subexpressions.
|
||||||
|
pub(crate) fn leftmost_subexpression_with_dot(self) -> Self {
|
||||||
|
FixupContext {
|
||||||
|
stmt: self.stmt || self.leftmost_subexpression_in_stmt,
|
||||||
|
leftmost_subexpression_in_stmt: false,
|
||||||
|
match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm,
|
||||||
|
leftmost_subexpression_in_match_arm: false,
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Transform this fixup into the one that should apply when printing any
|
/// Transform this fixup into the one that should apply when printing any
|
||||||
/// subexpression that is neither a leftmost subexpression nor surrounded in
|
/// subexpression that is neither a leftmost subexpression nor surrounded in
|
||||||
/// delimiters.
|
/// delimiters.
|
||||||
|
|
|
@ -108,6 +108,10 @@ static EXPRS: &[&str] = &[
|
||||||
"{ (match 2 {})() - 1 }",
|
"{ (match 2 {})() - 1 }",
|
||||||
"{ (match 2 {})[0] - 1 }",
|
"{ (match 2 {})[0] - 1 }",
|
||||||
"{ (loop {}) - 1 }",
|
"{ (loop {}) - 1 }",
|
||||||
|
"match 2 { _ => (loop {}) - 1 }",
|
||||||
|
// No eager statement boundary if followed by `.` or `?`.
|
||||||
|
"{ loop {}.to_string() - 1 }",
|
||||||
|
"match 2 { _ => loop {}.to_string() - 1 }",
|
||||||
// Angle bracket is eagerly parsed as a path's generic argument list.
|
// Angle bracket is eagerly parsed as a path's generic argument list.
|
||||||
"(2 as T) < U",
|
"(2 as T) < U",
|
||||||
"(2 as T<U>) < V", // FIXME: no parentheses needed.
|
"(2 as T<U>) < V", // FIXME: no parentheses needed.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue