Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
leongersen opened this issue Aug 16, 2022 · 5 comments
Closed

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

leongersen opened this issue Aug 16, 2022 · 5 comments

Comments

@leongersen
Copy link
Contributor

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
	}
}
@ondrejmirtes
Copy link
Member

This already works for array_map: https://phpstan.org/r/e507c34c-7ffa-474b-bd40-2b1630f420a0

Thanks to these lines of code: https://github.com/phpstan/phpstan-src/blob/4b6d9647784966438c742b367066656cf269a8d4/src/Reflection/ParametersAcceptorSelector.php#L72-L100

The arrayMapArgs is set thanks to this node visitor: https://github.com/phpstan/phpstan-src/blob/1.8.x/src/Parser/ArrayMapArgVisitor.php (more about them: https://phpstan.org/blog/preprocessing-ast-for-custom-rules).

(Of course, I could be wrong, you can try remove these lines of code and see which tests fail.)

Adapting this knowledge to make this feature request work is really easy I'd say :)

@ondrejmirtes
Copy link
Member

The relevant code for this in NodeScopeResolver is this but you won't have to touch that for this feature request, it works in a general sense: https://github.com/phpstan/phpstan-src/blob/4b6d9647784966438c742b367066656cf269a8d4/src/Analyser/NodeScopeResolver.php#L2964-L2975

@leongersen
Copy link
Contributor Author

Thanks for the pointers, I'll have another look :)

@ondrejmirtes
Copy link
Member

Implemented: phpstan/phpstan-src#1628

ondrejmirtes added a commit that referenced this issue Aug 17, 2022
phpstan/phpstan-src@7be8400 Update PHP 8 stubs phpstan/phpstan-src@087141e Remove jean85/pretty-package-versions dependency phpstan/phpstan-src@3dbb89e Use argument types as parameter types for inline closures (#7798)
@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants