You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
2.6.6 (rule source unchanged on rector-src main as of 2026-09-23)
Installed as
composer dependency
PHP
8.5.4
We ran into this while moving a mid-sized PHP 8.5 codebase to typed signatures. No test or static check noticed it; a byte-for-byte comparison of every rendered page before and after the Rector run did, because a label silently disappeared.
?? binds tighter than ?:, so the result parses as ($a ?? $b) ? 'yes' : 'no'. For $a = 'abc', $b = false the original returns 'abc', the rewritten code returns 'yes'.
Expected Behaviour
return $a ?? ($b ? 'yes' : 'no'); — as the isset() / is_null() branches already do since rector-src #7889, #7916 and #7969 (issues #9649, #9674).
Cause
In refactor(), the Identical / NotIdentical path calls createCoalesce($checkedNode, $fallbackNode) without preserveWrappedFallback($fallbackNode). The underlying cause is nikic/PHP-Parser#1119: the format-preserving printer does not re-add parentheses for an unchanged node moved under a new parent. A nested ternary fallback is always parenthesized in valid PHP 8 code, so every such case is affected.
Suggested fix: call $this->preserveWrappedFallback($fallbackNode) on that path as well, with a fixture (e.g. keep_right_parentheses_not_identical.php.inc) covering both !== null and === null. Happy to send a PR if that direction is welcome.
Activity
TomasVotruba commentedon Oct 16, 2026
Thanks for reporting 👍
Fixedi in rectorphp/rector-src#8674