From ce2aefa099395c54e6536284c9c18878a32423a4 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 18 May 2026 11:44:41 +0200 Subject: [PATCH] Fix another array_shuffle() variant --- src/Type/ArrayType.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-14631.php | 49 +++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/Type/ArrayType.php b/src/Type/ArrayType.php index b3be6b3b8c..7f3eed6f82 100644 --- a/src/Type/ArrayType.php +++ b/src/Type/ArrayType.php @@ -523,7 +523,7 @@ public function shiftArray(): Type public function shuffleArray(): Type { - return new IntersectionType([new self(IntegerRangeType::createAllGreaterThanOrEqualTo(0), $this->itemType), new AccessoryArrayListType()]); + return new IntersectionType([$this->withTypes(IntegerRangeType::createAllGreaterThanOrEqualTo(0), $this->itemType), new AccessoryArrayListType()]); } public function sliceArray(Type $offsetType, Type $lengthType, TrinaryLogic $preserveKeys): Type diff --git a/tests/PHPStan/Analyser/nsrt/bug-14631.php b/tests/PHPStan/Analyser/nsrt/bug-14631.php index 6034061bde..e65873e31a 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-14631.php +++ b/tests/PHPStan/Analyser/nsrt/bug-14631.php @@ -176,3 +176,52 @@ public function ksortArray(array $items): array } } + +/** + * Cases where T is bounded by a plain array (TemplateArrayType), + * so T is directly the subject of shuffleArray() in ArrayType. + * These verify the $this->withTypes() fix rather than the IntersectionType fix. + */ +class Bar +{ + + /** + * @template T of array + * @param T $items + * @return T + */ + public function shuffleTemplateArray(array $items): array + { + assertType('T of array (method Bug14631\Bar::shuffleTemplateArray(), argument)', $items); + shuffle($items); + // T preserved with updated key bound; without $this->withTypes() fix, T was dropped → list + assertType('T of array, int> (method Bug14631\Bar::shuffleTemplateArray(), argument)&list', $items); + return $items; + } + + /** + * @template T of array + * @param T $items + * @return T + */ + public function sortTemplateArray(array $items): array + { + sort($items); + assertType('T of array, int> (method Bug14631\Bar::sortTemplateArray(), argument)&list', $items); + return $items; + } + + /** + * @template T of array + * @param T $items + * @return T + */ + public function usortTemplateArray(array $items): array + { + usort($items, static fn (int $a, int $b) => $a <=> $b); + assertType('T of array, int> (method Bug14631\Bar::usortTemplateArray(), argument)&list', $items); + return $items; + } + +} +