Skip to content

Do not extend Expr in the isset/empty/coalesce rule-facing virtual nodes - #6155

Merged
ondrejmirtes merged 1 commit into
2.2.xfrom
isset-virtual-nodes-not-expr
Jul 30, 2026
Merged

Do not extend Expr in the isset/empty/coalesce rule-facing virtual nodes#6155
ondrejmirtes merged 1 commit into
2.2.xfrom
isset-virtual-nodes-not-expr

Conversation

@ondrejmirtes

Copy link
Copy Markdown
Member

Fixes the reported integration crash:

Internal error: Call to undefined method PHPStan\Node\Printer\Printer::pPHPStan_Node_IssetExpressionNode()

IssetExpressionNode, EmptyExpressionNode and CoalesceExpressionNode are emitted to node callbacks for their rules, and third-party collectors/rules commonly call $scope->getType() on every Expr they receive — which reached the type-cache key printer with no printer method for these nodes. The codebase convention for rule-facing virtual nodes is to extend NodeAbstract (MatchExpressionNode, BooleanAndNode, …) precisely so they can never be passed to getType(); these three now follow, and callNodeCallbackWithExpression() accepts any Node (it only adjusts the scope for deep contexts).

The regression test mimics the crashing collector: a Node::class rule calling $scope->getType() on every expression over an isset/empty/??/??= fixture — red with the exact production error before the fix, green after.

Full test suite green with and without the active turbo extension, make phpstan and make cs clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DaBZjgksga4c5s6Q9FniY7

IssetExpressionNode, EmptyExpressionNode and CoalesceExpressionNode are
emitted to node callbacks for their rules, and third-party collectors
and rules commonly call $scope->getType() on every expression they
receive - which crashed in the type-cache key printer, since these
nodes have no printer method:

  Call to undefined method Printer::pPHPStan_Node_IssetExpressionNode()

Rule-facing virtual nodes extend NodeAbstract (MatchExpressionNode,
BooleanAndNode, ...) precisely so they can never reach getType(); these
three now follow. callNodeCallbackWithExpression() accepts any Node -
it only adjusts the scope for deep contexts before emitting.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DaBZjgksga4c5s6Q9FniY7
@ondrejmirtes
ondrejmirtes merged commit f935366 into 2.2.x Jul 30, 2026
742 of 745 checks passed
@ondrejmirtes
ondrejmirtes deleted the isset-virtual-nodes-not-expr branch July 30, 2026 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant