Fix lost type when assigning variable in method argument
closes https://github.com/phpstan/phpstan/issues/12234 closes https://github.com/phpstan/phpstan/issues/12735
As I said, this either needs virtual nodes
so you mean e.g. a CallLikeArg virtual node so we would hook a rule onto every arg and rework all callers of FunctionCallParametersCheck::check?
ambitious refactoring.
this would mean something like a new MutatingScope->enterCallLike() method, right?
The args need to be considered together. Looking at this the problem goes really deep and it might not be so easy to fix. Looking at places where FunctionCallParametersCheck is called, ParametersAcceptorSelector is called:
ParametersAcceptorSelector::selectFromArgs(
$scope,
$node->getArgs(),
$constructorReflection->getVariants(),
$constructorReflection->getNamedArgumentsVariants(),
)
The considered types inside are going to be wrong too because we're only passing along a single scope.
And of course this method is one of the most used methods across the codebase. Changing that would have ripple effects across the ecosystem so we can't do that now.
Also, FunctionCallParametersCheck::check() accepts a single scope and $funcCall where it gets its arguments. This might be easier to fix. We need a new virtual node for each of Node\Expr\FuncCall|Node\Expr\MethodCall|Node\Expr\StaticCall|Node\Expr\New_ $funcCall. And inside of them we need $args to be a new virtual node array, something like Argument[]. The Argument would contain Scope too.
The proper Argument virtual nodes objects would need to be made inside NodeScopeResolver::processArgs().
So my conclusion is that we can fix FunctionCallParametersCheck::check() now and it might work in most of the cases.
If people do assignment shenanigans and they have wrong generics resolved because of that, it's not so easy to fix.
this would mean something like a new MutatingScope->enterCallLike() method, right?
No, I meant the really ambitious refactoring that I described here https://github.com/phpstan/phpstan-src/pull/4237#issuecomment-3262472961 and that I don't know how the code should look like after yet 😅
Also, FunctionCallParametersCheck::check() accepts a single scope and $funcCall where it gets its arguments. This might be easier to fix. We need a new virtual node for each of Node\Expr\FuncCall|Node\Expr\MethodCall|Node\Expr\StaticCall|Node\Expr\New_ $funcCall. And inside of them we need $args to be a new virtual node array, something like Argument[]. The Argument would contain Scope too.
The proper Argument virtual nodes objects would need to be made inside NodeScopeResolver::processArgs().
While this makes sense it sounds to be a big undertaking to support things I don't like to use at all myself (assigns in expressions).
I prefer to spend my time somewhere on something more valuable
Yeah, sure 👍
Keeping this open because the tests are valuable.