Skip to content

Commit

Permalink
Fix Array_ expr type resolving with unpacked array items
Browse files Browse the repository at this point in the history
  • Loading branch information
herndlm committed Aug 5, 2022
1 parent 2ea6efe commit cb46f97
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 10 deletions.
9 changes: 4 additions & 5 deletions src/Reflection/InitializerExprTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -455,11 +455,10 @@ public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback): Type
} else {
$arrayBuilder->degradeToGeneralArray();

if (! (new StringType())->isSuperTypeOf($valueType->getIterableKeyType())->no() && $this->phpVersion->supportsArrayUnpackingWithStringKeys()) {
$arrayBuilder->setOffsetValueType($valueType->getIterableKeyType(), $valueType->getIterableValueType());
} else {
$arrayBuilder->setOffsetValueType(new IntegerType(), $valueType->getIterableValueType(), !$valueType->isIterableAtLeastOnce()->yes() && !$valueType->getIterableValueType()->isIterableAtLeastOnce()->yes());
}
$offsetType = $this->phpVersion->supportsArrayUnpackingWithStringKeys() && !(new StringType())->isSuperTypeOf($valueType->getIterableKeyType())->no()
? $valueType->getIterableKeyType()
: new IntegerType();
$arrayBuilder->setOffsetValueType($offsetType, $valueType->getIterableValueType(), !$valueType->isIterableAtLeastOnce()->yes());
}
} else {
$arrayBuilder->setOffsetValueType(
Expand Down
28 changes: 25 additions & 3 deletions tests/PHPStan/Analyser/data/array-unpacking-string-keys.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function foo(array $a, array $b)
{
$c = [...$a, ...$b];

assertType('non-empty-array<int|string, int>', $c);
assertType('array<int|string, int>', $c);
}

/**
Expand All @@ -31,7 +31,7 @@ function bar(array $a, array $b)
{
$c = [...$a, ...$b];

assertType('non-empty-array<int>', $c);
assertType('array<int>', $c);
}

/**
Expand All @@ -42,5 +42,27 @@ function baz(array $a, array $b)
{
$c = [...$a, ...$b];

assertType('non-empty-array<string, int>', $c);
assertType('array<string, int>', $c);
}

/**
* @param non-empty-array<string, int> $a
* @param array<int, int> $b
*/
function nonEmptyArray1(array $a, array $b)
{
$c = [...$a, ...$b];

assertType('non-empty-array<int|string, int>', $c);
}

/**
* @param array<string, int> $a
* @param non-empty-array<int, int> $b
*/
function nonEmptyArray2(array $a, array $b)
{
$c = [...$a, ...$b];

assertType('non-empty-array<int|string, int>', $c);
}
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/data/bug-5287-php81.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function foo(array $arr): void
function foo2(array $arr): void
{
$arrSpread = [...$arr];
assertType('non-empty-array<int, non-empty-array>', $arrSpread);
assertType('array<int, non-empty-array>', $arrSpread);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/data/bug-5287.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function foo(array $arr): void
function foo2(array $arr): void
{
$arrSpread = [...$arr];
assertType('non-empty-array<int, non-empty-array>', $arrSpread);
assertType('array<int, non-empty-array>', $arrSpread);
}

/**
Expand Down
8 changes: 8 additions & 0 deletions tests/PHPStan/Rules/Variables/EmptyRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,12 @@ public function testBug7424(): void
$this->analyse([__DIR__ . '/data/bug-7424.php'], []);
}

public function testBug7724(): void
{
$this->treatPhpDocTypesAsCertain = true;
$this->strictUnnecessaryNullsafePropertyFetch = false;

$this->analyse([__DIR__ . '/data/bug-7724.php'], []);
}

}
22 changes: 22 additions & 0 deletions tests/PHPStan/Rules/Variables/data/bug-7724.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php // lint >= 7.4

declare(strict_types = 1);

namespace Bug7724;

$array = [];

/**
* @return int[]
*/
function getElements(): array {
$empty = rand(0, 1);

return $empty ? [] : [1];
}

$array = [...$array, ...getElements()];

if (false === empty($array)) {

}

0 comments on commit cb46f97

Please sign in to comment.