Skip to content

Commit 7fb4a37

Browse files
VincentLangletphpstan-bot
authored andcommitted
Fix phpstan/phpstan#11488: count() narrowing on union of constant arrays
- Fixed specifyTypesForCountFuncCall falsey context to build complement types directly instead of removing matching types, avoiding structural subtyping issues with TypeCombinator::remove - Added regression test in tests/PHPStan/Analyser/nsrt/bug-11488.php
1 parent a3fb8e9 commit 7fb4a37

2 files changed

Lines changed: 38 additions & 2 deletions

File tree

src/Analyser/TypeSpecifier.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,11 +1274,16 @@ private function specifyTypesForCountFuncCall(
12741274
$resultTypes = [];
12751275
foreach ($type->getArrays() as $arrayType) {
12761276
$isSizeSuperTypeOfArraySize = $sizeType->isSuperTypeOf($arrayType->getArraySize());
1277-
if ($isSizeSuperTypeOfArraySize->no()) {
1277+
1278+
if ($context->falsey()) {
1279+
if ($isSizeSuperTypeOfArraySize->yes()) {
1280+
continue;
1281+
}
1282+
$resultTypes[] = $arrayType;
12781283
continue;
12791284
}
12801285

1281-
if ($context->falsey() && $isSizeSuperTypeOfArraySize->maybe()) {
1286+
if ($isSizeSuperTypeOfArraySize->no()) {
12821287
continue;
12831288
}
12841289

@@ -1371,6 +1376,13 @@ private function specifyTypesForCountFuncCall(
13711376
$resultTypes[] = TypeCombinator::intersect($arrayType, new NonEmptyArrayType());
13721377
}
13731378

1379+
if ($context->falsey()) {
1380+
if (count($resultTypes) === 0) {
1381+
return null;
1382+
}
1383+
return $this->create($countFuncCall->getArgs()[0]->value, TypeCombinator::union(...$resultTypes), TypeSpecifierContext::createTrue(), $scope)->setRootExpr($rootExpr);
1384+
}
1385+
13741386
return $this->create($countFuncCall->getArgs()[0]->value, TypeCombinator::union(...$resultTypes), $context, $scope)->setRootExpr($rootExpr);
13751387
}
13761388

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug11488;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
/**
10+
* @param array{mixed}|array{mixed, string|null, mixed} $row
11+
*/
12+
protected function test(array $row): string
13+
{
14+
if (count($row) !== 1) {
15+
assertType('array{mixed, string|null, mixed}', $row);
16+
17+
[$field, $operator, $value] = $row;
18+
assertType('string|null', $operator);
19+
return $operator ?? '=';
20+
}
21+
22+
return '';
23+
}
24+
}

0 commit comments

Comments
 (0)