Skip to content

Fix #11310: False Positive on Match Arm Comparison with Incremented Bounded Integer#4973

Open
phpstan-bot wants to merge 2 commits into2.1.xfrom
create-pull-request/patch-rycoul0
Open

Fix #11310: False Positive on Match Arm Comparison with Incremented Bounded Integer#4973
phpstan-bot wants to merge 2 commits into2.1.xfrom
create-pull-request/patch-rycoul0

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When using $i++ (post-increment) as a match expression subject, PHPStan incorrectly used the post-incremented type for arm comparisons. For example, with int<0, max> parameter type, match($i++) would compare arms against int<1, max> instead of int<0, max>, causing false "always false" match arm comparison errors.

Changes

  • Modified src/Analyser/NodeScopeResolver.php to capture the condition's native type ($condNativeType) before processing the expression, and pass both the PHPDoc type and native type to enterMatch()
  • Modified src/Analyser/MutatingScope.php to accept optional $condType and $condNativeType parameters in enterMatch(), using them instead of re-evaluating the condition on the already-updated scope

Root cause

In NodeScopeResolver, the match expression condition was processed in two stages:

  1. $condType = $scope->getType($expr->cond) — captures the type before processing
  2. $this->processExprNode(...) — processes the condition, updating the scope (e.g., incrementing $i)
  3. $scope->enterMatch($expr) — called on the updated scope

Inside enterMatch(), the condition type was re-evaluated via $this->getType($cond) on the already-modified scope. For $i++, this meant the scope already reflected $i as int<1, max>, so the match subject type became int<1, max> instead of the correct int<0, max>.

The fix passes the pre-computed types (captured before processing) directly to enterMatch(), ensuring the match subject uses the correct type regardless of side effects in the condition expression.

Test

Added tests/PHPStan/Rules/Comparison/data/bug-11310.php with three cases:

  • $i++ (post-increment): no false positive — match subject uses original value
  • $i-- (post-decrement): no false positive — match subject uses original value
  • ++$i (pre-increment): correctly reports always-false comparison with int<1, max> vs 0

Fixes phpstan/phpstan#11310

phpstan-bot and others added 2 commits February 17, 2026 03:25
- Pass pre-computed condition type and native type to MutatingScope::enterMatch()
- Previously, enterMatch() re-evaluated the condition on the already-updated scope,
  causing post-increment ($i++) to use the incremented type instead of the original
- Also fixes pre-increment (++$i) double-counting the increment in match context
- New regression test in tests/PHPStan/Rules/Comparison/data/bug-11310.php

Closes phpstan/phpstan#11310
Automated fix attempt 1 for CI failures.
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.

1 participant