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 3, 2022
1 parent bee8f24 commit 7875ced
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 5 deletions.
5 changes: 3 additions & 2 deletions src/Reflection/InitializerExprTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -454,11 +454,12 @@ public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback): Type
}
} else {
$arrayBuilder->degradeToGeneralArray();
$optional = !$valueType->isIterableAtLeastOnce()->yes() && !$valueType->getIterableValueType()->isIterableAtLeastOnce()->yes();

if (! (new StringType())->isSuperTypeOf($valueType->getIterableKeyType())->no() && $this->phpVersion->supportsArrayUnpackingWithStringKeys()) {
$arrayBuilder->setOffsetValueType($valueType->getIterableKeyType(), $valueType->getIterableValueType());
$arrayBuilder->setOffsetValueType($valueType->getIterableKeyType(), $valueType->getIterableValueType(), $optional);
} else {
$arrayBuilder->setOffsetValueType(new IntegerType(), $valueType->getIterableValueType(), !$valueType->isIterableAtLeastOnce()->yes() && !$valueType->getIterableValueType()->isIterableAtLeastOnce()->yes());
$arrayBuilder->setOffsetValueType(new IntegerType(), $valueType->getIterableValueType(), $optional);
}
}
} else {
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);
}
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 7875ced

Please sign in to comment.