Skip to content

Commit 7b417c7

Browse files
committed
TypeSpecifier - support IntegerRangeType with count()
1 parent 9cc7734 commit 7b417c7

File tree

3 files changed

+57
-5
lines changed

3 files changed

+57
-5
lines changed

src/Analyser/TypeSpecifier.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ public function specifyTypesInCondition(
219219
$newContext = $newContext->negate();
220220
}
221221
$argType = $scope->getType($exprNode->args[0]->value);
222-
if ((new ArrayType(new MixedType(), new MixedType()))->isSuperTypeOf($argType)->yes()) {
222+
if ($argType->isArray()->yes()) {
223223
return $this->create($exprNode->args[0]->value, new NonEmptyArrayType(), $newContext, false, $scope);
224224
}
225225
}
@@ -389,7 +389,6 @@ public function specifyTypesInCondition(
389389
&& count($expr->left->args) === 1
390390
&& $expr->left->name instanceof Name
391391
&& strtolower((string) $expr->left->name) === 'count'
392-
&& $rightType instanceof ConstantIntegerType
393392
&& (
394393
!$expr->right instanceof FuncCall
395394
|| !$expr->right->name instanceof Name
@@ -415,11 +414,14 @@ public function specifyTypesInCondition(
415414
&& count($expr->right->args) === 1
416415
&& $expr->right->name instanceof Name
417416
&& strtolower((string) $expr->right->name) === 'count'
418-
&& $leftType instanceof ConstantIntegerType
417+
&& (new IntegerType())->isSuperTypeOf($leftType)->yes()
419418
) {
420-
if ($context->truthy() || $leftType->getValue() + $offset === 1) {
419+
if (
420+
$context->truthy() && (IntegerRangeType::createAllGreaterThanOrEqualTo(1 - $offset)->isSuperTypeOf($leftType)->yes())
421+
|| ($context->falsey() && (new ConstantIntegerType(1 - $offset))->isSuperTypeOf($leftType)->yes())
422+
) {
421423
$argType = $scope->getType($expr->right->args[0]->value);
422-
if ((new ArrayType(new MixedType(), new MixedType()))->isSuperTypeOf($argType)->yes()) {
424+
if ($argType->isArray()->yes()) {
423425
$result = $result->unionWith($this->create($expr->right->args[0]->value, new NonEmptyArrayType(), $context, false, $scope));
424426
}
425427
}

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10336,6 +10336,7 @@ public function dataFileAsserts(): iterable
1033610336
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4434.php');
1033710337
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4231.php');
1033810338
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4287.php');
10339+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4700.php');
1033910340
}
1034010341

1034110342
/**
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Bug4700;
4+
5+
use function PHPStan\Analyser\assertType;
6+
7+
function(array $array, int $count): void {
8+
if ($count < 1) {
9+
return;
10+
}
11+
12+
assertType('int<1, max>', $count);
13+
14+
$a = [];
15+
if (isset($array['a'])) $a[] = $array['a'];
16+
if (isset($array['b'])) $a[] = $array['b'];
17+
if (isset($array['c'])) $a[] = $array['c'];
18+
if (isset($array['d'])) $a[] = $array['d'];
19+
if (isset($array['e'])) $a[] = $array['e'];
20+
if (count($a) >= $count) {
21+
assertType('1|2|3|4|5', count($a));
22+
assertType('array(0 => mixed~null, ?1 => mixed~null, ?2 => mixed~null, ?3 => mixed~null, ?4 => mixed~null)', $a);
23+
} else {
24+
assertType('0|1|2|3|4|5', count($a));
25+
assertType('array()|array(0 => mixed~null, ?1 => mixed~null, ?2 => mixed~null, ?3 => mixed~null, ?4 => mixed~null)', $a);
26+
}
27+
};
28+
29+
function(array $array, int $count): void {
30+
if ($count < 1) {
31+
return;
32+
}
33+
34+
assertType('int<1, max>', $count);
35+
36+
$a = [];
37+
if (isset($array['a'])) $a[] = $array['a'];
38+
if (isset($array['b'])) $a[] = $array['b'];
39+
if (isset($array['c'])) $a[] = $array['c'];
40+
if (isset($array['d'])) $a[] = $array['d'];
41+
if (isset($array['e'])) $a[] = $array['e'];
42+
if (count($a) > $count) {
43+
assertType('2|3|4|5', count($a));
44+
assertType('array(0 => mixed~null, ?1 => mixed~null, ?2 => mixed~null, ?3 => mixed~null, ?4 => mixed~null)', $a);
45+
} else {
46+
assertType('0|1|2|3|4|5', count($a));
47+
assertType('array()|array(0 => mixed~null, ?1 => mixed~null, ?2 => mixed~null, ?3 => mixed~null, ?4 => mixed~null)', $a);
48+
}
49+
};

0 commit comments

Comments
 (0)