Skip to content

Commit

Permalink
Unrolled build for rust-lang#134833
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#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() + "", };
}
```
  • Loading branch information
rust-timer authored Dec 28, 2024
2 parents ecc1899 + e67fe36 commit 4a8c035
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 11 deletions.
28 changes: 17 additions & 11 deletions compiler/rustc_ast_pretty/src/pprust/state/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,19 +245,21 @@ impl<'a> State<'a> {
base_args: &[P<ast::Expr>],
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.
//
// 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(
receiver,
receiver.precedence() < ExprPrecedence::Unambiguous,
fixup,
fixup.leftmost_subexpression_with_dot(),
);

self.word(".");
Expand Down Expand Up @@ -503,7 +505,7 @@ impl<'a> State<'a> {
self.print_expr_cond_paren(
expr,
expr.precedence() < ExprPrecedence::Unambiguous,
fixup,
fixup.leftmost_subexpression_with_dot(),
);
self.word_nbsp(".match");
}
Expand Down Expand Up @@ -567,7 +569,7 @@ impl<'a> State<'a> {
self.print_expr_cond_paren(
expr,
expr.precedence() < ExprPrecedence::Unambiguous,
fixup,
fixup.leftmost_subexpression_with_dot(),
);
self.word(".await");
}
Expand Down Expand Up @@ -606,7 +608,7 @@ impl<'a> State<'a> {
self.print_expr_cond_paren(
expr,
expr.precedence() < ExprPrecedence::Unambiguous,
fixup,
fixup.leftmost_subexpression_with_dot(),
);
self.word(".");
self.print_ident(*ident);
Expand Down Expand Up @@ -763,7 +765,11 @@ impl<'a> State<'a> {
}
}
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("?")
}
ast::ExprKind::TryBlock(blk) => {
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
/// subexpression that is neither a leftmost subexpression nor surrounded in
/// delimiters.
Expand Down
4 changes: 4 additions & 0 deletions tests/ui-fulldeps/pprust-parenthesis-insertion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ static EXPRS: &[&str] = &[
"{ (match 2 {})() - 1 }",
"{ (match 2 {})[0] - 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.
"(2 as T) < U",
"(2 as T<U>) < V", // FIXME: no parentheses needed.
Expand Down

0 comments on commit 4a8c035

Please sign in to comment.