Fix #12363: Spreading an associative array into a generic function/method call may restrict optional arguments to their default values.#5079
Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Conversation
- When spreading an associative constant array into a function/method call, ParametersAcceptorSelector::selectFromArgs() now expands string-keyed constant arrays into individual named type entries instead of collapsing them into a single getIterableValueType() call - This allows GenericParametersAcceptorResolver to correctly map argument types to parameters by name, preventing template types from being incorrectly inferred from default values - Added regression tests for both function calls and class constructors Closes phpstan/phpstan#12363
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When spreading an associative array into a function/method call, template types on optional parameters were incorrectly resolved to their default values instead of the actual provided values. For example,
f(...['x' => 5, 'y' => 'b'])where$yis a templateY of 'a'|'b'with default'a'would reportParameter $y expects 'a', 'b' givenas a false positive.Changes
src/Reflection/ParametersAcceptorSelector.phpinselectFromArgs(): when processing an unpacked argument that is a constant array with all string keys, expand it into individual named type entries instead of collapsing into a singlegetIterableValueType()calltests/PHPStan/Rules/Functions/data/bug-12363.phpfor function callstests/PHPStan/Rules/Methods/data/bug-12363.phpfor class constructor callsCallToFunctionParametersRuleTestandInstantiationRuleTestRoot cause
In
ParametersAcceptorSelector::selectFromArgs(), when encountering an unpacked argument like...['x' => 5, 'y' => 'b'], the code called$type->getIterableValueType()which merged all values intoint|'b'and assigned it to positional index 0. This meantGenericParametersAcceptorResolver::resolve()only saw a type for parameter 0 ($x), while parameter 1 ($y) had no argument type and fell back to its default value'a'for template inference. The templateYwas therefore resolved to'a'instead of'b'.The fix detects constant arrays with all string keys during unpacking and expands them into individual named entries in the
$typesarray. This allowsGenericParametersAcceptorResolver::resolve()to correctly match each value to its corresponding parameter by name, resulting in proper template type inference.Test
Regression tests verify that spreading associative arrays into functions and class constructors with template-typed optional parameters no longer produces false positive errors. Tests cover:
int $x+ optional templateY $y = 'a'called viaf(...['x' => 5, 'y' => 'b'])g(...['y' => 'b'])(was already working, ensures no regression)Fixes phpstan/phpstan#12363