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;
}
}
18 changes: 18 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-9907.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php declare(strict_types = 1);

namespace Bug9907;

use function PHPStan\Testing\assertType;

class HelloWorld
{
/**
* @param 'foo'|'bar' $key
*/
public function sayHello(string $key): void
{
$a = ['id' => null, $key => 'string'];

assertType("array{id: null, foo?: 'string', bar?: 'string'}", $a);
}
}
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);
}

}
6 changes: 6 additions & 0 deletions tests/PHPStan/Rules/Classes/InstantiationRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -609,4 +609,10 @@ public function testBug14251(): void
]);
}

#[RequiresPhp('>= 8.0')]
public function testBug11006(): void
{
$this->analyse([__DIR__ . '/data/bug-11006.php'], []);
}

}
74 changes: 74 additions & 0 deletions tests/PHPStan/Rules/Classes/data/bug-11006.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php // lint >= 8.0

declare(strict_types = 1);

namespace Bug11006;

class ProductParentPayloadDto
{
/** @param null|'size_uk'|'size_us' $SizeAttributeCode */
public function __construct(
public ?string $SizeAttributeCode,
) {
}
}

class AkeneoUpdateProductDto
{
/**
* @param array{
* ean?: array<StringOrNullAttributeDto>,
* osa_sizes?: array<StringAttributeDto>,
* size_uk?: array<StringOrNullAttributeDto>,
* size_us?: array<StringOrNullAttributeDto>,
* } $values
*/
public function __construct(
public array $values,
) {
}
}

class StringOrNullAttributeDto
{
public function __construct(
public ?string $data,
) {
}
}

class StringAttributeDto
{
public function __construct(
public string $data,
) {
}
}


class PhpStanProblem
{
public function example(ProductParentPayloadDto $productParentPayloadDto): void
{
if (null === $productParentPayloadDto->SizeAttributeCode) {
return;
}

$values = [
'ean' => [
new StringOrNullAttributeDto(''),
],
$productParentPayloadDto->SizeAttributeCode => [
new StringOrNullAttributeDto(''),
],
// This part goes wrong
'osa_sizes' => [
new StringAttributeDto(''),
],
];

$productData = new AkeneoUpdateProductDto(
values: $values,
);
}
}
5 changes: 5 additions & 0 deletions tests/PHPStan/Rules/Functions/PrintfParametersRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,9 @@ public function testBug1889(): void
]);
}

public function testBug8774(): void
{
$this->analyse([__DIR__ . '/data/bug-8774.php'], []);
}

}
25 changes: 25 additions & 0 deletions tests/PHPStan/Rules/Functions/data/bug-8774.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php declare(strict_types = 1);

namespace Bug8774;

class ModerateCtrl
{
private const DISABLE_KEYS_AND_LABELS = [
'DisablePosting' => 'Posting on forum and comments',
'DisableAvatar' => 'Avatar and Custom Icon',
];

public static function handleModerate(): void
{
$summaryTemplates = [
'PermissionID' => "Class changed from <b>'%s'</b> to <b>'%s'</b>.",
'Reset' => '%s reset.',
];

foreach (self::DISABLE_KEYS_AND_LABELS as $key => $label) {
$summaryTemplates[$key] = "Disable $label status %s.";
}

echo sprintf($summaryTemplates['Reset'], 'foo');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -821,4 +821,9 @@ public function testBug10595(): void
$this->analyse([__DIR__ . '/data/bug-10595.php'], []);
}

public function testBug14080(): void
{
$this->analyse([__DIR__ . '/data/bug-14080.php'], []);
}

}
19 changes: 19 additions & 0 deletions tests/PHPStan/Rules/Operators/data/bug-14080.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types = 1);

namespace Bug14080;

$queryTotals = ['all' => 0, 'duplicates' => 0];
$queryTypes = ['select', 'update', 'delete', 'insert'];
$queries = [['sql' => 'select', 'time' => 8234], ['sql' => 'select', 'time' => 4558], ['sql' => 'insert', 'time' => 9928]];

$queryTotals['time'] = array_sum(array_column($queries, 'time'));

foreach ($queryTypes as $type) {
$tq = array_filter($queries, fn ($v) => str_starts_with(strtolower($v['sql']), $type));
$tq_time = array_sum(array_column($tq, 'time'));
$queryTotals['all'] += count($tq);
$queryTotals[$type] = [
'count' => count($tq),
'time' => $tq_time / $queryTotals['time'] * 100,
];
}
Loading