[6.x] Fix: comparison with int range variable not narrowing the other operand#11779
[6.x] Fix: comparison with int range variable not narrowing the other operand#11779alies-dev wants to merge 2 commits into
Conversation
When comparing two variables where one has an int range type (e.g. assert($max >= $min) where $min: int<0, max>), the assertion finder did not extract bounds from the range variable. It only checked for literal int values, so variable-to-variable comparisons produced no assertions and the other operand stayed as plain int. Now hasSuperiorNumberCheck and hasInferiorNumberCheck extract the relevant bound (min_bound or max_bound) from int range types as a fallback when no literal is found, enabling proper type narrowing. For example: - $max >= $min where $min: int<5, max> → $max: int<5, max> - $a < $b where $b: int<min, 10> → $a: int<min, 10> Fixes vimeo#11764
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Reviewed by Cursor Bugbot for commit 2cc62a2. Configure here.
| return self::ASSIGNMENT_TO_RIGHT; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Int range check order blocks left literal narrowing
High Severity
In hasSuperiorNumberCheck, the new right-operand int range check (extracting min_bound) is placed between the right-side and left-side literal int checks, unlike hasInferiorNumberCheck where both int range checks are placed after both literal checks. This causes a regression: for expressions like 5 >= $x where $x has type int<0, max>, the int range match fires first and returns ASSIGNMENT_TO_RIGHT, so the caller tries to resolve a variable name on the literal 5 (which yields null), producing no assertion at all. The existing literal-based narrowing of $x to int<min, 5> is silently lost.
Reviewed by Cursor Bugbot for commit 2cc62a2. Configure here.


Fixes #11764
When comparing two variables where one has an int range type (e.g.
assert($max >= $min)where$min: int<0, max>), the assertion finder only checked for literal int values. Variable-to-variable comparisons produced no assertions, so the other operand stayed as plainint.Before
After
No errors —
$maxis narrowed toint<0, max>after the assertion.Changes
AssertionFinder.php: In bothhasSuperiorNumberCheck(for>/>=) andhasInferiorNumberCheck(for</<=), added fallback logic that extracts the relevant bound from an int range type when no literal value is found:min_bound(for>=) ormax_bound(for<) to narrow the left operandmax_bound(for>=) ormin_bound(for<) to narrow the right operandThis reuses the existing assertion infrastructure (
IsGreaterThan,IsGreaterThanOrEqualTo, etc.) without new assertion types.Note
Medium Risk
Touches core assertion inference for numeric comparisons, which can subtly change type narrowing across analyses, but the logic is small and guarded to
TIntRangebounds with added tests.Overview
Fixes numeric comparison assertion extraction so variable-to-variable comparisons can still narrow types when one side is an
intrange.AssertionFindernow falls back to usingTIntRangebounds (min_bound/max_bound) as the effective comparison value when no int literal is present, enabling narrowing for>/>=and</<=cases. Adds newIntRangeTestcoverage forassert($max >= $min),assert($max > $min), andassert($min <= $max)narrowing behavior.Reviewed by Cursor Bugbot for commit 2cc62a2. Bugbot is set up for automated code reviews on this repo. Configure here.