Optimize redundant bool check#7176
Conversation
📝 WalkthroughWalkthroughIntroduce targeted short-circuit jump threading in boolean-op compilation by adding Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Code has been automatically formatted The code in this PR has been formatted using:
git pull origin optimize-redundant-bool-check |
0fe34f5 to
d28d1cb
Compare
There was a problem hiding this comment.
Pull request overview
This pull request implements an optimization for nested boolean operations to avoid redundant __bool__ calls, matching CPython's behavior. The optimization uses jump threading to allow inner boolean operations with opposite operators to short-circuit directly to a cleanup block, bypassing the outer operation's boolean conversion test.
Changes:
- Added jump threading optimization for nested BoolOps with opposite operators (e.g.,
(x and y) or z) - Refactored
compile_bool_opto support optional short-circuit target override - Added test case validating that
__bool__is called only once forTest() and False or False
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
extra_tests/snippets/builtin_bool.py |
Added test case to verify __bool__ is called only once in nested BoolOps |
crates/codegen/src/snapshots/rustpython_codegen__compile__tests__nested_bool_op.snap |
Snapshot of optimized bytecode for the new test case |
crates/codegen/src/compile.rs |
Implemented jump threading optimization and refactored BoolOp compilation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
extra_tests/snippets/builtin_bool.py
Outdated
| with assert_raises(TypeError): | ||
| bool(TestLenThrowError()) | ||
|
|
||
| # Issue #3567: nested BoolOps should not call __bool__ redundantly |
There was a problem hiding this comment.
this is more like short-circuit than bool. we have syntax_short_circuit_bool.py for that
There was a problem hiding this comment.
I didn't know existence of the file. I moved and simplified the testcase in c1e7986 commit.
# Issue #3567: nested BoolOps should not call __bool__ redundantly
ExplodingBool(False) and False or False…ps to avoid redundant __bool__ calls When a nested BoolOp has the opposite operator (e.g., `And` inside `Or`), the inner BoolOp's short-circuit exits are redirected to skip the outer BoolOp's redundant truth test. This avoids calling `__bool__()` twice on the same value (e.g., `Test() and False or False` previously called `Test().__bool__()` twice instead of once). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ith compile_bool_op_inner Reduce code duplication by: - Extracting the repeated Copy + conditional jump pattern into emit_short_circuit_test - Merging compile_bool_op and compile_bool_op_inner into a single compile_bool_op_with_target with an optional short_circuit_target parameter - Keeping compile_bool_op as a thin wrapper for the public interface Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
c1e7986 to
e68c018
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
extra_tests/snippets/syntax_short_circuit_bool.py (1)
34-36: Consider asserting the expression result for completeness.The
ExplodingBoolmechanism correctly validates that__bool__is invoked only once. However, asserting the expected result value would also guard against changes in evaluation semantics:-ExplodingBool(False) and False or False +assert (ExplodingBool(False) and False or False) == FalseThis matches the style of line 27 (
assert ExplodingBool(True) or False) and makes the test self-documenting.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@extra_tests/snippets/syntax_short_circuit_bool.py` around lines 34 - 36, Add an assertion that verifies the boolean expression's result (like the existing `assert ExplodingBool(True) or False` at line 27) so the test both checks `ExplodingBool.__bool__` is called only once and documents expected semantics; specifically, assert that the expression `ExplodingBool(False) and False or False` evaluates to False (use the same `ExplodingBool` symbol and the same assert style as the earlier test).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@extra_tests/snippets/syntax_short_circuit_bool.py`:
- Around line 34-36: Add an assertion that verifies the boolean expression's
result (like the existing `assert ExplodingBool(True) or False` at line 27) so
the test both checks `ExplodingBool.__bool__` is called only once and documents
expected semantics; specifically, assert that the expression
`ExplodingBool(False) and False or False` evaluates to False (use the same
`ExplodingBool` symbol and the same assert style as the earlier test).
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@extra_tests/snippets/syntax_short_circuit_bool.py`:
- Around line 34-36: The assert currently forces an AssertionError because the
expression "ExplodingBool(False) and False or False" is falsy; change the test
to not assert on the falsy expression—either remove the leading "assert" so the
expression is merely evaluated (matching the pattern used elsewhere) or flip it
to a truthy case (e.g., use ExplodingBool(True) and True or True) so the test
can exercise redundant __bool__ avoidance; locate the expression using the
ExplodingBool symbol and update accordingly.
|
As a note about d6e48ff, |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
extra_tests/snippets/syntax_short_circuit_bool.py (1)
34-36: Good fix — previousasserton a bare falsy expression has been resolved.The
== Falsecomparison correctly makes this assertion pass when the optimization works (single__bool__call), while theExplodingBoolinternal assert still guards against redundant invocations. Nice.One minor nit from flake8 (E712): prefer
is Falseover== False.Suggested tweak
-assert (ExplodingBool(False) and False or False) == False +assert (ExplodingBool(False) and False or False) is False🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@extra_tests/snippets/syntax_short_circuit_bool.py` around lines 34 - 36, Replace the equality comparison with an identity check to satisfy flake8 E712: in the test assertion using ExplodingBool (the expression "(ExplodingBool(False) and False or False) == False") change the comparator to "is False" so the assertion becomes "(ExplodingBool(False) and False or False) is False", preserving the single-__bool__ behavior while addressing the lint warning.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@extra_tests/snippets/syntax_short_circuit_bool.py`:
- Around line 34-36: Replace the equality comparison with an identity check to
satisfy flake8 E712: in the test assertion using ExplodingBool (the expression
"(ExplodingBool(False) and False or False) == False") change the comparator to
"is False" so the assertion becomes "(ExplodingBool(False) and False or False)
is False", preserving the single-__bool__ behavior while addressing the lint
warning.
Closes #3567
Summary by CodeRabbit
Bug Fixes
Tests