Skip to content

Fix #5610: Match integer comparision#5085

Closed
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-htothxd
Closed

Fix #5610: Match integer comparision#5085
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-htothxd

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When using match(true) with complementary integer comparisons like $bar < $baz and $bar >= $baz, PHPStan incorrectly reported "Match expression does not handle remaining value: true" even though the two arms cover all possible cases.

Changes

  • Added resolveComplementaryComparison() method to src/Analyser/MutatingScope.php that checks stored expression types for complementary comparisons
  • Modified the comparison resolution logic in MutatingScope::resolveType() to use this method before computing comparison results from operand types
  • Added regression test in tests/PHPStan/Rules/Comparison/data/bug-5610.php covering all four complement pairs (</>=, >/<=, <=/>, >=/<)
  • Added test method testBug5610() in tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php

Root cause

When match(true) processes arms sequentially, after the first arm ($bar < $baz), the scope stores $bar < $baz → false via filterByFalseyValue. However, when resolving the second arm's condition $bar >= $baz, MutatingScope::resolveType() computed the result purely from the operand types (int >= intmaybebool), without checking if the complementary expression $bar < $baz already had a stored constant boolean type. Since getType($bar >= $baz) returned bool instead of true, the match was not detected as exhaustive.

The fix adds a complement check: when resolving $a >= $b, it looks up $a < $b in the scope's stored expression types. If the complement is stored as false, the comparison returns true (and vice versa). This allows the match arm processing to correctly identify the second arm as always-true, making the match exhaustive.

Test

The regression test covers four functions, each with a match(true) using a different pair of complementary comparisons (</>=, >/<=, <=/>, >=/<). All are expected to produce no errors (empty expected errors array).

Fixes phpstan/phpstan#5610

- Added resolveComplementaryComparison() method to MutatingScope that checks
  if the complement of a comparison expression has a stored type in the scope
- When resolving $a >= $b, if $a < $b is already stored as false (or true),
  the complement is returned, allowing match(true) to detect exhaustive arms
- Handles all four comparison pairs: < / >=, <= / >, > / <=, >= / <
- New regression test in tests/PHPStan/Rules/Comparison/data/bug-5610.php

Closes phpstan/phpstan#5610
Copy link
Contributor

@VincentLanglet VincentLanglet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This need more tests, like

Copy link
Contributor

@VincentLanglet VincentLanglet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried and this is too specific, more case should be handled
https://phpstan.org/r/9b3cc36b-6df2-4db3-83b3-cadf8850c6b8

@VincentLanglet VincentLanglet deleted the create-pull-request/patch-htothxd branch March 8, 2026 12:16
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