From 64eb10776daf7b62f3247dfd444bf28ad7050ff6 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 29 Dec 2025 17:18:17 +0100 Subject: [PATCH 1/5] Speedup analysis of big arrays containing closures degrade analysis precision to a callable type --- src/Type/Constant/ConstantArrayType.php | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Type/Constant/ConstantArrayType.php b/src/Type/Constant/ConstantArrayType.php index fbb1217057..f792996ef4 100644 --- a/src/Type/Constant/ConstantArrayType.php +++ b/src/Type/Constant/ConstantArrayType.php @@ -29,6 +29,8 @@ use PHPStan\Type\Accessory\NonEmptyArrayType; use PHPStan\Type\ArrayType; use PHPStan\Type\BooleanType; +use PHPStan\Type\CallableType; +use PHPStan\Type\ClosureType; use PHPStan\Type\CompoundType; use PHPStan\Type\ConstantScalarType; use PHPStan\Type\ErrorType; @@ -167,7 +169,25 @@ public function getIterableValueType(): Type return $this->iterableValueType; } - return $this->iterableValueType = count($this->valueTypes) > 0 ? TypeCombinator::union(...$this->valueTypes) : new NeverType(true); + $count = count($this->valueTypes); + if ($count === 0) { + return new NeverType(true); + } + + if ($count > 16) { + $onlyClosureValues = true; + foreach ($this->valueTypes as $valueType) { + if (!$valueType instanceof ClosureType) { + $onlyClosureValues = false; + } + } + + if ($onlyClosureValues) { + return new CallableType(); + } + } + + return TypeCombinator::union(...$this->valueTypes); } public function getKeyType(): Type From c87fb6350606a9ce48f478109689a62fb8cd3b53 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 29 Dec 2025 17:19:31 +0100 Subject: [PATCH 2/5] Update ConstantArrayType.php --- src/Type/Constant/ConstantArrayType.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Type/Constant/ConstantArrayType.php b/src/Type/Constant/ConstantArrayType.php index f792996ef4..544e4c48fa 100644 --- a/src/Type/Constant/ConstantArrayType.php +++ b/src/Type/Constant/ConstantArrayType.php @@ -179,6 +179,7 @@ public function getIterableValueType(): Type foreach ($this->valueTypes as $valueType) { if (!$valueType instanceof ClosureType) { $onlyClosureValues = false; + break; } } From c50bf7838ffc570f506be1233425d822b1ee3b2e Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 29 Dec 2025 17:42:42 +0100 Subject: [PATCH 3/5] added regression test --- .../Analyser/AnalyserIntegrationTest.php | 7 + tests/PHPStan/Analyser/data/bug-13933.php | 246 ++++++++++++++++++ 2 files changed, 253 insertions(+) create mode 100644 tests/PHPStan/Analyser/data/bug-13933.php diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index a3e9095a89..3a46c92ca8 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -1570,6 +1570,13 @@ public function testBug13714(): void $this->assertSame('Function Bug13714\array_find invoked with 2 parameters, 0 required.', $errors[6]->getMessage()); } + public function testBug13933(): void + { + $errors = $this->runAnalyse(__DIR__ . '/data/bug-13933.php'); + $this->assertNoErrors($errors); + } + + /** * @param string[]|null $allAnalysedFiles * @return list diff --git a/tests/PHPStan/Analyser/data/bug-13933.php b/tests/PHPStan/Analyser/data/bug-13933.php new file mode 100644 index 0000000000..023c61bad3 --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-13933.php @@ -0,0 +1,246 @@ + Date: Mon, 29 Dec 2025 17:44:25 +0100 Subject: [PATCH 4/5] Update AnalyserIntegrationTest.php --- tests/PHPStan/Analyser/AnalyserIntegrationTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index 3a46c92ca8..fed5cb2c75 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -1576,7 +1576,6 @@ public function testBug13933(): void $this->assertNoErrors($errors); } - /** * @param string[]|null $allAnalysedFiles * @return list From a2646e69b44a414dca1f0744d076bf3df9f6c6c3 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 29 Dec 2025 17:48:47 +0100 Subject: [PATCH 5/5] Update ConstantArrayType.php --- src/Type/Constant/ConstantArrayType.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Type/Constant/ConstantArrayType.php b/src/Type/Constant/ConstantArrayType.php index 544e4c48fa..028698e42b 100644 --- a/src/Type/Constant/ConstantArrayType.php +++ b/src/Type/Constant/ConstantArrayType.php @@ -171,7 +171,7 @@ public function getIterableValueType(): Type $count = count($this->valueTypes); if ($count === 0) { - return new NeverType(true); + return $this->iterableValueType = new NeverType(true); } if ($count > 16) { @@ -184,11 +184,11 @@ public function getIterableValueType(): Type } if ($onlyClosureValues) { - return new CallableType(); + return $this->iterableValueType = new CallableType(); } } - return TypeCombinator::union(...$this->valueTypes); + return $this->iterableValueType = TypeCombinator::union(...$this->valueTypes); } public function getKeyType(): Type