Skip to content

Commit

Permalink
Detect closure parameter types when passing closure in a union
Browse files Browse the repository at this point in the history
  • Loading branch information
axlon committed Feb 25, 2022
1 parent 7b104ae commit a483c11
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/Analyser/NodeScopeResolver.php
Expand Up @@ -139,6 +139,7 @@
use PHPStan\Type\VoidType;
use Throwable;
use function array_fill_keys;
use function array_filter;
use function array_key_exists;
use function array_map;
use function array_merge;
Expand Down Expand Up @@ -2858,6 +2859,13 @@ private function processClosureNode(
$byRefUses = [];

if ($passedToType !== null && !$passedToType->isCallable()->no()) {
if ($passedToType instanceof UnionType) {
$passedToType = TypeCombinator::union(...array_filter(
$passedToType->getTypes(),
static fn (Type $type) => $type->isCallable()->yes(),
));
}

$callableParameters = null;
$acceptors = $passedToType->getCallableParametersAcceptors($scope);
if (count($acceptors) === 1) {
Expand Down Expand Up @@ -2987,6 +2995,13 @@ private function processArrowFunctionNode(
}

if ($passedToType !== null && !$passedToType->isCallable()->no()) {
if ($passedToType instanceof UnionType) {
$passedToType = TypeCombinator::union(...array_filter(
$passedToType->getTypes(),
static fn (Type $type) => $type->isCallable()->yes(),
));
}

$callableParameters = null;
$acceptors = $passedToType->getCallableParametersAcceptors($scope);
if (count($acceptors) === 1) {
Expand Down
4 changes: 4 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Expand Up @@ -714,6 +714,10 @@ public function dataFileAsserts(): iterable
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6672.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6687.php');

if (self::$useStaticReflectionProvider) {
yield from $this->gatherAssertTypes(__DIR__ . '/data/callable-in-union.php');
}

require_once __DIR__ . '/data/countable.php';
yield from $this->gatherAssertTypes(__DIR__ . '/data/countable.php');
}
Expand Down
17 changes: 17 additions & 0 deletions tests/PHPStan/Analyser/data/callable-in-union.php
@@ -0,0 +1,17 @@
<?php

namespace CallableInUnion;

use function PHPStan\Testing\assertType;

/** @param array<string, mixed>|(callable(array<string, mixed>): array<string, mixed>) $_ */
function acceptArrayOrCallable($_)
{
}

acceptArrayOrCallable(fn ($parameter) => assertType('array<string, mixed>', $parameter));

acceptArrayOrCallable(function ($parameter) {
assertType('array<string, mixed>', $parameter);
return $parameter;
});

0 comments on commit a483c11

Please sign in to comment.