diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index f1ea0a4e7c..91bd6da533 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -119,7 +119,6 @@ use function array_map; use function array_merge; use function array_pop; -use function array_reverse; use function array_slice; use function count; use function explode; @@ -3735,7 +3734,7 @@ public function filterBySpecifiedTypes(SpecifiedTypes $specifiedTypes): self } foreach ($scope->conditionalExpressions as $conditionalExprString => $conditionalExpressions) { - foreach (array_reverse($conditionalExpressions) as $conditionalExpression) { + foreach ($conditionalExpressions as $conditionalExpression) { foreach ($conditionalExpression->getConditionExpressionTypeHolders() as $holderExprString => $conditionalTypeHolder) { if (!array_key_exists($holderExprString, $specifiedExpressions) || !$specifiedExpressions[$holderExprString]->equals($conditionalTypeHolder)) { continue 2; @@ -3745,10 +3744,15 @@ public function filterBySpecifiedTypes(SpecifiedTypes $specifiedTypes): self if ($conditionalExpression->getTypeHolder()->getCertainty()->no()) { unset($scope->expressionTypes[$conditionalExprString]); } else { - $scope->expressionTypes[$conditionalExprString] = $conditionalExpression->getTypeHolder(); + $scope->expressionTypes[$conditionalExprString] = array_key_exists($conditionalExprString, $scope->expressionTypes) + ? new ExpressionTypeHolder( + $scope->expressionTypes[$conditionalExprString]->getExpr(), + TypeCombinator::intersect($scope->expressionTypes[$conditionalExprString]->getType(), $conditionalExpression->getTypeHolder()->getType()), + TrinaryLogic::maxMin($scope->expressionTypes[$conditionalExprString]->getCertainty(), $conditionalExpression->getTypeHolder()->getCertainty()), + ) + : $conditionalExpression->getTypeHolder(); $specifiedExpressions[$conditionalExprString] = $conditionalExpression->getTypeHolder(); } - continue 2; } } diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index e7b187dbce..e0a8eaa2cc 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -1135,6 +1135,7 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-8421.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/imagick-pixel.php'); yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Arrays/data/bug-8467a.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-8467b.php'); } /** diff --git a/tests/PHPStan/Analyser/data/bug-8467b.php b/tests/PHPStan/Analyser/data/bug-8467b.php new file mode 100644 index 0000000000..c4971320ff --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-8467b.php @@ -0,0 +1,56 @@ + + * + * @phpstan-param list|null $mirrors + */ + protected function getUrls(?string $url, ?array $mirrors, ?string $ref, ?string $type, string $urlType): array + { + if (!$url) { + return []; + } + + if ($urlType === 'dist' && false !== strpos($url, '%')) { + assertType('string|null', $type); + $url = 'test'; + } + assertType('non-falsy-string', $url); + + $urls = [$url]; + if ($mirrors) { + foreach ($mirrors as $mirror) { + if ($urlType === 'dist') { + assertType('string|null', $type); + } elseif ($urlType === 'source' && $type === 'git') { + assertType("'git'", $type); + } elseif ($urlType === 'source' && $type === 'hg') { + assertType("'hg'", $type); + } else { + continue; + } + } + } + + return $urls; + } +}