Skip to content

Commit 30abaae

Browse files
committed
take HasOffset*Type into account
1 parent e852dc5 commit 30abaae

File tree

2 files changed

+45
-4
lines changed

2 files changed

+45
-4
lines changed

src/Type/IntersectionType.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
use function in_array;
5454
use function is_int;
5555
use function ksort;
56+
use function max;
5657
use function md5;
5758
use function sprintf;
5859
use function strcasecmp;
@@ -680,7 +681,25 @@ public function isIterableAtLeastOnce(): TrinaryLogic
680681

681682
public function getArraySize(): Type
682683
{
683-
return $this->intersectTypes(static fn (Type $type): Type => $type->getArraySize());
684+
$arraySize = $this->intersectTypes(static fn (Type $type): Type => $type->getArraySize());
685+
686+
if ($arraySize instanceof IntegerRangeType) {
687+
$knownOffsets = [];
688+
foreach ($this->types as $type) {
689+
if ($type instanceof HasOffsetValueType) {
690+
$knownOffsets[$type->getOffsetType()->getValue()] = true;
691+
}
692+
if (!($type instanceof HasOffsetType)) {
693+
continue;
694+
}
695+
696+
$knownOffsets[$type->getOffsetType()->getValue()] = true;
697+
}
698+
699+
return IntegerRangeType::fromInterval(max(count($knownOffsets), $arraySize->getMin()), $arraySize->getMax());
700+
}
701+
702+
return $arraySize;
684703
}
685704

686705
public function getIterableKeyType(): Type

tests/PHPStan/Analyser/nsrt/count-recursive.php

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,36 @@ public function countConstantArray(array $anotherArray): void {
116116
assertType('int<1, max>', count($arr, COUNT_RECURSIVE));
117117

118118
$arr = [1, 2, 3, $anotherArray];
119+
assertType('array{1, 2, 3, array}', $arr);
119120
assertType('4', count($arr));
120121
assertType('4', count($arr, COUNT_NORMAL));
121122
assertType('int<1, max>', count($arr, COUNT_RECURSIVE)); // could be int<4, max>
122123

123124
$arr = [1, 2, 3] + $anotherArray;
124125
assertType('non-empty-array&hasOffsetValue(0, 1)&hasOffsetValue(1, 2)&hasOffsetValue(2, 3)', $arr);
125-
assertType('int<1, max>', count($arr)); // could be int<3, max>
126-
assertType('int<1, max>', count($arr, COUNT_NORMAL)); // could be int<3, max>
127-
assertType('int<1, max>', count($arr, COUNT_RECURSIVE));
126+
assertType('int<3, max>', count($arr));
127+
assertType('int<3, max>', count($arr, COUNT_NORMAL));
128+
assertType('int<1, max>', count($arr, COUNT_RECURSIVE)); // could be int<3, max>
129+
}
130+
131+
public function countAfterKeyExists(array $array, int $i): void {
132+
if (array_key_exists(5, $array)) {
133+
assertType('non-empty-array&hasOffset(5)', $array);
134+
assertType('int<1, max>', count($array));
135+
}
136+
137+
if ($array !== []) {
138+
assertType('non-empty-array', $array);
139+
assertType('int<1, max>', count($array));
140+
if (array_key_exists(5, $array)) {
141+
assertType('non-empty-array&hasOffset(5)', $array);
142+
assertType('int<1, max>', count($array));
143+
144+
if (array_key_exists(15, $array)) {
145+
assertType('non-empty-array&hasOffset(15)&hasOffset(5)', $array);
146+
assertType('int<2, max>', count($array));
147+
}
148+
}
149+
}
128150
}
129151
}

0 commit comments

Comments
 (0)