Skip to content

Commit f25ff73

Browse files
Fix list description with offset required
1 parent 8d69bd0 commit f25ff73

File tree

4 files changed

+59
-5
lines changed

4 files changed

+59
-5
lines changed

src/Type/Constant/ConstantArrayType.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
use function count;
6262
use function implode;
6363
use function in_array;
64+
use function is_int;
6465
use function is_string;
6566
use function min;
6667
use function pow;
@@ -1848,16 +1849,31 @@ public function makeOffsetRequired(Type $offsetType): self
18481849
{
18491850
$offsetType = $offsetType->toArrayKey();
18501851
$optionalKeys = $this->optionalKeys;
1852+
$isList = $this->isList->yes();
18511853
foreach ($this->keyTypes as $i => $keyType) {
18521854
if (!$keyType->equals($offsetType)) {
18531855
continue;
18541856
}
18551857

1858+
$keyValue = $keyType->getValue();
18561859
foreach ($optionalKeys as $j => $key) {
1857-
if ($i === $key) {
1860+
if (
1861+
$i !== $key
1862+
&& (
1863+
!$isList
1864+
|| !is_int($keyValue)
1865+
|| !is_int($this->keyTypes[$key]->getValue())
1866+
|| $this->keyTypes[$key]->getValue() >= $keyValue
1867+
)
1868+
) {
18581869
unset($optionalKeys[$j]);
1859-
return new self($this->keyTypes, $this->valueTypes, $this->nextAutoIndexes, array_values($optionalKeys), $this->isList);
18601870
}
1871+
1872+
unset($optionalKeys[$j]);
1873+
}
1874+
1875+
if (count($this->optionalKeys) !== count($optionalKeys)) {
1876+
return new self($this->keyTypes, $this->valueTypes, $this->nextAutoIndexes, array_values($optionalKeys), $this->isList);
18611877
}
18621878

18631879
break;

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class HelloWorld
1212
public function testList(array $b): void
1313
{
1414
if (array_key_exists(3, $b)) {
15-
assertType('list{0: string, 1: string, 2?: string, 3: string}', $b);
15+
assertType('array{string, string, string, string}', $b);
1616
} else {
1717
assertType('array{0: string, 1: string, 2?: string}', $b);
1818
}
@@ -208,10 +208,10 @@ public function testFoo($l): void
208208
{
209209
if (array_key_exists(2, $l, true)) {
210210
assertType('true', array_is_list($l));
211-
assertType('list{0?: string, 1?: string, 2: string}', $l);
211+
assertType('array{string, string, string}', $l);
212212
if (array_key_exists(1, $l, true)) {
213213
assertType('true', array_is_list($l));
214-
assertType('list{0?: string, 1: string, 2: string}', $l);
214+
assertType('array{string, string, string}', $l);
215215
} else {
216216
assertType('true', array_is_list($l));
217217
assertType('*NEVER*', $l);

tests/PHPStan/Rules/Variables/IssetRuleTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,22 @@ public function testPr4374(): void
499499
]);
500500
}
501501

502+
public function testIssetConstantArray(): void
503+
{
504+
$this->treatPhpDocTypesAsCertain = true;
505+
506+
$this->analyse([__DIR__ . '/data/isset-constant-array.php'], [
507+
[
508+
'Offset 2 on array{0: string, 1: string, 2: string, 3: string, 4?: string} in isset() always exists and is not nullable.',
509+
13,
510+
],
511+
[
512+
'Offset 3 on array{string, string, string, string, string} in isset() always exists and is not nullable.',
513+
17,
514+
],
515+
]);
516+
}
517+
502518
public function testBug10640(): void
503519
{
504520
$this->treatPhpDocTypesAsCertain = true;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace IssetConstantArray;
4+
5+
class HelloWorld
6+
{
7+
/**
8+
* @param list{0: string, 1: string, 2?: string, 3?: string, 4?: string} $list
9+
*/
10+
public function sayHello(array $list): bool
11+
{
12+
if (isset($list[3])) {
13+
return isset($list[2]); // offset 3 implies offset 2;
14+
}
15+
16+
if (isset($list[4])) {
17+
return isset($list[3]); // offset 4 implies offset 3;
18+
}
19+
20+
return false;
21+
}
22+
}

0 commit comments

Comments
 (0)