Skip to content
12 changes: 12 additions & 0 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,7 @@
);
} else {
$varType = $scope->getType($var->var);

$narrowedKey = AllowedArrayKeysTypes::narrowOffsetKeyType($varType, $dimType);
if ($narrowedKey !== null) {
$types = $types->unionWith(
Expand All @@ -1088,6 +1089,17 @@
)->setRootExpr($expr),
);
}

if ($varType->isArray()->yes()) {

Check warning on line 1093 in src/Analyser/TypeSpecifier.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.4, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ ); } - if ($varType->isArray()->yes()) { + if (!$varType->isArray()->no()) { $types = $types->unionWith( $this->create( $var->var,

Check warning on line 1093 in src/Analyser/TypeSpecifier.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.3, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ ); } - if ($varType->isArray()->yes()) { + if (!$varType->isArray()->no()) { $types = $types->unionWith( $this->create( $var->var,
$types = $types->unionWith(
$this->create(
$var->var,
new NonEmptyArrayType(),
$context,
$scope,
)->setRootExpr($expr),
);
}
}
}

Expand Down
14 changes: 7 additions & 7 deletions tests/PHPStan/Analyser/nsrt/bug-12274.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function getItemsByModifiedIndex(array $items): array
function testKeepListAfterIssetIndex(array $list, int $i): void
{
if (isset($list[$i])) {
assertType('list<int>', $list);
assertType('non-empty-list<int>', $list);
$list[$i] = 21;
assertType('non-empty-list<int>', $list);
$list[$i+1] = 21;
Expand All @@ -53,8 +53,8 @@ function testKeepListAfterIssetIndex(array $list, int $i): void
function testKeepNestedListAfterIssetIndex(array $nestedList, int $i, int $j): void
{
if (isset($nestedList[$i][$j])) {
assertType('list<list<int>>', $nestedList);
assertType('list<int>', $nestedList[$i]);
assertType('non-empty-list<list<int>>', $nestedList);
assertType('non-empty-list<int>', $nestedList[$i]);
$nestedList[$i][$j] = 21;
assertType('non-empty-list<list<int>>', $nestedList);
assertType('list<int>', $nestedList[$i]);
Expand All @@ -66,7 +66,7 @@ function testKeepNestedListAfterIssetIndex(array $nestedList, int $i, int $j): v
function testKeepListAfterIssetIndexPlusOne(array $list, int $i): void
{
if (isset($list[$i])) {
assertType('list<int>', $list);
assertType('non-empty-list<int>', $list);
$list[$i+1] = 21;
assertType('non-empty-list<int>', $list);
}
Expand All @@ -77,7 +77,7 @@ function testKeepListAfterIssetIndexPlusOne(array $list, int $i): void
function testKeepListAfterIssetIndexOnePlus(array $list, int $i): void
{
if (isset($list[$i])) {
assertType('list<int>', $list);
assertType('non-empty-list<int>', $list);
$list[1+$i] = 21;
assertType('non-empty-list<int>', $list);
}
Expand All @@ -90,7 +90,7 @@ function testShouldLooseListbyAst(array $list, int $i): void
if (isset($list[$i])) {
$i++;

assertType('list<int>', $list);
assertType('non-empty-list<int>', $list);
$list[1+$i] = 21;
assertType('non-empty-array<int<0, max>, int>', $list);
}
Expand All @@ -101,7 +101,7 @@ function testShouldLooseListbyAst(array $list, int $i): void
function testShouldLooseListbyAst2(array $list, int $i): void
{
if (isset($list[$i])) {
assertType('list<int>', $list);
assertType('non-empty-list<int>', $list);
$list[2+$i] = 21;
assertType('non-empty-array<int<0, max>, int>', $list);
}
Expand Down
39 changes: 39 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-13674b.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Bug13674b;

use function assert;
use function PHPStan\Testing\assertType;

class HelloWorld
{
/**
* @param array<int> $arrayA
* @param list<int> $listA
*/
public function sayHello($arrayA, $listA, int $i): void
{
if (isset($arrayA[$i])) {
assertType('non-empty-array<int>', $arrayA);
} else {
assertType('array<int>', $arrayA);
}
assertType('array<int>', $arrayA);

if (isset($listA[$i])) {
assertType('non-empty-list<int>', $listA);
} else {
assertType('list<int>', $listA);
}
assertType('list<int>', $listA);

if (!isset($listA[$i])) {
assertType('list<int>', $listA);
return;
}
assertType('non-empty-list<int>', $listA);

$emptyArray = [];
assertType('false', isset($emptyArray[$i]));
}
}
27 changes: 27 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-13675.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Bug13675;

use function assert;
use function PHPStan\Testing\assertType;

class HelloWorld
{
/**
* @param list<int> $listA
* @param list<int> $listB
*/
public function sayHello(int $i, $listA, $listB): void
{
if (!isset($listA[$i])) {
return;
}
assertType('non-empty-list<int>', $listA);

if (count($listA) !== count($listB)) {
return;
}
assertType('non-empty-list<int>', $listB);
}
}

2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/bug-7000.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public function doBar(): void
$composer = array();
foreach (array('require', 'require-dev') as $linkType) {
if (isset($composer[$linkType])) {
assertType('array{require?: array<string, string>, require-dev?: array<string, string>}', $composer);
assertType('non-empty-array{require?: array<string, string>, require-dev?: array<string, string>}', $composer);
foreach ($composer[$linkType] as $x) {}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Analyser/nsrt/has-offset-type-bug.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function doFoo(array $errorMessages): void
continue;
}

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

$fileErrorsCounts[$errorMessage]++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function getGroupedQueries(): void
$connectionGroupedQueries[$key]['index'] = $i; // "Explain query" relies on query index in 'queries'.
}

assertType("array<string, array{sql: string, executionMS: 0, types: array<int|string, int|Shopware\Core\Profiling\Doctrine\ParameterType>, count: 0, index: int}|array{sql: string, executionMS: float, types: array<int|string, int|Shopware\Core\Profiling\Doctrine\ParameterType>, count: int<1, max>, index: int}>", $connectionGroupedQueries);
assertType("non-empty-array<string, array{sql: string, executionMS: 0, types: array<int|string, int|Shopware\Core\Profiling\Doctrine\ParameterType>, count: 0, index: int}|array{sql: string, executionMS: float, types: array<int|string, int|Shopware\Core\Profiling\Doctrine\ParameterType>, count: int<1, max>, index: int}>", $connectionGroupedQueries);
$connectionGroupedQueries[$key]['executionMS'] += $query['executionMS'];
assertType("non-empty-array<string, array{sql: string, executionMS: float, types: array<int|string, int|Shopware\Core\Profiling\Doctrine\ParameterType>, count: int<0, max>, index: int}>", $connectionGroupedQueries);
++$connectionGroupedQueries[$key]['count'];
Expand Down
8 changes: 4 additions & 4 deletions tests/PHPStan/Analyser/nsrt/specified-types-closure-use.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ function ($arr) use ($key): void {
public function doBuzz(array $arr, string $key): void
{
if (isset($arr[$key])) {
assertType('array', $arr);
assertType('non-empty-array', $arr);
assertType("mixed~null", $arr[$key]);
function () use ($arr, $key): void {
assertType('array', $arr);
assertType('non-empty-array', $arr);
assertType("mixed~null", $arr[$key]);
};
}
Expand All @@ -60,10 +60,10 @@ function () use ($arr, $key): void {
public function doBuzz(array $arr, string $key): void
{
if (isset($arr[$key])) {
assertType('array', $arr);
assertType('non-empty-array', $arr);
assertType("mixed~null", $arr[$key]);
function ($key) use ($arr): void {
assertType('array', $arr);
assertType('non-empty-array', $arr);
assertType("mixed", $arr[$key]);
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ public function testBug7000(): void
{
$this->analyse([__DIR__ . '/data/bug-7000.php'], [
[
"Offset 'require'|'require-dev' might not exist on array{require?: array<string, string>, require-dev?: array<string, string>}.",
"Offset 'require'|'require-dev' might not exist on non-empty-array{require?: array<string, string>, require-dev?: array<string, string>}.",
16,
],
]);
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Arrays/data/bug-11679.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function sayHello(int $index): bool
assertType('non-empty-array<int, array{foo?: bool}>', $this->arr);
assertType('true', $this->arr[$index]['foo']);
}
assertType('array<int, array{foo?: bool}>', $this->arr);
assertType('non-empty-array<int, array{foo?: bool}>', $this->arr);
return $this->arr[$index]['foo']; // PHPStan does not realize 'foo' is set
}
}
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Variables/IssetRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ public function testPr4374(): void

$this->analyse([__DIR__ . '/data/pr-4374.php'], [
[
'Offset string on array<PR4374\Foo> in isset() always exists and is not nullable.',
'Offset string on non-empty-array<PR4374\Foo> in isset() always exists and is not nullable.',
23,
],
]);
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ public function testBug7190(): void
{
$this->analyse([__DIR__ . '/../Properties/data/bug-7190.php'], [
[
'Offset int on array<int, int> on left side of ?? always exists and is not nullable.',
'Offset int on non-empty-array<int, int> on left side of ?? always exists and is not nullable.',
20,
],
]);
Expand Down
Loading