diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index a43ba35dda..58068161f8 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1758,15 +1758,24 @@ private function enterFunctionLike( $ifType = $parameterType->isNegated() ? $parameterType->getElse() : $parameterType->getIf(); $elseType = $parameterType->isNegated() ? $parameterType->getIf() : $parameterType->getElse(); - $holder = new ConditionalExpressionHolder([ - $parameterType->getParameterName() => ExpressionTypeHolder::createYes(new Variable($targetParameterName), TypeCombinator::intersect($targetParameter->getType(), $parameterType->getTarget())), - ], ExpressionTypeHolder::createYes(new Variable($parameter->getName()), $ifType)); - $conditionalTypes['$' . $parameter->getName()][$holder->getKey()] = $holder; - - $holder = new ConditionalExpressionHolder([ - $parameterType->getParameterName() => ExpressionTypeHolder::createYes(new Variable($targetParameterName), TypeCombinator::remove($targetParameter->getType(), $parameterType->getTarget())), - ], ExpressionTypeHolder::createYes(new Variable($parameter->getName()), $elseType)); - $conditionalTypes['$' . $parameter->getName()][$holder->getKey()] = $holder; + $ifConditionType = TypeCombinator::intersect($targetParameter->getType(), $parameterType->getTarget()); + $elseConditionType = TypeCombinator::remove($targetParameter->getType(), $parameterType->getTarget()); + + $ifConditionTypes = $ifConditionType instanceof UnionType ? $ifConditionType->getTypes() : [$ifConditionType]; + foreach ($ifConditionTypes as $conditionType) { + $holder = new ConditionalExpressionHolder([ + $parameterType->getParameterName() => ExpressionTypeHolder::createYes(new Variable($targetParameterName), $conditionType), + ], ExpressionTypeHolder::createYes(new Variable($parameter->getName()), $ifType)); + $conditionalTypes['$' . $parameter->getName()][$holder->getKey()] = $holder; + } + + $elseConditionTypes = $elseConditionType instanceof UnionType ? $elseConditionType->getTypes() : [$elseConditionType]; + foreach ($elseConditionTypes as $conditionType) { + $holder = new ConditionalExpressionHolder([ + $parameterType->getParameterName() => ExpressionTypeHolder::createYes(new Variable($targetParameterName), $conditionType), + ], ExpressionTypeHolder::createYes(new Variable($parameter->getName()), $elseType)); + $conditionalTypes['$' . $parameter->getName()][$holder->getKey()] = $holder; + } } } diff --git a/tests/PHPStan/Analyser/nsrt/bug-10055.php b/tests/PHPStan/Analyser/nsrt/bug-10055.php new file mode 100644 index 0000000000..8dcfe7ecf1 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-10055.php @@ -0,0 +1,20 @@ += 8.0 + +declare(strict_types = 1); + +namespace Bug10055; + +use function PHPStan\Testing\assertType; + +/** + * @param 'value1'|'value2'|'value3' $param1 + * @param ($param1 is 'value3' ? bool : int) $param2 + */ +function test(string $param1, int|bool $param2): void +{ + match ($param1) { + 'value1' => assertType('int', $param2), + 'value2' => assertType('int', $param2), + 'value3' => assertType('bool', $param2), + }; +}