Skip to content

Commit 6b2afbc

Browse files
committed
Invalidate count($array) after array_shift()
1 parent 402b34a commit 6b2afbc

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1616,7 +1616,9 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
16161616
) {
16171617
$arrayArg = $expr->args[0]->value;
16181618
$constantArrays = TypeUtils::getConstantArrays($scope->getType($arrayArg));
1619-
$scope = $scope->invalidateExpression($arrayArg);
1619+
$scope = $scope->invalidateExpression($arrayArg)
1620+
->invalidateExpression(new FuncCall(new Name\FullyQualified('count'), [$expr->args[0]]))
1621+
->invalidateExpression(new FuncCall(new Name('count'), [$expr->args[0]]));
16201622
if (count($constantArrays) > 0) {
16211623
$resultArrayTypes = [];
16221624

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10832,6 +10832,11 @@ public function dataBug2927(): array
1083210832
return $this->gatherAssertTypes(__DIR__ . '/data/bug-2927.php');
1083310833
}
1083410834

10835+
public function dataBug4558(): array
10836+
{
10837+
return $this->gatherAssertTypes(__DIR__ . '/data/bug-4558.php');
10838+
}
10839+
1083510840
/**
1083610841
* @param string $file
1083710842
* @return array<string, mixed[]>
@@ -11060,6 +11065,7 @@ private function gatherAssertTypes(string $file): array
1106011065
* @dataProvider dataBug1897
1106111066
* @dataProvider dataBug1801
1106211067
* @dataProvider dataBug2927
11068+
* @dataProvider dataBug4558
1106311069
* @param string $assertType
1106411070
* @param string $file
1106511071
* @param mixed ...$args
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace Bug4558;
4+
5+
use DateTime;
6+
use function PHPStan\Analyser\assertType;
7+
8+
class HelloWorld
9+
{
10+
/**
11+
* @var DateTime[]
12+
*/
13+
private array $suggestions = [];
14+
15+
public function sayHello(): ?DateTime
16+
{
17+
while (count($this->suggestions) > 0) {
18+
assertType('array<DateTime>&nonEmpty', $this->suggestions);
19+
assertType('int<1, max>', count($this->suggestions));
20+
$try = array_shift($this->suggestions);
21+
22+
assertType('array<DateTime>', $this->suggestions);
23+
assertType('int<0, max>', count($this->suggestions));
24+
25+
if (rand(0, 1)) {
26+
return $try;
27+
}
28+
29+
assertType('array<DateTime>', $this->suggestions);
30+
assertType('int<0, max>', count($this->suggestions));
31+
32+
// we might be out of suggested days, so load some more
33+
if (count($this->suggestions) === 0) {
34+
assertType('array()', $this->suggestions);
35+
assertType('0', count($this->suggestions));
36+
$this->createSuggestions();
37+
}
38+
39+
assertType('array<DateTime>', $this->suggestions);
40+
assertType('int<0, max>', count($this->suggestions));
41+
}
42+
43+
return null;
44+
}
45+
46+
private function createSuggestions(): void
47+
{
48+
$this->suggestions[] = new DateTime;
49+
}
50+
}

0 commit comments

Comments
 (0)