Skip to content

Use the common OperatorPrecedence for the parser #16747

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

Merged
merged 3 commits into from
Mar 21, 2025

Conversation

junhsonjb
Copy link
Contributor

@junhsonjb junhsonjb commented Mar 14, 2025

Summary

This change continues to resolve #16071 (and continues the work started in #16162). Specifically, this PR changes the code in the parser so that it uses the OperatorPrecedence struct from ruff_python_ast instead of its own version. This is part of an effort to get rid of the redundant definitions of OperatorPrecedence throughout the codebase.

Note that this PR only makes this change for ruff_python_parser -- we still want to make a similar change for the formatter (namely the OperatorPrecedence defined in the expression part of the formatter, the pattern one is different). I separated the work to keep the PRs small and easily reviewable.

Test Plan

Because this is an internal change, I didn't add any additional tests. Existing tests do pass.

Copy link
Contributor

github-actions bot commented Mar 14, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

@MichaReiser MichaReiser added internal An internal refactor or improvement parser Related to the parser labels Mar 14, 2025
@dhruvmanila
Copy link
Member

It's worth noting however, that this change did have a slight impact on snapshot results. The removed defintion of OperatorPrecedence had separate enum variants BitOr and BitXor. This differs from the newer version of OperatorPrecedence which keeps both operators on the same level with BitXorOr.

Why does the newer version does not have them as separate variants? As per the documentation on operator precedence, they should be separate.

It can be seen in the AST printed by the CPython parser that the overall expression is indeed a bitwise-or expression and not a bitwise-xor expression as is in the updated snapshot:

echo "1 | 2 & 3 ^ 4 + 5 @ 6 << 7 // 8 >> 9" | uv run python -m ast -
Module(
   body=[
      Expr(
         value=BinOp(
            left=Constant(value=1),
            op=BitOr(),
            right=BinOp(
               left=BinOp(
                  left=Constant(value=2),
                  op=BitAnd(),
                  right=Constant(value=3)),
               op=BitXor(),
               right=BinOp(
                  left=BinOp(
                     left=BinOp(
                        left=Constant(value=4),
                        op=Add(),
                        right=BinOp(
                           left=Constant(value=5),
                           op=MatMult(),
                           right=Constant(value=6))),
                     op=LShift(),
                     right=BinOp(
                        left=Constant(value=7),
                        op=FloorDiv(),
                        right=Constant(value=8))),
                  op=RShift(),
                  right=Constant(value=9)))))])

This looks like a bug to me and should be fixed first.

@junhsonjb
Copy link
Contributor Author

@dhruvmanila You make a great point, I'll get started on a fix for this! I am curious, though, about the motivation for giving BitXor and BitOr the same precedence in the first place. The code that does this was originally in the linter crate -- do you know if was there a reason for doing that?

@junhsonjb
Copy link
Contributor Author

@dhruvmanila @MichaReiser The patch for the requested bug-fix is in #16844 (pinging because the PR didn't automatically add reviewers so I wanted to make sure it doesn't get buried 🙂)

dhruvmanila pushed a commit that referenced this pull request Mar 20, 2025
## Summary

This change follows up on the bug-fix requested in #16747 --
`ruff_python_ast::OperatorPrecedence` had an enum variant, `BitXorOr`,
which which gave the same precedence to the `|` and `^` operators. This
goes against [Python's documentation for operator
precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence),
so this PR changes the code so that it's correct.

This is part of the overall effort to unify redundant definitions of
`OperatorPrecedence` throughout the codebase (#16071)

## Test Plan

Because this is an internal change, I only ran existing tests to ensure
nothing was broken.
@dhruvmanila
Copy link
Member

@junhsonjb Thanks for fixing the highlighted issue! Can you rebase it on latest main? I think otherwise the PR looks good.

@junhsonjb junhsonjb force-pushed the jjb-ast-precedence-in-parser branch from b6f6e50 to b849789 Compare March 20, 2025 15:10
@MichaReiser
Copy link
Member

Looks good to me. I'll leave the final review to @dhruvmanila because he's our parser expert.

Copy link
Member

@dhruvmanila dhruvmanila left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@dhruvmanila dhruvmanila changed the title [internal] Use ruff_python_ast::OperatorPrecedence in Parser (ruff_python_parser) Use the common OperatorPrecedence for the parser Mar 21, 2025
@dhruvmanila
Copy link
Member

I removed the now fixed issue about bitwise precedence from the PR description as it's used for the commit message as well.

@dhruvmanila dhruvmanila merged commit 2a4d835 into astral-sh:main Mar 21, 2025
22 checks passed
dcreager added a commit that referenced this pull request Mar 21, 2025
* main: (26 commits)
  Use the common `OperatorPrecedence` for the parser (#16747)
  [red-knot] Check subtype relation between callable types (#16804)
  [red-knot] Check whether two callable types are equivalent (#16698)
  [red-knot] Ban most `Type::Instance` types in type expressions (#16872)
  Special-case value-expression inference of special form subscriptions (#16877)
  [syntax-errors] Fix star annotation before Python 3.11 (#16878)
  Recognize `SyntaxError:` as an error code for ecosystem checks (#16879)
  [red-knot] add test cases result in false positive errors (#16856)
  Bump 0.11.1 (#16871)
  Allow discovery of venv in VIRTUAL_ENV env variable (#16853)
  Split git pathspecs in change determination onto separate lines (#16869)
  Use the correct base commit for change determination (#16857)
  Separate `BitXorOr` into `BitXor` and `BitOr` precedence (#16844)
  Server: Allow `FixAll` action in presence of version-specific syntax errors (#16848)
  [`refurb`] Fix starred expressions fix (`FURB161`) (#16550)
  [`flake8-executable`] Add pytest and uv run to help message for `shebang-missing-python` (`EXE003`) (#16855)
  Show more precise messages in invalid type expressions (#16850)
  [`flake8-executables`] Allow `uv run` in shebang line for `shebang-missing-python` (`EXE003`) (#16849)
  Add `--exit-non-zero-on-format` (#16009)
  [red-knot] Ban list literals in most contexts in type expressions (#16847)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
internal An internal refactor or improvement parser Related to the parser
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unify OperatorPrecedence enums
3 participants