Skip to content

Commit 013d30e

Browse files
committed
support HasOffset* types
1 parent fc51df8 commit 013d30e

File tree

2 files changed

+29
-7
lines changed

2 files changed

+29
-7
lines changed

src/Type/Php/ArrayMergeFunctionDynamicReturnTypeExtension.php

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PHPStan\TrinaryLogic;
1010
use PHPStan\Type\Accessory\AccessoryArrayListType;
1111
use PHPStan\Type\Accessory\HasOffsetType;
12+
use PHPStan\Type\Accessory\HasOffsetValueType;
1213
use PHPStan\Type\Accessory\NonEmptyArrayType;
1314
use PHPStan\Type\ArrayType;
1415
use PHPStan\Type\Constant\ConstantArrayType;
@@ -20,6 +21,7 @@
2021
use PHPStan\Type\NeverType;
2122
use PHPStan\Type\Type;
2223
use PHPStan\Type\TypeCombinator;
24+
use PHPStan\Type\TypeUtils;
2325
use function array_keys;
2426
use function count;
2527
use function in_array;
@@ -74,7 +76,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
7476
static fn (Type $argType) => $argType->isConstantArray(),
7577
);
7678

77-
$nonOptionalConstKeys = [];
79+
$offsetTypes = [];
7880
$newArrayBuilder = null;
7981
if ($allConstant->yes()) {
8082
$newArrayBuilder = ConstantArrayTypeBuilder::createEmpty();
@@ -90,11 +92,24 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
9092
continue;
9193
}
9294

93-
$nonOptionalConstKeys[] = $keyType;
95+
$offsetTypes[$keyType->getValue()] = new HasOffsetType($keyType);
9496
}
9597
}
9698

9799
if ($newArrayBuilder === null) {
100+
foreach (TypeUtils::getAccessoryTypes($argType) as $accessoryType) {
101+
if (
102+
!($accessoryType instanceof HasOffsetType)
103+
&& !($accessoryType instanceof HasOffsetValueType)
104+
) {
105+
continue;
106+
}
107+
108+
$offsetType = $accessoryType->getOffsetType();
109+
$offsetTypes[$offsetType->getValue()] = new HasOffsetType($offsetType);
110+
111+
}
112+
98113
continue;
99114
}
100115

@@ -136,11 +151,6 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
136151
return new ConstantArrayType([], []);
137152
}
138153

139-
$offsetTypes = [];
140-
foreach ($nonOptionalConstKeys as $constKey) {
141-
$offsetTypes[] = new HasOffsetType($constKey);
142-
}
143-
144154
$arrayType = new ArrayType(
145155
$keyType,
146156
TypeCombinator::union(...$valueTypes),

tests/PHPStan/Analyser/nsrt/array-merge-const-non-const.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,15 @@ function doOptKeys(array $array, array $arr2): void {
4040
function doOptShapeKeys(array $array, array $arr2): void {
4141
assertType("non-empty-array&hasOffset('b')", array_merge($arr2, $array));
4242
}
43+
44+
function hasOffsetKeys(array $array, array $arr2): void {
45+
if (array_key_exists('b', $array)) {
46+
assertType("non-empty-array&hasOffset('b')", array_merge($arr2, $array));
47+
}
48+
}
49+
50+
function hasOffsetValueKeys(array $array, array $arr2): void {
51+
$array['b'] = 123;
52+
53+
assertType("non-empty-array&hasOffset('b')", array_merge($arr2, $array));
54+
}

0 commit comments

Comments
 (0)