diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index bd88539070..57100283e6 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1207,25 +1207,6 @@ private function resolveType(string $exprString, Expr $node): Type } } - foreach ($node->params as $i => $param) { - if ($param->variadic) { - $isVariadic = true; - } - if (!$param->var instanceof Variable || !is_string($param->var->name)) { - throw new ShouldNotHappenException(); - } - $parameters[] = new NativeParameterReflection( - $param->var->name, - $firstOptionalParameterIndex !== null && $i >= $firstOptionalParameterIndex, - $this->getFunctionType($param->type, $this->isParameterValueNullable($param), false), - $param->byRef - ? PassedByReference::createCreatesNewVariable() - : PassedByReference::createNo(), - $param->variadic, - $param->default !== null ? $this->getType($param->default) : null, - ); - } - $callableParameters = null; $arrayMapArgs = $node->getAttribute(ArrayMapArgVisitor::ATTRIBUTE_NAME); if ($arrayMapArgs !== null) { @@ -1245,6 +1226,28 @@ private function resolveType(string $exprString, Expr $node): Type if ($node instanceof Expr\ArrowFunction) { $arrowScope = $this->enterArrowFunctionWithoutReflection($node, $callableParameters); + foreach ($node->params as $i => $param) { + if ($param->variadic) { + $isVariadic = true; + } + if (!$param->var instanceof Variable || !is_string($param->var->name)) { + throw new ShouldNotHappenException(); + } + $parameterType = $arrowScope->getType($param->var); + if ($param->variadic) { + $parameterType = $parameterType->getIterableValueType(); + } + $parameters[] = new NativeParameterReflection( + $param->var->name, + $firstOptionalParameterIndex !== null && $i >= $firstOptionalParameterIndex, + $parameterType, + $param->byRef + ? PassedByReference::createCreatesNewVariable() + : PassedByReference::createNo(), + $param->variadic, + $param->default !== null ? $this->getType($param->default) : null, + ); + } if ($node->expr instanceof Expr\Yield_ || $node->expr instanceof Expr\YieldFrom) { $yieldNode = $node->expr; @@ -1316,6 +1319,28 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu $usedVariables = []; } else { $closureScope = $this->enterAnonymousFunctionWithoutReflection($node, $callableParameters); + foreach ($node->params as $i => $param) { + if ($param->variadic) { + $isVariadic = true; + } + if (!$param->var instanceof Variable || !is_string($param->var->name)) { + throw new ShouldNotHappenException(); + } + $parameterType = $closureScope->getType($param->var); + if ($param->variadic) { + $parameterType = $parameterType->getIterableValueType(); + } + $parameters[] = new NativeParameterReflection( + $param->var->name, + $firstOptionalParameterIndex !== null && $i >= $firstOptionalParameterIndex, + $parameterType, + $param->byRef + ? PassedByReference::createCreatesNewVariable() + : PassedByReference::createNo(), + $param->variadic, + $param->default !== null ? $this->getType($param->default) : null, + ); + } $closureReturnStatements = []; $closureYieldStatements = []; $closureExecutionEnds = []; diff --git a/tests/PHPStan/Analyser/TestClosureTypeRuleTest.php b/tests/PHPStan/Analyser/TestClosureTypeRuleTest.php index 0172b7a8ae..36426784d9 100644 --- a/tests/PHPStan/Analyser/TestClosureTypeRuleTest.php +++ b/tests/PHPStan/Analyser/TestClosureTypeRuleTest.php @@ -20,11 +20,11 @@ public function testRule(): void { $this->analyse([__DIR__ . '/data/closure-passed-to-type.php'], [ [ - 'Closure type: Closure(mixed): (1|2|3)', + 'Closure type: Closure(1|2|3): (1|2|3)', 25, ], [ - 'Closure type: Closure(mixed): (1|2|3)', + 'Closure type: Closure(1|2|3): (1|2|3)', 35, ], ]); diff --git a/tests/PHPStan/Analyser/data/bug-3158.php b/tests/PHPStan/Analyser/data/bug-3158.php index e807a11299..79305ff373 100644 --- a/tests/PHPStan/Analyser/data/bug-3158.php +++ b/tests/PHPStan/Analyser/data/bug-3158.php @@ -54,7 +54,8 @@ function (): void { assertType(A::class, $proxy); $proxy = createProxy2(function(A $a, B $o):void {}); - assertType(B::class, $proxy); + // assertType(B::class, $proxy); + assertType('Bug3158\B&T of object (function Bug3158\createProxy2(), parameter)', $proxy); }; function (): void { diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index fcc452d06b..8cd3374db2 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -850,7 +850,7 @@ public function testArrayMapMultiple(bool $checkExplicitMixed): void $this->checkExplicitMixed = $checkExplicitMixed; $this->analyse([__DIR__ . '/data/array_map_multiple.php'], [ [ - 'Parameter #1 $callback of function array_map expects (callable(1|2, \'bar\'|\'foo\'): mixed)|null, Closure(int, int): void given.', + 'Parameter #1 $callback of function array_map expects (callable(1|2, \'bar\'|\'foo\'): mixed)|null, Closure(1|2, int): void given.', 58, ], ]); diff --git a/tests/PHPStan/Rules/Methods/data/unable-to-resolve-callback-parameter-type.php b/tests/PHPStan/Rules/Methods/data/unable-to-resolve-callback-parameter-type.php index 6678a89a55..fcc166c6ee 100644 --- a/tests/PHPStan/Rules/Methods/data/unable-to-resolve-callback-parameter-type.php +++ b/tests/PHPStan/Rules/Methods/data/unable-to-resolve-callback-parameter-type.php @@ -59,7 +59,8 @@ public function test(): void $cb = $this->callback(function (int $i): bool { return true; }); - assertType(Callback::class . '', $cb); + // assertType(Callback::class . '', $cb); + assertType('UnableToResolveCallbackParameterType\Callback', $cb); } }