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

Fix parenthesization of chained comparisons by pretty-printer #134600

Merged
merged 2 commits into from
Dec 21, 2024

Conversation

dtolnay
Copy link
Member

@dtolnay dtolnay commented Dec 21, 2024

Example:

macro_rules! repro {
    () => {
        1 < 2
    };
}

fn main() {
    let _ = repro!() == false;
}

Previously -Zunpretty=expanded would pretty-print this syntactically invalid output: fn main() { let _ = 1 < 2 == false; }

error: comparison operators cannot be chained
 --> <anon>:8:23
  |
8 | fn main() { let _ = 1 < 2 == false; }
  |                       ^   ^^
  |
help: parenthesize the comparison
  |
8 | fn main() { let _ = (1 < 2) == false; }
  |                     +     +

With the fix, it will print fn main() { let _ = (1 < 2) == false; }.

Making -Zunpretty=expanded consistently produce syntactically valid Rust output is important because that is what makes it possible for cargo expand to format and perform filtering on the expanded code.

Review notes

According to rg '\.fixity\(\)' compiler/ the fixity function is called only 3 places:

  • let (mut left_needs_paren, right_needs_paren) = match assoc_op.fixity() {
    Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
    Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec),
    Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec),
    };

  • let (mut left_needs_paren, right_needs_paren) = match assoc_op.fixity() {
    Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
    Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec),
    Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec),
    };

  • let fixity = op.fixity();
    let min_prec = match fixity {
    Fixity::Right => Bound::Included(prec),
    Fixity::Left => Bound::Excluded(prec),
    // We currently have no non-associative operators that are not handled above by
    // the special cases. The code is here only for future convenience.
    Fixity::None => Bound::Excluded(prec),
    };

The 2 pretty printers definitely want to treat comparisons using Fixity::None. That's the whole bug being fixed. Meanwhile, the parser's Fixity::None codepath is previously unreachable as indicated by the comment, so as long as Fixity::None here behaves exactly the way that Fixity::Left used to behave, you can tell that this PR definitely does not constitute any behavior change for the parser.

My guess for why comparison operators were set to Fixity::Left instead of Fixity::None is that it's a very old workaround for giving a good chained comparisons diagnostic (like what I pasted above). Nowadays that is handled by a different dedicated codepath.

@dtolnay dtolnay added the A-pretty Area: Pretty printing (including `-Z unpretty`) label Dec 21, 2024
@rustbot
Copy link
Collaborator

rustbot commented Dec 21, 2024

r? @oli-obk

rustbot has assigned @oli-obk.
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 21, 2024
@oli-obk
Copy link
Contributor

oli-obk commented Dec 21, 2024

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Dec 21, 2024

📌 Commit fe65e88 has been approved by oli-obk

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 21, 2024
bors added a commit to rust-lang-ci/rust that referenced this pull request Dec 21, 2024
Rollup of 7 pull requests

Successful merges:

 - rust-lang#133087 (Detect missing `.` in method chain in `let` bindings and statements)
 - rust-lang#134575 (Handle `DropKind::ForLint` in coroutines correctly)
 - rust-lang#134576 (Improve prose around basic examples of Iter and IterMut)
 - rust-lang#134577 (Improve prose around `as_slice` example of Iter)
 - rust-lang#134579 (Improve prose around into_slice example of IterMut)
 - rust-lang#134593 (Less unwrap() in documentation)
 - rust-lang#134600 (Fix parenthesization of chained comparisons by pretty-printer)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit ea8bc3b into rust-lang:master Dec 21, 2024
6 checks passed
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Dec 21, 2024
Rollup merge of rust-lang#134600 - dtolnay:chainedcomparison, r=oli-obk

Fix parenthesization of chained comparisons by pretty-printer

Example:

```rust
macro_rules! repro {
    () => {
        1 < 2
    };
}

fn main() {
    let _ = repro!() == false;
}
```

Previously `-Zunpretty=expanded` would pretty-print this syntactically invalid output: `fn main() { let _ = 1 < 2 == false; }`

```console
error: comparison operators cannot be chained
 --> <anon>:8:23
  |
8 | fn main() { let _ = 1 < 2 == false; }
  |                       ^   ^^
  |
help: parenthesize the comparison
  |
8 | fn main() { let _ = (1 < 2) == false; }
  |                     +     +
```

With the fix, it will print `fn main() { let _ = (1 < 2) == false; }`.

Making `-Zunpretty=expanded` consistently produce syntactically valid Rust output is important because that is what makes it possible for `cargo expand` to format and perform filtering on the expanded code.

## Review notes

According to `rg '\.fixity\(\)' compiler/` the `fixity` function is called only 3 places:

- https://github.com/rust-lang/rust/blob/13170cd787cb733ed24842ee825bcbd98dc01476/compiler/rustc_ast_pretty/src/pprust/state/expr.rs#L283-L287

- https://github.com/rust-lang/rust/blob/13170cd787cb733ed24842ee825bcbd98dc01476/compiler/rustc_hir_pretty/src/lib.rs#L1295-L1299

- https://github.com/rust-lang/rust/blob/13170cd787cb733ed24842ee825bcbd98dc01476/compiler/rustc_parse/src/parser/expr.rs#L282-L289

The 2 pretty printers definitely want to treat comparisons using `Fixity::None`. That's the whole bug being fixed. Meanwhile, the parser's `Fixity::None` codepath is previously unreachable as indicated by the comment, so as long as `Fixity::None` here behaves exactly the way that `Fixity::Left` used to behave, you can tell that this PR definitely does not constitute any behavior change for the parser.

My guess for why comparison operators were set to `Fixity::Left` instead of `Fixity::None` is that it's a very old workaround for giving a good chained comparisons diagnostic (like what I pasted above). Nowadays that is handled by a different dedicated codepath.
@rustbot rustbot added this to the 1.85.0 milestone Dec 21, 2024
@dtolnay dtolnay deleted the chainedcomparison branch December 21, 2024 10:10
@dtolnay dtolnay removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Jan 14, 2025
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`) 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.

4 participants