Skip to content
22 changes: 22 additions & 0 deletions src/Type/Constant/ConstantArrayTypeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt
}
if (count($scalarTypes) > 0 && count($scalarTypes) < self::ARRAY_COUNT_LIMIT) {
$match = true;
$hasMatch = false;
$valueTypes = $this->valueTypes;
foreach ($scalarTypes as $scalarType) {
$offsetMatch = false;
Expand All @@ -273,6 +274,7 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt
}

if ($offsetMatch) {
$hasMatch = true;
continue;
}

Expand All @@ -283,6 +285,26 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt
$this->valueTypes = $valueTypes;
return;
}

if (!$hasMatch && count($this->keyTypes) > 0) {
foreach ($scalarTypes as $scalarType) {
$this->keyTypes[] = $scalarType;
$this->valueTypes[] = $valueType;
$this->optionalKeys[] = count($this->keyTypes) - 1;
}

$this->isList = TrinaryLogic::createNo();

if (
!$this->disableArrayDegradation
&& count($this->keyTypes) > self::ARRAY_COUNT_LIMIT
) {
$this->degradeToGeneralArray = true;
$this->oversized = true;
}

return;
}
}

$this->isList = TrinaryLogic::createNo();
Expand Down
4 changes: 2 additions & 2 deletions tests/PHPStan/Analyser/nsrt/array-fill-keys.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ function withObjectKey() : array
function withUnionKeys(): void
{
$arr1 = ['foo', rand(0, 1) ? 'bar1' : 'bar2', 'baz'];
assertType("non-empty-array<'bar1'|'bar2'|'baz'|'foo', 'b'>", array_fill_keys($arr1, 'b'));
assertType("array{foo: 'b', bar1?: 'b', bar2?: 'b', baz: 'b'}", array_fill_keys($arr1, 'b'));

$arr2 = ['foo'];
if (rand(0, 1)) {
$arr2[] = 'bar';
}
$arr2[] = 'baz';
assertType("non-empty-array<'bar'|'baz'|'foo', 'b'>", array_fill_keys($arr2, 'b'));
assertType("array{foo: 'b', bar?: 'b', baz?: 'b'}", array_fill_keys($arr2, 'b'));
}

function withOptionalKeys(): void
Expand Down
19 changes: 19 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-12665.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types = 1);

namespace Bug12665;

use function PHPStan\Testing\assertType;

class Broken
{
/** @return array{a: string, b: int, c: int} */
public function break(string $s, int $i): array
{
$array = ['a' => $s];
foreach (['b', 'c'] as $letter) {
$array[$letter] = $i;
}
assertType('array{a: string, b?: int, c?: int}', $array);
return $array;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace SetConstantUnionOffsetOnConstantArray;

use function PHPStan\Testing\assertType;

class Foo
{

/**
* @param array{foo: int} $a
*/
public function doFoo(array $a): void
{
$k = rand(0, 1) ? 'a' : 'b';
$a[$k] = 256;
assertType('array{foo: int, a?: 256, b?: 256}', $a);
}

}
Loading