Skip to content

Commit 3a3b2c9

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

File tree

4 files changed

+56
-5
lines changed

4 files changed

+56
-5
lines changed

src/Type/Constant/ConstantArrayType.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,18 +1848,31 @@ public function makeOffsetRequired(Type $offsetType): self
18481848
{
18491849
$offsetType = $offsetType->toArrayKey();
18501850
$optionalKeys = $this->optionalKeys;
1851+
$isList = $this->isList->yes();
18511852
foreach ($this->keyTypes as $i => $keyType) {
18521853
if (!$keyType->equals($offsetType)) {
18531854
continue;
18541855
}
18551856

1857+
$keyValue = $keyType->getValue();
18561858
foreach ($optionalKeys as $j => $key) {
1857-
if ($i === $key) {
1859+
if (
1860+
$i === $key
1861+
|| (
1862+
$isList
1863+
&& is_int($keyValue)
1864+
&& is_int($this->keyTypes[$key]->getValue())
1865+
&& $this->keyTypes[$key]->getValue() < $keyValue
1866+
)
1867+
) {
18581868
unset($optionalKeys[$j]);
1859-
return new self($this->keyTypes, $this->valueTypes, $this->nextAutoIndexes, array_values($optionalKeys), $this->isList);
18601869
}
18611870
}
18621871

1872+
if (count($this->optionalKeys) !== count($optionalKeys)) {
1873+
return new self($this->keyTypes, $this->valueTypes, $this->nextAutoIndexes, array_values($optionalKeys), $this->isList);
1874+
}
1875+
18631876
break;
18641877
}
18651878

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)