Normalize array keys through toArrayKey() in array_fill_keys and array_combine return types#6078
Open
phpstan-bot wants to merge 1 commit into
Open
Conversation
…`array_combine` return types - `ArrayType::fillKeysArray()` now passes the resulting key type through `toArrayKey()`, so `decimal-int-string` (and other integer-like string keys) collapse to `int`, matching how PHP coerces array keys. This mirrors what `ArrayType::flipArray()` already does. - `MixedType::fillKeysArray()` normalizes the key type the same way, so `array_fill_keys` on a `mixed` array no longer yields a `mixed` key type (array keys can only be `int|string`). - `ArrayCombineHelper` (the non-constant path of `array_combine`) had the identical missing normalization and is fixed the same way. - Probed the other value-as-key functions: `array_flip`, `array_count_values` and `array_column` already normalize via `toArrayKey()` and were correct; no change needed there. - Updated existing `array-fill-keys` / `array-combine` expectations that encoded the un-normalized keys (float keys now include `int`, `bool` keys collapse to `int|string`, decimal-int-string keys collapse to `int`).
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
Documenting an array key as
int|decimal-int-stringnormalizes toint, butarray_fill_keys()did not perform this normalization on its result, producingarray<int|decimal-int-string, ...>. Assigning that to anarray<int, ...>property triggered a false positive. The fix runs the computed key type throughType::toArrayKey(), which coerces integer-like string keys tointexactly like PHP does at runtime.Changes
src/Type/ArrayType.php—fillKeysArray()now returnsnew ArrayType($keyType->toArrayKey(), $valueType)in both branches, so the resulting key type is coerced the way PHP coerces array keys (this matchesflipArray(), which already usedtoArrayKey()).src/Type/MixedType.php—fillKeysArray()normalizes the key type throughtoArrayKey()as well, soarray_fill_keys()on amixedarray produces anint|stringkey instead ofmixed.src/Type/Php/ArrayCombineHelper.php— the non-constantarray_combine()path had the same missing normalization; the key type is now passed throughtoArrayKey().array-fill-keys.php,array-fill-keys-php8.phpandarray-combine-php8.phpthat asserted the previous, un-normalized keys.tests/PHPStan/Analyser/nsrt/bug-14980.php.Root cause
array_fill_keys()(andarray_combine(), andarray_fill_keys()onmixed) use the input array's values as keys. PHP coerces those values with the usual array-key rules (decimal-int-strings becomeint, floats/bools/objects are stringified first, then re-coerced). PHPStan'sType::toArrayKey()models exactly this coercion, andarray_flip()/array_count_values()/array_column()already used it — but thearray_fill_keysand non-constantarray_combinepaths built the key type withtoString()(or returned it verbatim) and never appliedtoArrayKey(). As a result the refinement (decimal-int-string, plainmixed, un-truncated floats,bool) leaked into the key type. The pattern is "value-as-key array functions must normalize the key throughtoArrayKey()"; every affected location now does.Test
bug-14980.phpassertsarray_fill_keys()onlist<int|decimal-int-string>yieldsarray<int, true>(the reported case), plus the numeric-string,mixed-array andarray_combineanalogues.array-fill-keys/array-combinefixtures were updated to the now-correct normalized keys (float keys includeint,boolkeys collapse toint|string, decimal-int-string keys collapse toint).Fixes phpstan/phpstan#14980