diff --git a/src/Analyser/TypeSpecifier.php b/src/Analyser/TypeSpecifier.php index 0aafa3956b..0a6cf38249 100644 --- a/src/Analyser/TypeSpecifier.php +++ b/src/Analyser/TypeSpecifier.php @@ -1279,6 +1279,23 @@ private function specifyTypesForCountFuncCall( return null; } + if ($context->falsey() && $isConstantArray->yes()) { + $remainingSize = TypeCombinator::remove($type->getArraySize(), $sizeType); + if (!$remainingSize instanceof NeverType) { + $result = $this->specifyTypesForCountFuncCall( + $countFuncCall, + $type, + $remainingSize, + $context->negate(), + $scope, + $rootExpr, + ); + if ($result !== null) { + return $result; + } + } + } + $resultTypes = []; foreach ($type->getArrays() as $arrayType) { $isSizeSuperTypeOfArraySize = $sizeType->isSuperTypeOf($arrayType->getArraySize()); @@ -1372,7 +1389,14 @@ private function specifyTypesForCountFuncCall( $builder->setOffsetValueType($offsetType, $valueType, $optional); } - $resultTypes[] = $builder->getArray(); + $builtArray = $builder->getArray(); + if ($isList->yes() && !$builder->isList()) { + $constantArrays = $builtArray->getConstantArrays(); + if (count($constantArrays) === 1) { + $builtArray = $constantArrays[0]->makeList(); + } + } + $resultTypes[] = $builtArray; continue; } diff --git a/tests/PHPStan/Analyser/nsrt/bug-14297.php b/tests/PHPStan/Analyser/nsrt/bug-14297.php new file mode 100644 index 0000000000..727c64a10c --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-14297.php @@ -0,0 +1,26 @@ +", count($a)); + + if (count($a) === 2) { + assertType("array{'a'|'b', 'b'}", $a); + } else { + assertType("array{'a'|'b'}", $a); + } +}; diff --git a/tests/PHPStan/Analyser/nsrt/list-count.php b/tests/PHPStan/Analyser/nsrt/list-count.php index f5b37b4410..4a90322e53 100644 --- a/tests/PHPStan/Analyser/nsrt/list-count.php +++ b/tests/PHPStan/Analyser/nsrt/list-count.php @@ -233,13 +233,13 @@ protected function testOptionalKeys($row): void if (count($row) === 1) { assertType('array{mixed}', $row); } else { - assertType('array{0: mixed, 1?: string|null}', $row); + assertType('array{mixed, string|null}', $row); } if (count($row) === 2) { assertType('array{mixed, string|null}', $row); } else { - assertType('array{0: mixed, 1?: string|null}', $row); + assertType('array{mixed}', $row); } if (count($row) === 3) { @@ -263,13 +263,13 @@ protected function testOptionalKeysInUnion($row): void if (count($row) === 1) { assertType('array{mixed}', $row); } else { - assertType('array{0: mixed, 1?: string|null}', $row); + assertType('array{mixed, string|null}', $row); } if (count($row) === 2) { assertType('array{mixed, string|null}', $row); } else { - assertType('array{0: mixed, 1?: string|null}', $row); + assertType('array{mixed}', $row); } if (count($row) === 3) { @@ -293,7 +293,7 @@ protected function testOptionalKeysInListsOfTaggedUnion($row): void if (count($row) === 1) { assertType('array{0: int, 1?: string|null}|array{string}', $row); } else { - assertType('array{0: int, 1?: string|null}', $row); + assertType('array{int, string|null}', $row); } if (count($row) === 2) {