Skip to content

Commit b2b8c97

Browse files
github-actions[bot]staabm
authored andcommitted
Fix array_filter with assert-if-true callable marking all keys optional
- When array_filter callback has @phpstan-assert-if-true, check the falsey branch to determine if the callback can actually return false for the given input type - If filtering by falsey value makes the item/key type NeverType, the false branch is impossible, so the key should not be marked optional - New regression test in tests/PHPStan/Analyser/nsrt/bug-11730.php Closes phpstan/phpstan#11730
1 parent 47f36d8 commit b2b8c97

2 files changed

Lines changed: 38 additions & 4 deletions

File tree

src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,22 @@ private function processKeyAndItemType(MutatingScope $scope, Type $keyType, Type
260260
return [new NeverType(), new NeverType(), false];
261261
}
262262

263-
$scope = $scope->filterByTruthyValue($expr);
263+
$truthyScope = $scope->filterByTruthyValue($expr);
264+
265+
$optional = !$booleanResult->isTrue()->yes();
266+
if ($optional) {
267+
$falseyScope = $scope->filterByFalseyValue($expr);
268+
$falseyItemType = $itemVarName !== null ? $falseyScope->getVariableType($itemVarName) : $itemType;
269+
$falseyKeyType = $keyVarName !== null ? $falseyScope->getVariableType($keyVarName) : $keyType;
270+
if ($falseyItemType instanceof NeverType || $falseyKeyType instanceof NeverType) {
271+
$optional = false;
272+
}
273+
}
264274

265275
return [
266-
$keyVarName !== null ? $scope->getVariableType($keyVarName) : $keyType,
267-
$itemVarName !== null ? $scope->getVariableType($itemVarName) : $itemType,
268-
!$booleanResult->isTrue()->yes(),
276+
$keyVarName !== null ? $truthyScope->getVariableType($keyVarName) : $keyType,
277+
$itemVarName !== null ? $truthyScope->getVariableType($itemVarName) : $itemType,
278+
$optional,
269279
];
270280
}
271281

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php // lint >= 8.1
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug11730;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
class Foo {}
10+
11+
/** @return ($value is Foo ? true : false) */
12+
function isFoo(mixed $value): bool {
13+
return $value instanceof Foo;
14+
}
15+
16+
/** @phpstan-assert-if-true Foo $value */
17+
function checkFoo(mixed $value): bool {
18+
return $value instanceof Foo;
19+
}
20+
21+
$data = [new Foo, new Foo];
22+
23+
assertType('array{Bug11730\Foo, Bug11730\Foo}', array_filter($data, isFoo(...)));
24+
assertType('array{Bug11730\Foo, Bug11730\Foo}', array_filter($data, checkFoo(...)));

0 commit comments

Comments
 (0)