Skip to content

Commit 82dfce1

Browse files
authored
Array after array_push / array_unshift call can still be empty
1 parent d60c7dc commit 82dfce1

File tree

5 files changed

+67
-10
lines changed

5 files changed

+67
-10
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,7 +1825,7 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
18251825

18261826
/**
18271827
* @param Arg[] $callArgs
1828-
* @param callable(?Type, Type, bool=): void $setOffsetValueType
1828+
* @param callable(?Type, Type, bool): void $setOffsetValueType
18291829
*/
18301830
$setOffsetValueTypes = static function (Scope $scope, array $callArgs, callable $setOffsetValueType, ?bool &$nonConstantArrayWasUnpacked = null): void {
18311831
foreach ($callArgs as $callArg) {
@@ -1850,7 +1850,7 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
18501850
}
18511851
continue;
18521852
}
1853-
$setOffsetValueType(null, $callArgType);
1853+
$setOffsetValueType(null, $callArgType, false);
18541854
}
18551855
};
18561856

@@ -1861,7 +1861,7 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
18611861
$setOffsetValueTypes(
18621862
$scope,
18631863
$callArgs,
1864-
static function (?Type $offsetType, Type $valueType, bool $optional = false) use (&$arrayTypeBuilder): void {
1864+
static function (?Type $offsetType, Type $valueType, bool $optional) use (&$arrayTypeBuilder): void {
18651865
$arrayTypeBuilder->setOffsetValueType($offsetType, $valueType, $optional);
18661866
},
18671867
$nonConstantArrayWasUnpacked,
@@ -1890,8 +1890,14 @@ static function (?Type $offsetType, Type $valueType, bool $optional = false) use
18901890
$setOffsetValueTypes(
18911891
$scope,
18921892
$callArgs,
1893-
static function (?Type $offsetType, Type $valueType) use (&$arrayType): void {
1893+
static function (?Type $offsetType, Type $valueType, bool $optional) use (&$arrayType): void {
1894+
$isIterableAtLeastOnce = $arrayType->isIterableAtLeastOnce()->yes() || !$optional;
18941895
$arrayType = $arrayType->setOffsetValueType($offsetType, $valueType);
1896+
if ($isIterableAtLeastOnce) {
1897+
return;
1898+
}
1899+
1900+
$arrayType = TypeCombinator::union(...TypeUtils::getArrays($arrayType));
18951901
},
18961902
);
18971903
}

tests/PHPStan/Analyser/data/array-push.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@
1313
* @param non-empty-array<int> $c
1414
* @param array<int|string> $d
1515
*/
16-
function arrayPush(array $a, array $b, array $c, array $d): void
16+
function arrayPush(array $a, array $b, array $c, array $d, array $arr): void
1717
{
1818
array_push($a, ...$b);
19-
assertType('non-empty-array<int|string>', $a);
19+
assertType('array<int|string>', $a);
20+
21+
/** @var non-empty-array<string> $arr */
22+
array_push($arr, ...$b);
23+
assertType('non-empty-array<int|string>', $arr);
2024

2125
array_push($b, ...[]);
2226
assertType('array<int>', $b);
@@ -27,7 +31,7 @@ function arrayPush(array $a, array $b, array $c, array $d): void
2731
/** @var array<bool|null> $d1 */
2832
$d1 = [];
2933
array_push($d, ...$d1);
30-
assertType('non-empty-array<bool|int|string|null>', $d);
34+
assertType('array<bool|int|string|null>', $d);
3135
}
3236

3337
function arrayPushConstantArray(): void

tests/PHPStan/Analyser/data/array-unshift.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@
1313
* @param non-empty-array<int> $c
1414
* @param array<int|string> $d
1515
*/
16-
function arrayUnshift(array $a, array $b, array $c, array $d): void
16+
function arrayUnshift(array $a, array $b, array $c, array $d, array $arr): void
1717
{
1818
array_unshift($a, ...$b);
19-
assertType('non-empty-array<int|string>', $a);
19+
assertType('array<int|string>', $a);
20+
21+
/** @var non-empty-array<string> $arr */
22+
array_unshift($arr, ...$b);
23+
assertType('non-empty-array<int|string>', $arr);
2024

2125
array_unshift($b, ...[]);
2226
assertType('array<int>', $b);
@@ -27,7 +31,7 @@ function arrayUnshift(array $a, array $b, array $c, array $d): void
2731
/** @var array<bool|null> $d1 */
2832
$d1 = [];
2933
array_unshift($d, ...$d1);
30-
assertType('non-empty-array<bool|int|string|null>', $d);
34+
assertType('array<bool|int|string|null>', $d);
3135
}
3236

3337
function arrayUnshiftConstantArray(): void

tests/PHPStan/Rules/Variables/EmptyRuleTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,12 @@ public function testBug7318(): void
169169
$this->analyse([__DIR__ . '/../Properties/data/bug-7318.php'], []);
170170
}
171171

172+
public function testBug7424(): void
173+
{
174+
$this->treatPhpDocTypesAsCertain = true;
175+
$this->strictUnnecessaryNullsafePropertyFetch = false;
176+
177+
$this->analyse([__DIR__ . '/data/bug-7424.php'], []);
178+
}
179+
172180
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Bug7424;
4+
5+
class Test
6+
{
7+
public function run(): void
8+
{
9+
$data = $this->getInitData();
10+
11+
array_push($data, ...$this->getExtra());
12+
13+
if (empty($data)) {
14+
return;
15+
}
16+
17+
echo 'Proceeding to process data';
18+
}
19+
20+
/**
21+
* @return string[]
22+
*/
23+
protected function getInitData(): array
24+
{
25+
return [];
26+
}
27+
28+
/**
29+
* @return string[]
30+
*/
31+
protected function getExtra(): array
32+
{
33+
return [];
34+
}
35+
}

0 commit comments

Comments
 (0)