Skip to content

Fix phpstan/phpstan#14215: Nonexistent offset detection on lists with count() -1#5116

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

Fix phpstan/phpstan#14215: Nonexistent offset detection on lists with count() -1#5116
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-xaz8gw4

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

PHPStan was reporting false positive "Offset might not exist" errors when accessing a list element after a $index < count($array) - 1 or $index <= count($array) - 1 guard. This extends the fix from #5090 (which handled plain count($array)) to also handle count($array) - K patterns.

Changes

  • Modified src/Analyser/TypeSpecifier.php to extract count()/sizeof() calls from BinaryOp\Minus expressions (e.g. count($list) - 1)
  • Adjusted sizeType computation to account for the subtraction value K when narrowing the count type
  • Updated list offset inference condition: $index <= count($list) - K is safe when K >= 1 (equivalent to $index < count($list) - (K-1))
  • Adjusted non-empty array narrowing threshold by subtracting K

Root cause

The TypeSpecifier only looked for FuncCall nodes matching count/sizeof on the right side of comparisons. When the right side was BinaryOp\Minus(FuncCall(count), Int_(K)), it was not recognized, so no offset validity inference was made. The fix extracts the count call from the minus expression and adjusts the comparison semantics by the subtraction amount.

Test

Added tests/PHPStan/Rules/Arrays/data/bug-14215.php with test cases for:

  • $index < count($array) - 1 with positive-int (no error)
  • $index <= count($array) - 1 with positive-int (no error)
  • $index <= count($array) - 1 with plain int (still reports - could be negative)
  • $index < count($array) - 1 with int<0, max> (no error)
  • $index <= count($array) - 1 with int<0, max> (no error)
  • $index < count($array) - 2 / $index <= count($array) - 2 with positive-int (no error)
  • sizeof() variant (no error)
  • Inverted form count($array) - 1 > $index (no error)

Fixes phpstan/phpstan#14215

… `count() - 1`

- Extended TypeSpecifier to detect `count($list) - K` patterns in comparisons, not just plain `count($list)`
- Adjusted sizeType computation to account for the subtraction value
- List offset inference now works with both `$index < count($list) - K` and `$index <= count($list) - K` (when K >= 1)
- Non-empty array narrowing threshold adjusted for subtraction
- New regression test in tests/PHPStan/Rules/Arrays/data/bug-14215.php
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.

Seems interesting, dunno if you plan/want to work on it @staabm ?

$sizeType = $leftType->shift($offset);
$sizeType = $leftType->shift($offset + $subtraction);
} else {
$sizeType = $leftType;
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we add $substraction here too ?

$subtraction = $expr->right->right->value;
}

if (
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the bot is trying to support thing like

if (3 < count($array) - 1)

@staabm
Copy link
Contributor

staabm commented Mar 1, 2026

I can have a look.

If you are interested feel free to take it

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.

3 participants