Skip to content

Commit 9961760

Browse files
staabmphpstan-bot
authored andcommitted
Narrow array to non-empty-array after isset() with non-constant dim
Fixes phpstan/phpstan#13674
1 parent d32efcb commit 9961760

File tree

7 files changed

+65
-13
lines changed

7 files changed

+65
-13
lines changed

src/Analyser/TypeSpecifier.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,17 @@ public function specifyTypesInCondition(
10801080
)->setRootExpr($expr),
10811081
);
10821082
}
1083+
1084+
if ($varType->isArray()->yes() && $scope->getNativeType($var->var)->isArray()->yes()) {
1085+
$types = $types->unionWith(
1086+
$this->create(
1087+
$var->var,
1088+
new NonEmptyArrayType(),
1089+
$context,
1090+
$scope,
1091+
)->setRootExpr($expr),
1092+
);
1093+
}
10831094
}
10841095
}
10851096

tests/PHPStan/Analyser/nsrt/bug-12274.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function getItemsByModifiedIndex(array $items): array
4040
function testKeepListAfterIssetIndex(array $list, int $i): void
4141
{
4242
if (isset($list[$i])) {
43-
assertType('list<int>', $list);
43+
assertType('non-empty-list<int>', $list);
4444
$list[$i] = 21;
4545
assertType('non-empty-list<int>', $list);
4646
$list[$i+1] = 21;
@@ -53,7 +53,7 @@ function testKeepListAfterIssetIndex(array $list, int $i): void
5353
function testKeepNestedListAfterIssetIndex(array $nestedList, int $i, int $j): void
5454
{
5555
if (isset($nestedList[$i][$j])) {
56-
assertType('list<list<int>>', $nestedList);
56+
assertType('non-empty-list<list<int>>', $nestedList);
5757
assertType('list<int>', $nestedList[$i]);
5858
$nestedList[$i][$j] = 21;
5959
assertType('non-empty-list<list<int>>', $nestedList);
@@ -66,7 +66,7 @@ function testKeepNestedListAfterIssetIndex(array $nestedList, int $i, int $j): v
6666
function testKeepListAfterIssetIndexPlusOne(array $list, int $i): void
6767
{
6868
if (isset($list[$i])) {
69-
assertType('list<int>', $list);
69+
assertType('non-empty-list<int>', $list);
7070
$list[$i+1] = 21;
7171
assertType('non-empty-list<int>', $list);
7272
}
@@ -77,7 +77,7 @@ function testKeepListAfterIssetIndexPlusOne(array $list, int $i): void
7777
function testKeepListAfterIssetIndexOnePlus(array $list, int $i): void
7878
{
7979
if (isset($list[$i])) {
80-
assertType('list<int>', $list);
80+
assertType('non-empty-list<int>', $list);
8181
$list[1+$i] = 21;
8282
assertType('non-empty-list<int>', $list);
8383
}
@@ -90,7 +90,7 @@ function testShouldLooseListbyAst(array $list, int $i): void
9090
if (isset($list[$i])) {
9191
$i++;
9292

93-
assertType('list<int>', $list);
93+
assertType('non-empty-list<int>', $list);
9494
$list[1+$i] = 21;
9595
assertType('non-empty-array<int<0, max>, int>', $list);
9696
}
@@ -101,7 +101,7 @@ function testShouldLooseListbyAst(array $list, int $i): void
101101
function testShouldLooseListbyAst2(array $list, int $i): void
102102
{
103103
if (isset($list[$i])) {
104-
assertType('list<int>', $list);
104+
assertType('non-empty-list<int>', $list);
105105
$list[2+$i] = 21;
106106
assertType('non-empty-array<int<0, max>, int>', $list);
107107
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug13674;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class HelloWorld
8+
{
9+
/**
10+
* @param list<int> $listA
11+
*/
12+
public function sayHello(int $i, array $listA): void
13+
{
14+
if (isset($listA[$i])) {
15+
assertType('non-empty-list<int>', $listA);
16+
17+
return;
18+
}
19+
}
20+
21+
/**
22+
* @param list<int> $listB
23+
*/
24+
public function sayHello2(int $i, array $listB): void
25+
{
26+
if (!isset($listB[$i])) {
27+
return;
28+
}
29+
assertType('non-empty-list<int>', $listB);
30+
}
31+
32+
/**
33+
* @param array<string, int> $arr
34+
*/
35+
public function sayHello3(string $key, array $arr): void
36+
{
37+
if (isset($arr[$key])) {
38+
assertType('non-empty-array<string, int>', $arr);
39+
}
40+
}
41+
}

tests/PHPStan/Analyser/nsrt/has-offset-type-bug.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function doFoo(array $errorMessages): void
2626
continue;
2727
}
2828

29-
assertType('array<string, int<1, max>>', $fileErrorsCounts);
29+
assertType('non-empty-array<string, int<1, max>>', $fileErrorsCounts);
3030
assertType('int<1, max>', $fileErrorsCounts[$errorMessage]);
3131

3232
$fileErrorsCounts[$errorMessage]++;

tests/PHPStan/Analyser/nsrt/specified-types-closure-use.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ function ($arr) use ($key): void {
4848
public function doBuzz(array $arr, string $key): void
4949
{
5050
if (isset($arr[$key])) {
51-
assertType('array', $arr);
51+
assertType('non-empty-array', $arr);
5252
assertType("mixed~null", $arr[$key]);
5353
function () use ($arr, $key): void {
54-
assertType('array', $arr);
54+
assertType('non-empty-array', $arr);
5555
assertType("mixed~null", $arr[$key]);
5656
};
5757
}
@@ -60,10 +60,10 @@ function () use ($arr, $key): void {
6060
public function doBuzz(array $arr, string $key): void
6161
{
6262
if (isset($arr[$key])) {
63-
assertType('array', $arr);
63+
assertType('non-empty-array', $arr);
6464
assertType("mixed~null", $arr[$key]);
6565
function ($key) use ($arr): void {
66-
assertType('array', $arr);
66+
assertType('non-empty-array', $arr);
6767
assertType("mixed", $arr[$key]);
6868
};
6969
}

tests/PHPStan/Rules/Arrays/data/bug-11679.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function sayHello(int $index): bool
3333
$this->arr[$index]['foo'] = true;
3434
assertType('non-empty-array<int, array{foo: true}>', $this->arr);
3535
}
36-
assertType('array<int, array{foo?: bool}>', $this->arr);
36+
assertType('non-empty-array<int, array{foo?: bool}>', $this->arr);
3737
return $this->arr[$index]['foo']; // PHPStan does not realize 'foo' is set
3838
}
3939
}

tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ public function testBug7190(): void
280280
{
281281
$this->analyse([__DIR__ . '/../Properties/data/bug-7190.php'], [
282282
[
283-
'Offset int on array<int, int> on left side of ?? always exists and is not nullable.',
283+
'Offset int on non-empty-array<int, int> on left side of ?? always exists and is not nullable.',
284284
20,
285285
],
286286
]);

0 commit comments

Comments
 (0)