Skip to content

Narrow variadic parameter array key integer type to int<0, max>#5791

Merged
staabm merged 1 commit into
phpstan:2.2.xfrom
phpstan-bot:create-pull-request/patch-u076hqc
Jun 2, 2026
Merged

Narrow variadic parameter array key integer type to int<0, max>#5791
staabm merged 1 commit into
phpstan:2.2.xfrom
phpstan-bot:create-pull-request/patch-u076hqc

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

The array synthesized for a variadic parameter (function f(mixed ...$args)) was typed array<int|string, mixed>. The integer keys generated for positional and spread arguments are always non-negative, so the key type can be narrowed. This change types the array as array<int<0, max>|string, mixed>.

The string part of the key is left as string (not non-empty-string) because empty strings can legitimately be passed as keys via argument unpacking — as noted in the issue discussion.

Changes

  • src/Analyser/MutatingScope.php — replaced int|string with int<0, max>|string as the variadic array key in all four construction sites: the declared-type and native-type parameter-scope builders (used when entering a function/method body), getFunctionType(), and buildVariadicArrayTypeFromCallableParameters().
  • src/Reflection/InitializerExprTypeResolver.php — applied the same narrowing and fixed an inverted condition: the method returned the string-keyed array when named arguments were not supported and a pure list when they were, the opposite of MutatingScope. It now matches MutatingScope.
  • Updated test expectations in the affected nsrt data files and TypesAssignedToPropertiesRuleTest to reflect the narrowed key type.

Root cause

Variadic parameters collect arguments into an array whose integer keys (for positional and unpacked positional arguments) start at 0 and increase, so they are always non-negative. The code unconditionally used a plain IntegerType for the key instead of IntegerRangeType::createAllGreaterThanOrEqualTo(0). The same int|string key was constructed in several parallel locations; all were updated. InitializerExprTypeResolver additionally had its two branches swapped relative to MutatingScope, which was fixed at the same time.

Test

  • tests/PHPStan/Analyser/nsrt/variadic-parameter-php8.php — updated existing assertions and added a mixed ...$args case reproducing the issue; now asserts array<int<0, max>|string, ...>.
  • Updated analogous expectations across bug-2600-php8.php, bug-2600-php-version-scope.php, call-user-func-php8.php, bug-9240.php, bug-10671.php, bug-4902-php8.php, bug-5698-php8.php, anonymous-function.php, typehints.php, and TypesAssignedToPropertiesRuleTest::testBug11275. The PHP 7 variadic case correctly remains list<...>.

Fixes phpstan/phpstan#14744

- When named arguments are supported, the array gathered from a variadic
  parameter (`...$args`) is now typed `array<int<0, max>|string, ...>`
  instead of `array<int|string, ...>`. The integer keys produced for
  positional/spread arguments are always non-negative, so the key type is
  narrowed to `int<0, max>`. The string part stays `string` because empty
  strings can be passed as keys via argument unpacking.
- Updated all four variadic key construction sites in `MutatingScope`
  (`getFunctionType`, `buildVariadicArrayTypeFromCallableParameters`, and
  the two parameter-scope builders for declared and native types).
- Fixed the analogous (and inverted) branch in
  `InitializerExprTypeResolver::getFunctionType`: it returned the
  string-keyed array when named arguments were NOT supported and a pure
  list when they were — the opposite of `MutatingScope`. It now matches
  `MutatingScope` and applies the same `int<0, max>` narrowing.
- Updated regression/expectation tests accordingly.
Copy link
Copy Markdown
Contributor

@staabm staabm left a comment

Choose a reason for hiding this comment

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

could we even make it a list?

no we can't: https://3v4l.org/gFrDj#veol

@staabm staabm requested a review from VincentLanglet June 2, 2026 05:36
@phpstan phpstan deleted a comment from phpstan-bot Jun 2, 2026
@staabm staabm merged commit 0ff88f6 into phpstan:2.2.x Jun 2, 2026
665 of 670 checks passed
@staabm staabm deleted the create-pull-request/patch-u076hqc branch June 2, 2026 06:44
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.

Variadic argument's type can be narrowed

3 participants