Skip to content

Fix phpstan/phpstan#10055: Conditional argument type not properly narrowing type (for constant string unions?)#5386

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-6ci6gsl
Open

Fix phpstan/phpstan#10055: Conditional argument type not properly narrowing type (for constant string unions?)#5386
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-6ci6gsl

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

Conditional parameter types (@param ($param1 is 'value3' ? bool : int) $param2) fail to narrow correctly when the parameter union type has more than 2 members. The "false" branch condition becomes a UnionType that never matches individual constant types during the equals() check.

Changes

  • Modified src/Analyser/MutatingScope.php to split union condition types into individual ConditionalExpressionHolder instances when creating holders for @param conditional types
  • Added regression test tests/PHPStan/Analyser/nsrt/bug-10055.php

Root cause

When processing @param ($param1 is 'value3' ? bool : int) $param2 with $param1 typed as 'value1'|'value2'|'value3':

  • The "true" branch condition is TypeCombinator::intersect('value1'|'value2'|'value3', 'value3') = 'value3' (works fine)
  • The "false" branch condition is TypeCombinator::remove('value1'|'value2'|'value3', 'value3') = 'value1'|'value2' (a UnionType)

Later, when matching conditions in a match arm where $param1 is narrowed to 'value1', the equals() check compares ConstantStringType('value1') against UnionType('value1'|'value2'), which always fails.

The fix splits union condition types into individual holders: instead of one holder with condition 'value1'|'value2', two holders are created — one for 'value1' and one for 'value2' — both mapping to the same result type (int). This allows the equals() check to match correctly.

Test

Added tests/PHPStan/Analyser/nsrt/bug-10055.php which verifies that in a match expression, conditional parameter types correctly narrow $param2 to int for 'value1' and 'value2' arms, and to bool for the 'value3' arm.

Fixes phpstan/phpstan#10055

- Split union condition types into individual ConditionalExpressionHolders
- When TypeCombinator::intersect or ::remove produces a UnionType, each member
  gets its own holder so the equals() check can match individual constant types
- New regression test in tests/PHPStan/Analyser/nsrt/bug-10055.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants