Skip to content

Commit 0be769d

Browse files
authored
Cover non-empty-array in array_merge
1 parent 9ee914b commit 0be769d

File tree

3 files changed

+26
-7
lines changed

3 files changed

+26
-7
lines changed

src/Type/Php/ArrayMergeFunctionDynamicReturnTypeExtension.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Reflection\FunctionReflection;
88
use PHPStan\Reflection\ParametersAcceptorSelector;
9+
use PHPStan\Type\Accessory\NonEmptyArrayType;
910
use PHPStan\Type\ArrayType;
1011
use PHPStan\Type\GeneralizePrecision;
1112
use PHPStan\Type\Type;
@@ -29,6 +30,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
2930

3031
$keyTypes = [];
3132
$valueTypes = [];
33+
$nonEmpty = false;
3234
foreach ($functionCall->args as $arg) {
3335
$argType = $scope->getType($arg->value);
3436
if ($arg->unpack) {
@@ -42,12 +44,24 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
4244

4345
$keyTypes[] = TypeUtils::generalizeType($argType->getIterableKeyType(), GeneralizePrecision::moreSpecific());
4446
$valueTypes[] = $argType->getIterableValueType();
47+
48+
if (!$argType->isIterableAtLeastOnce()->yes()) {
49+
continue;
50+
}
51+
52+
$nonEmpty = true;
4553
}
4654

47-
return new ArrayType(
55+
$arrayType = new ArrayType(
4856
TypeCombinator::union(...$keyTypes),
4957
TypeCombinator::union(...$valueTypes)
5058
);
59+
60+
if ($nonEmpty) {
61+
$arrayType = TypeCombinator::intersect($arrayType, new NonEmptyArrayType());
62+
}
63+
64+
return $arrayType;
5165
}
5266

5367
}

tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5129,31 +5129,31 @@ public function dataArrayFunctions(): array
51295129
'array_values($generalStringKeys)',
51305130
],
51315131
[
5132-
'array<int|non-empty-string, stdClass>',
5132+
'array<int|non-empty-string, stdClass>&nonEmpty',
51335133
'array_merge($stringOrIntegerKeys)',
51345134
],
51355135
[
51365136
'array<int|string, DateTimeImmutable|int>',
51375137
'array_merge($generalStringKeys, $generalDateTimeValues)',
51385138
],
51395139
[
5140-
'array<int|string, int|stdClass>',
5140+
'array<int|string, int|stdClass>&nonEmpty',
51415141
'array_merge($generalStringKeys, $stringOrIntegerKeys)',
51425142
],
51435143
[
5144-
'array<int|string, int|stdClass>',
5144+
'array<int|string, int|stdClass>&nonEmpty',
51455145
'array_merge($stringOrIntegerKeys, $generalStringKeys)',
51465146
],
51475147
[
5148-
'array<int|non-empty-string, \'foo\'|stdClass>',
5148+
'array<int|non-empty-string, \'foo\'|stdClass>&nonEmpty',
51495149
'array_merge($stringKeys, $stringOrIntegerKeys)',
51505150
],
51515151
[
5152-
'array<int|non-empty-string, \'foo\'|stdClass>',
5152+
'array<int|non-empty-string, \'foo\'|stdClass>&nonEmpty',
51535153
'array_merge($stringOrIntegerKeys, $stringKeys)',
51545154
],
51555155
[
5156-
'array<int|non-empty-string, 2|4|\'a\'|\'b\'|\'green\'|\'red\'|\'trapezoid\'>',
5156+
'array<int|non-empty-string, 2|4|\'a\'|\'b\'|\'green\'|\'red\'|\'trapezoid\'>&nonEmpty',
51575157
'array_merge(array("color" => "red", 2, 4), array("a", "b", "color" => "green", "shape" => "trapezoid", 4))',
51585158
],
51595159
[

tests/PHPStan/Analyser/data/non-empty-array.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,10 @@ public function arrayFunctions($array, $list): void
4242
{
4343
assertType('array&nonEmpty', array_combine($array, $array));
4444
assertType('array&nonEmpty', array_combine($list, $list));
45+
46+
assertType('array&nonEmpty', array_merge($array));
47+
assertType('array&nonEmpty', array_merge([], $array));
48+
assertType('array&nonEmpty', array_merge($array, []));
49+
assertType('array&nonEmpty', array_merge($array, $array));
4550
}
4651
}

0 commit comments

Comments
 (0)