From cc80aa8b377a3f34ee363978bdd919d9c99dbc37 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 21 Jan 2026 14:15:14 +0100 Subject: [PATCH 1/2] Fix broken `array_count_values` array key inference --- ...yCountValuesDynamicReturnTypeExtension.php | 6 +++++ .../Analyser/nsrt/array-count-values.php | 23 ++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/Type/Php/ArrayCountValuesDynamicReturnTypeExtension.php b/src/Type/Php/ArrayCountValuesDynamicReturnTypeExtension.php index 986f299cd8..bd88f6bbc5 100644 --- a/src/Type/Php/ArrayCountValuesDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArrayCountValuesDynamicReturnTypeExtension.php @@ -54,6 +54,12 @@ public function getTypeFromFunctionCall( continue; } + if (!$itemType->isString()->no() && !$itemType->isConstantScalarValue()->yes()) { + $itemType = $allowedValues; + } else { + $itemType = $itemType->toArrayKey(); + } + $outputTypes[] = new IntersectionType([ new ArrayType($itemType->toArrayKey(), IntegerRangeType::fromInterval(1, null)), new NonEmptyArrayType(), diff --git a/tests/PHPStan/Analyser/nsrt/array-count-values.php b/tests/PHPStan/Analyser/nsrt/array-count-values.php index 0be5d86a1c..f5db340136 100644 --- a/tests/PHPStan/Analyser/nsrt/array-count-values.php +++ b/tests/PHPStan/Analyser/nsrt/array-count-values.php @@ -25,7 +25,7 @@ function returnsStringOrObjectArray(): array } // Objects are ignored by array_count_values, with a warning emitted. -assertType('non-empty-array>', array_count_values(returnsStringOrObjectArray())); +assertType('non-empty-array>', array_count_values(returnsStringOrObjectArray())); class StringableObject { @@ -50,3 +50,24 @@ public function __toString(): string $intAsString = array_count_values(['1', '2', '2', '3']); assertType("non-empty-array<1|2|3, int<1, max>>", $intAsString); + +/** + * @param array $strings + * @param array $ints + * @param array $positives + * @param array> $ranges + * @param array $stringOrInts + * @param array $stringsOrBool + */ +function strings(array $strings, array $ints, array $positives, array $ranges, array $stringOrInts, array $stringsOrBool): void +{ + // numeric-strings in array-keys are auto-casted to int, see https://3v4l.org/VQoSJQ#vnull + assertType("non-empty-array>", array_count_values($strings)); + + assertType("non-empty-array>", array_count_values($ints)); + assertType("non-empty-array, int<1, max>>", array_count_values($positives)); + assertType("non-empty-array, int<1, max>>", array_count_values($ranges)); + + assertType("non-empty-array>", array_count_values($stringOrInts)); + assertType("non-empty-array>", array_count_values($stringsOrBool)); +} From 652aa23ae3f0c88f7913a53ab230abe0ec503339 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 21 Jan 2026 14:24:02 +0100 Subject: [PATCH 2/2] more tests --- .../PHPStan/Analyser/nsrt/array-count-values.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/PHPStan/Analyser/nsrt/array-count-values.php b/tests/PHPStan/Analyser/nsrt/array-count-values.php index f5db340136..64af79934f 100644 --- a/tests/PHPStan/Analyser/nsrt/array-count-values.php +++ b/tests/PHPStan/Analyser/nsrt/array-count-values.php @@ -58,8 +58,19 @@ public function __toString(): string * @param array> $ranges * @param array $stringOrInts * @param array $stringsOrBool + * @param array $intOrConstNumericString + * @param array $intOrConstNonNumericString */ -function strings(array $strings, array $ints, array $positives, array $ranges, array $stringOrInts, array $stringsOrBool): void +function strings( + array $strings, + array $ints, + array $positives, + array $ranges, + array $stringOrInts, + array $stringsOrBool, + array $intOrConstNumericString, + array $intOrConstNonNumericString, +): void { // numeric-strings in array-keys are auto-casted to int, see https://3v4l.org/VQoSJQ#vnull assertType("non-empty-array>", array_count_values($strings)); @@ -70,4 +81,6 @@ function strings(array $strings, array $ints, array $positives, array $ranges, a assertType("non-empty-array>", array_count_values($stringOrInts)); assertType("non-empty-array>", array_count_values($stringsOrBool)); + assertType("non-empty-array>", array_count_values($intOrConstNumericString)); // could have only "int" key + assertType("non-empty-array>", array_count_values($intOrConstNonNumericString)); }