Skip to content

[CodeQuality] Preserve parentheses around low-precedence operands in LogicalToBooleanRector#8155

Merged
TomasVotruba merged 1 commit into
mainfrom
fix-logical-to-boolean-precedence-parens
Jul 8, 2026
Merged

[CodeQuality] Preserve parentheses around low-precedence operands in LogicalToBooleanRector#8155
TomasVotruba merged 1 commit into
mainfrom
fix-logical-to-boolean-precedence-parens

Conversation

@TomasVotruba

Copy link
Copy Markdown
Member

Fixes rectorphp/rector#9800

LogicalToBooleanRector swaps and/or for &&/||. The boolean operators bind tighter than the logical ones, so any operand whose top-level operator sits between them in precedence lost its parentheses on reprint — silently changing semantics.

Affected operand types: ternary, elvis (?:), compound assignments (+=, ??=, ...), print, yield, yield from.

Before (broken)

(true ? 42 : 0) and true;   // → true, but printed as: true ? 42 : 0 && true;   → 42
($x += 42) and true;        // $x = 42, but printed as: $x += 42 && true;        → $x = 1
(yield 1) and true;         // yields 1, but printed as: yield 1 && true;        → yields true

After (fixed)

-(true ? 42 : 0) and true;
+(true ? 42 : 0) && true;

-($x += 42) and true;
+($x += 42) && true;

-($y ??= 5) and true;
+($y ??= 5) && true;

-(print "foo") and (print "bar");
+(print "foo") && print "bar";

-(yield 1) and true;
-(yield from [1]) and true;
+(yield 1) && true;
+(yield from [1]) && true;

-($z ?: 7) and true;
+($z ?: 7) && true;

((print "foo") && print "bar" is intentional — only the left operand needs wrapping; the right stays semantically identical.)

Fix

BetterStandardPrinter::wrapBinaryOpWithBrackets() now reprints lower-precedence operands of a newly created BooleanAnd/BooleanOr so the pretty-printer re-adds the parentheses. yield <value> additionally needs the parentheses forced, since the format-preserving printer drops them for that form.

…LogicalToBooleanRector

Fixes rectorphp/rector#9800

Boolean operators (&& ||) bind tighter than logical ones (and or). When
LogicalToBooleanRector swaps them, operands whose top operator has lower
precedence (ternary, elvis, +=/??=, print, yield, yield from) lost their
parentheses on reprint, changing semantics. Reprint those operands so the
pretty-printer re-adds the parentheses; yield <value> additionally needs
them forced, as the format-preserving printer drops them.
@TomasVotruba

Copy link
Copy Markdown
Member Author

Let's give it a go 👍

@TomasVotruba TomasVotruba merged commit 1ccbb46 into main Jul 8, 2026
65 checks passed
@TomasVotruba TomasVotruba deleted the fix-logical-to-boolean-precedence-parens branch July 8, 2026 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Incorrect behavior of LogicalToBooleanRector: missing parentheses around ternary, Elvis, composed assignments, 'print', 'yield' or 'yield from'

1 participant