diff --git a/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php b/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php index 04ef90fef5..6c71da8a1c 100644 --- a/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php +++ b/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php @@ -260,12 +260,22 @@ private function processKeyAndItemType(MutatingScope $scope, Type $keyType, Type return [new NeverType(), new NeverType(), false]; } - $scope = $scope->filterByTruthyValue($expr); + $truthyScope = $scope->filterByTruthyValue($expr); + + $optional = !$booleanResult->isTrue()->yes(); + if ($optional) { + $falseyScope = $scope->filterByFalseyValue($expr); + $falseyItemType = $itemVarName !== null ? $falseyScope->getVariableType($itemVarName) : $itemType; + $falseyKeyType = $keyVarName !== null ? $falseyScope->getVariableType($keyVarName) : $keyType; + if ($falseyItemType instanceof NeverType || $falseyKeyType instanceof NeverType) { + $optional = false; + } + } return [ - $keyVarName !== null ? $scope->getVariableType($keyVarName) : $keyType, - $itemVarName !== null ? $scope->getVariableType($itemVarName) : $itemType, - !$booleanResult->isTrue()->yes(), + $keyVarName !== null ? $truthyScope->getVariableType($keyVarName) : $keyType, + $itemVarName !== null ? $truthyScope->getVariableType($itemVarName) : $itemType, + $optional, ]; } diff --git a/tests/PHPStan/Analyser/nsrt/bug-11730.php b/tests/PHPStan/Analyser/nsrt/bug-11730.php new file mode 100644 index 0000000000..42299b511e --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-11730.php @@ -0,0 +1,24 @@ += 8.1 + +declare(strict_types = 1); + +namespace Bug11730; + +use function PHPStan\Testing\assertType; + +class Foo {} + +/** @return ($value is Foo ? true : false) */ +function isFoo(mixed $value): bool { + return $value instanceof Foo; +} + +/** @phpstan-assert-if-true Foo $value */ +function checkFoo(mixed $value): bool { + return $value instanceof Foo; +} + +$data = [new Foo, new Foo]; + +assertType('array{Bug11730\Foo, Bug11730\Foo}', array_filter($data, isFoo(...))); +assertType('array{Bug11730\Foo, Bug11730\Foo}', array_filter($data, checkFoo(...)));