diff --git a/src/Type/ArrayType.php b/src/Type/ArrayType.php index a951f13c24..b24fbc64fc 100644 --- a/src/Type/ArrayType.php +++ b/src/Type/ArrayType.php @@ -484,10 +484,10 @@ public function fillKeysArray(Type $valueType): Type return $stringKeyType; } - return new ArrayType($stringKeyType, $valueType); + return new ArrayType($stringKeyType->toArrayKey(), $valueType); } - return new ArrayType($itemType, $valueType); + return new ArrayType($itemType->toArrayKey(), $valueType); } public function flipArray(): Type diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 9b07022d5e..4633760d19 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -223,7 +223,7 @@ public function fillKeysArray(Type $valueType): Type return new ErrorType(); } - return new ArrayType($this->getIterableValueType(), $valueType); + return new ArrayType($this->getIterableValueType()->toArrayKey(), $valueType); } public function flipArray(): Type diff --git a/src/Type/Php/ArrayCombineHelper.php b/src/Type/Php/ArrayCombineHelper.php index b8bb3f445a..d4744cfe02 100644 --- a/src/Type/Php/ArrayCombineHelper.php +++ b/src/Type/Php/ArrayCombineHelper.php @@ -98,9 +98,9 @@ public function getReturnAndThrowType(Expr $firstArg, Expr $secondArg, Scope $sc return [new NeverType(), TrinaryLogic::createNo()]; } - $keyType = $itemType->toString(); + $keyType = $itemType->toString()->toArrayKey(); } else { - $keyType = $itemType; + $keyType = $itemType->toArrayKey(); } } else { $keyType = new MixedType(); diff --git a/tests/PHPStan/Analyser/nsrt/array-combine-php8.php b/tests/PHPStan/Analyser/nsrt/array-combine-php8.php index 1a1a78c411..76da9400e5 100644 --- a/tests/PHPStan/Analyser/nsrt/array-combine-php8.php +++ b/tests/PHPStan/Analyser/nsrt/array-combine-php8.php @@ -110,7 +110,7 @@ function withUnionConstArraysDifferentArraysCount(): void } } - assertType("non-empty-array<1|'2'|'3', 'apple'|'avocado'|'banana'|'pear'>", array_combine($a, $b)); + assertType("non-empty-array<1|2|3, 'apple'|'avocado'|'banana'|'pear'>", array_combine($a, $b)); } function withUnionConstArraysAndDifferentFiniteKeysCount(bool $bool): void @@ -123,7 +123,7 @@ function withUnionConstArraysAndDifferentFiniteKeysCount(bool $bool): void $b = ['apple', 'banana']; } - assertType("non-empty-array<''|'1'|'2', 'apple'|'avocado'|'banana'>", array_combine($a, $b)); + assertType("non-empty-array<1|2|'', 'apple'|'avocado'|'banana'>", array_combine($a, $b)); } /** diff --git a/tests/PHPStan/Analyser/nsrt/array-fill-keys-php8.php b/tests/PHPStan/Analyser/nsrt/array-fill-keys-php8.php index 4710482534..07c06367dc 100644 --- a/tests/PHPStan/Analyser/nsrt/array-fill-keys-php8.php +++ b/tests/PHPStan/Analyser/nsrt/array-fill-keys-php8.php @@ -7,7 +7,7 @@ function mixedAndSubtractedArray($mixed): void { if (is_array($mixed)) { - assertType("array", array_fill_keys($mixed, 'b')); + assertType("array<'b'>", array_fill_keys($mixed, 'b')); } else { assertType("*NEVER*", array_fill_keys($mixed, 'b')); } diff --git a/tests/PHPStan/Analyser/nsrt/array-fill-keys.php b/tests/PHPStan/Analyser/nsrt/array-fill-keys.php index 231b2dcbe5..eabf069c86 100644 --- a/tests/PHPStan/Analyser/nsrt/array-fill-keys.php +++ b/tests/PHPStan/Analyser/nsrt/array-fill-keys.php @@ -91,17 +91,17 @@ function withNotConstantArray(array $foo, array $bar, array $baz, array $floats, assertType("array", array_fill_keys($foo, null)); assertType("array", array_fill_keys($bar, null)); assertType("array<'foo', null>", array_fill_keys($baz, null)); - assertType("array", array_fill_keys($floats, null)); - assertType("array", array_fill_keys($mixed, null)); + assertType("array", array_fill_keys($floats, null)); + assertType("array", array_fill_keys($mixed, null)); assertType('array', array_fill_keys($list, null)); assertType('*ERROR*', array_fill_keys($objectsWithoutToString, null)); if (array_key_exists(17, $mixed)) { - assertType('non-empty-array', array_fill_keys($mixed, null)); + assertType('non-empty-array', array_fill_keys($mixed, null)); } if (array_key_exists(17, $mixed) && $mixed[17] === 'foo') { - assertType('non-empty-array', array_fill_keys($mixed, null)); + assertType('non-empty-array', array_fill_keys($mixed, null)); } } diff --git a/tests/PHPStan/Analyser/nsrt/bug-14980.php b/tests/PHPStan/Analyser/nsrt/bug-14980.php new file mode 100644 index 0000000000..eb62e95e2a --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-14980.php @@ -0,0 +1,82 @@ += 8.0 + +declare(strict_types = 1); + +namespace Bug14980; + +use function PHPStan\Testing\assertType; + +/** + * @param list $ints + */ +function decimalIntStringKeys(array $ints): void +{ + $keys = []; + foreach ($ints as $int) { + $keys[] = $int; + $keys[] = (string) $int; + } + + assertType('list', $keys); + assertType('array', array_fill_keys($keys, true)); +} + +/** + * @param list $keys + */ +function numericStringKeys(array $keys): void +{ + assertType('array', array_fill_keys($keys, true)); +} + +function fillKeysMixedArray(mixed $m): void +{ + if (is_array($m)) { + assertType('array', array_fill_keys($m, true)); + } +} + +/** + * @param list $ints + */ +function combineDecimalIntStringKeys(array $ints): void +{ + $keys = []; + foreach ($ints as $int) { + $keys[] = $int; + $keys[] = (string) $int; + } + + assertType('array', array_combine($keys, $keys)); +} + +/** + * @param list $keys + * @param list $values + */ +function combineNumericStringKeys(array $keys, array $values): void +{ + assertType('array', array_combine($keys, $values)); +} + +class DecimalIntBug +{ + + /** @var array */ + private array $data = []; + + /** + * @param list $ints + */ + public function set(array $ints): void + { + $keys = []; + foreach ($ints as $int) { + $keys[] = $int; + $keys[] = (string) $int; + } + + $this->data = array_fill_keys($keys, true); + } + +}