Skip to content

Fix phpstan/phpstan#14325: Incorrect type inference in implode call with list<string> inside of closure#5248

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

Fix phpstan/phpstan#14325: Incorrect type inference in implode call with list<string> inside of closure#5248
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-7n9rqwg

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When a closure was assigned to a variable with a @param PHPDoc (e.g. @param list<string> $array), the PHPDoc types were not applied to the closure's parameters. This caused type degradation inside the closure body — for example list<string> became plain array.

Changes

  • Added resolveClosurePhpDocParameterTypes() method in src/Analyser/NodeScopeResolver.php that extracts @param tags from the PHPDoc comment on the parent statement and matches them to closure parameters
  • In processClosureNode(), applied the resolved PHPDoc parameter types to the closure scope after entering the anonymous function, overriding the expression types while preserving native types
  • Updated tests/PHPStan/Analyser/nsrt/count-type.php to reflect that closures now correctly receive their PHPDoc generic types (e.g. ArrayObject<int, mixed> instead of bare ArrayObject)

Root cause

The PHPDoc @param tags on a statement like $func = function(array $array): void {} are attached to the Stmt\Expression node, not the Expr\Closure node itself. While regular functions (Stmt\Function_) have their PHPDoc resolved via getPhpDocs() and applied through enterFunction(), closures only used native type hints (via getFunctionType()) when setting up their parameter scope in enterAnonymousFunctionWithoutReflection(). The fix reads the PHPDoc from the parent statement and applies @param types to the closure scope.

Test

Added tests/PHPStan/Analyser/nsrt/bug-14325.php with assertions verifying that:

  • Regular functions correctly infer list<string> from @param (baseline)
  • Closures assigned to variables correctly infer list<string> from @param
  • Closures inside class methods correctly infer list<string> from @param
  • Array push ($array[] = 'bar') correctly narrows to non-empty-list<string> in all cases

Fixes phpstan/phpstan#14325

…eters

- Added resolveClosurePhpDocParameterTypes() to extract @param types from PHPDoc
  comments on the statement containing a closure assignment
- Applied resolved PHPDoc parameter types to the closure scope in processClosureNode()
- Updated count-type test expectations to reflect correct generic types
- New regression test in tests/PHPStan/Analyser/nsrt/bug-14325.php
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