Skip to content

Fix phpstan/phpstan#3128: array ignored in @param array|stdClass[] $foo#5187

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

Fix phpstan/phpstan#3128: array ignored in @param array|stdClass[] $foo#5187
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-16uzoht

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When writing @param array|stdClass[] $foo, PHPStan incorrectly parsed this as array<stdClass> instead of array|array<stdClass>. This caused false positives when passing a plain array (e.g., [1]) to such a parameter, since array should accept any array.

Changes

  • Modified TypeNodeResolver::resolveUnionTypeNode() in src/PhpDoc/TypeNodeResolver.php to use a two-pass approach for merging [] shorthand types with other iterables
  • Pass 1 handles non-array iterables (ObjectType like Collection, IterableType) — these get their value type annotated by the [] notation as before
  • Pass 2 only merges ArrayType/ConstantArrayType if at least one non-array iterable was merged in Pass 1, preserving patterns like Foo[]|Collection|arrayarray<Foo>|(Collection & iterable<Foo>)
  • Updated expected errors in tests/PHPStan/Rules/Functions/MissingFunctionParameterTypehintRuleTest.php for array|int[] now correctly resolving to array
  • Added regression test in tests/PHPStan/Rules/Methods/data/bug-3128.php

Root cause

TypeNodeResolver::resolveUnionTypeNode() had a single-pass loop that merged Foo[] value types into all iterable types in the union, including plain array. When array (with MixedType value type) was in a union with stdClass[], the merge replaced array with array<stdClass>, incorrectly narrowing the type. The fix introduces a two-pass approach: first merge with non-array iterables, then only merge with array types if a non-array merge occurred — indicating the [] notation is annotating a collection pattern rather than being a standalone array type.

Test

Added tests/PHPStan/Rules/Methods/data/bug-3128.php testing both @param array|stdClass[] $foo and @param stdClass[]|array $bar with a plain array argument [1]. Both should produce no errors at level 5.

Fixes phpstan/phpstan#3128

- Changed TypeNodeResolver::resolveUnionTypeNode() to use a two-pass approach
  for merging [] shorthand types with other iterables in a union
- Pass 1 merges non-array iterables (ObjectType, IterableType) with the [] type
- Pass 2 merges ArrayType/ConstantArrayType only if a non-array iterable was
  also merged, preserving existing patterns like Foo[]|Collection|array
- Without a non-array iterable, array|Foo[] correctly becomes array|array<Foo>
  which simplifies to array via TypeCombinator
- New regression test in tests/PHPStan/Rules/Methods/data/bug-3128.php
- Updated MissingFunctionParameterTypehintRuleTest for array|int[] now resolving
  to plain array

Closes phpstan/phpstan#3128
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