Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Precedence improvements: closures and jumps #133782

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

dtolnay
Copy link
Member

@dtolnay dtolnay commented Dec 3, 2024

This PR fixes some cases where rustc's pretty printers would redundantly parenthesize expressions that didn't need it.

BeforeAfter
return (|x: i32| x)return |x: i32| x
(|| -> &mut () { std::process::abort() }).clone()|| -> &mut () { std::process::abort() }.clone()
(continue) + 1continue + 1

Tested by echo "fn main() { let _ = $AFTER; }" | rustc -Zunpretty=expanded /dev/stdin.

The pretty-printer aims to render the syntax tree as it actually exists in rustc, as faithfully as possible, in Rust syntax. It can insert parentheses where forced by Rust's grammar in order to preserve the meaning of a macro-generated syntax tree, for example in the case of a * $rhs where $rhs is b + c. But for any expression parsed from source code, without a macro involved, there should never be a reason for inserting additional parentheses not present in the original.

For closures and jumps (return, break, continue, yield, do yeet, become) the unneeded parentheses came from the precedence of some of these expressions being misidentified. In the same order as the table above:

  • Jumps and closures are supposed to have equal precedence. The Rust Reference says so, and in Syn they do. There is no Rust syntax that would require making a precedence distinction between jumps and closures. But in rustc these were previously 2 distinct levels with the closure being lower, hence the parentheses around a closure inside a jump (but not a jump inside a closure).

  • When a closure is written with an explicit return type, the grammar requires that the closure body consists of exactly one block expression, not any other arbitrary expression as usual for closures. Parsing of the closure body does not continue after the block expression. So in || { 0 }.clone() the clone is inside the closure body and applies to { 0 }, whereas in || -> _ { 0 }.clone() the clone is outside and applies to the closure as a whole.

  • Continue never needs parentheses. It was previously marked as having the lowest possible precedence but it should have been the highest, next to paths and loops and function calls, not next to jumps.

@rustbot
Copy link
Collaborator

rustbot commented Dec 3, 2024

r? @spastorino

rustbot has assigned @spastorino.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 3, 2024
@dtolnay dtolnay added the A-pretty Area: Pretty printing (including `-Z unpretty`) label Dec 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-pretty Area: Pretty printing (including `-Z unpretty`) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants