Fix as_string() dropping parentheses around a comparison that is the left operand of another comparison - #3239
Open
nikonikolov wants to merge 1 commit into
Open
Conversation
…operand of another comparison Comparisons chain rather than associate, but AsStringVisitor._should_wrap treated Compare like a left-associative operator, so the left operand was never parenthesized: '(a is None) == (b is None)' round-tripped to 'a is None == (b is None)', which Python parses as the semantically different chained comparison '(a is None) and (None == (b is None))'. Comparators on the right only kept their parentheses because is_left=False happened to disagree with the assumed left-associativity. At equal precedence, a Compare operand of a Compare is now always wrapped, on either side. Genuine chained comparisons are unaffected: their operands sit below Compare precedence and take the existing paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nikonikolov
force-pushed
the
fix-nested-compare-left-parens
branch
from
August 19, 2026 20:26
eb85057 to
0fd0b5f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Type of Changes
Description
as_string()dropped the parentheses around a comparison used as the leftoperand of another comparison:
The unparsed line is a chained comparison —
(a is None) and (None == (b is None))— a semantically different expression.
AsStringVisitor._should_wraphandled equal precedence purely via associativity, andCompareused the default "left associative", so a leftCompareoperand was neverwrapped. But comparisons chain rather than associate, so a
Compareoperand of aComparemust be parenthesized on either side (the right side was only wrappedbecause
is_left=Falsehappened to disagree with the assumed left-associativity).At equal precedence, a
Compareoperand of aCompareis now always wrapped.Genuine chained comparisons (
a < b < c) are unaffected: their operands sit belowCompareprecedence and take the existing paths.Regression tests: exact-text round-trips in
AsStringTest.test_nested_compare_as_left_operand,plus new lines in
tests/testdata/python3/data/operator_precedence.py(both fail withoutthe fix).
🤖 Generated with Claude Code