From 7a3ebe96d900a7263789656b2b0a45ad3606477e Mon Sep 17 00:00:00 2001 From: James Gilliland Date: Thu, 23 Jun 2022 10:51:04 -0500 Subject: [PATCH 1/3] Optimize inner loop of intersect union search Array slice spends a good bit of time allocating memory for new arrays even for small arrays. For larger computed unions this can be a non-trivial amount of time. We can minimize the cost by not repeating the slice for ever iteration of the inner loop since it doesn't depend on the loop. --- src/Type/TypeCombinator.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Type/TypeCombinator.php b/src/Type/TypeCombinator.php index ce77dda2ee..e18a75cf1b 100644 --- a/src/Type/TypeCombinator.php +++ b/src/Type/TypeCombinator.php @@ -638,11 +638,13 @@ public static function intersect(Type ...$types): Type $topLevelUnionSubTypes = []; $innerTypes = $type->getTypes(); usort($innerTypes, $sortTypes); + $slice1 = array_slice($types, 0, $i); + $slice2 = array_slice($types, $i + 1); foreach ($innerTypes as $innerUnionSubType) { $topLevelUnionSubTypes[] = self::intersect( $innerUnionSubType, - ...array_slice($types, 0, $i), - ...array_slice($types, $i + 1), + ...$slice1, + ...$slice2, ); } From 517bc8f98a5ea96568ed0ea7a34898d0c9386353 Mon Sep 17 00:00:00 2001 From: James Gilliland Date: Thu, 23 Jun 2022 13:47:11 -0500 Subject: [PATCH 2/3] Optimize type specification intersect logic Don't know if this will have side effects so testing needed but if it works... oh lord. Fixes #7421 Slow processing of Class::* type hints --- src/Analyser/TypeSpecifier.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Analyser/TypeSpecifier.php b/src/Analyser/TypeSpecifier.php index cf7c6f9fdf..5cfa27df48 100644 --- a/src/Analyser/TypeSpecifier.php +++ b/src/Analyser/TypeSpecifier.php @@ -342,9 +342,8 @@ public function specifyTypesInCondition( } if ($context->true()) { - $type = TypeCombinator::intersect($scope->getType($expr->right), $scope->getType($expr->left)); - $leftTypes = $this->create($expr->left, $type, $context, false, $scope, $rootExpr); - $rightTypes = $this->create($expr->right, $type, $context, false, $scope, $rootExpr); + $leftTypes = $this->create($expr->left, $exprRightType, $context, false, $scope, $rootExpr); + $rightTypes = $this->create($expr->right, $exprLeftType, $context, false, $scope, $rootExpr); return $leftTypes->unionWith($rightTypes); } elseif ($context->false()) { return $this->create($expr->left, $exprLeftType, $context, false, $scope, $rootExpr)->normalize($scope) From 9abc52cf3de78390ac02ee4752073f7ded750447 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Fri, 24 Jun 2022 13:25:23 +0200 Subject: [PATCH 3/3] Adjust test results --- tests/PHPStan/Analyser/TypeSpecifierTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PHPStan/Analyser/TypeSpecifierTest.php b/tests/PHPStan/Analyser/TypeSpecifierTest.php index f93374d8db..5838d222c7 100644 --- a/tests/PHPStan/Analyser/TypeSpecifierTest.php +++ b/tests/PHPStan/Analyser/TypeSpecifierTest.php @@ -422,7 +422,7 @@ public function dataCondition(): array new Variable('foo'), new Variable('bar'), ), - ['$foo' => 'Bar', '$bar' => 'Bar'], + ['$foo' => 'Bar', '$bar' => 'mixed'], // could be '$bar' => 'Bar' [], ], [ @@ -1067,7 +1067,7 @@ public function dataCondition(): array ), [ '$foo' => 'array', - 'array_filter($foo, \'is_string\', ARRAY_FILTER_USE_KEY)' => 'array', + 'array_filter($foo, \'is_string\', ARRAY_FILTER_USE_KEY)' => 'array', // could be 'array' ], [], ],