Skip to content

Feature request: Carry types into invoked callable/closure #7798

@leongersen

Description

@leongersen

Feature request

It would be nice if PhpStan could use the types of the arguments passed to a closure for the parameters of that closure.

Discussed in #7797

Originally posted by leongersen August 15, 2022
I'm trying to analyse some generated code.

Is there a way to have PhpStan "carry" the known types into an (inline) function invocation?

$context = ['a' => 3];

\PHPStan\dumpType($context['a']); // 3

(function($context) {
    \PHPStan\dumpType($context['a']); // mixed
})($context);

https://phpstan.org/r/3b8fec48-5b00-4a34-9cde-65037a5c6398

I tried giving this a shot, but I got stuck in the details of NodeScopeResolver.

I got towards something along the type lines of:

// When processing FuncCall
if ($expr->name instanceof Expr\Closure) {
	$args = $expr->getArgs();
	$params = $nameType->getParams();

	foreach ($args as $index => $arg) {
		$paramExpr = $params[$index]->var;
		$argType = $scope->getType($arg->value);

		$scope = $scope->assignExpression($paramExpr, $argType);
	}
}

I don't really understand the internals well enough to continue. (Especially around ParametersAcceptorSelector. I'm not sure if I need to extend NodeScopeResolver::processArgs to set the parameter types).

A start to the testcase for NodeScopeResolverTest:

namespace ClosureArgumentType;

use function PHPStan\Testing\assertType;

class Foo
{
	/**
	 * @param array{a: int} $array
	 */
	public function doFoo(int $integer, array $array, ?string $nullableString)
	{
		(function($context) {
			assertType('int', $context);
		})($integer);

		(function($context) {
			assertType('array{a: int}', $context);
		})($array);

		(function($context) {
			assertType('?string', $context);
		})($nullableString);

		(function($context1, $context2, $context3) {
			assertType('int', $context1);
			assertType('array{a: int}', $context2);
			assertType('?string', $context3);
		})($integer, $array, $nullableString);

               // Cases where arguments are unpacked should be added
	}
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions