Skip to content

Commit 9b64a6d

Browse files
jlherrenondrejmirtes
authored andcommitted
Fix ConstantArrayTypeBuilder's isList flag
1 parent 1b47baf commit 9b64a6d

File tree

4 files changed

+57
-1
lines changed

4 files changed

+57
-1
lines changed

src/Type/Constant/ConstantArrayTypeBuilder.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use function in_array;
1919
use function is_float;
2020
use function max;
21+
use function min;
2122
use function range;
2223

2324
/** @api */
@@ -158,8 +159,9 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $opt
158159
$this->valueTypes[] = $valueType;
159160

160161
if ($offsetType instanceof ConstantIntegerType) {
162+
$min = min($this->nextAutoIndexes);
161163
$max = max($this->nextAutoIndexes);
162-
if ($offsetType->getValue() !== $max) {
164+
if ($offsetType->getValue() > $min) {
163165
$this->isList = false;
164166
}
165167
if ($offsetType->getValue() >= $max) {

tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,4 +918,20 @@ public function testMagicSignatures(): void
918918
]);
919919
}
920920

921+
public function testLists(): void
922+
{
923+
$this->analyse([__DIR__ . '/data/return-list.php'], [
924+
[
925+
"Method ReturnList\Foo::getList1() should return list<string> but returns array{0?: 'foo', 1?: 'bar'}.",
926+
10,
927+
"array{0?: 'foo', 1?: 'bar'} is not a list.",
928+
],
929+
[
930+
"Method ReturnList\Foo::getList2() should return list<string> but returns array{0?: 'foo', 1?: 'bar'}.",
931+
19,
932+
"array{0?: 'foo', 1?: 'bar'} is not a list.",
933+
],
934+
]);
935+
}
936+
921937
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace ReturnList;
4+
5+
class Foo
6+
{
7+
/** @return list<string> */
8+
public function getList1(): array
9+
{
10+
return array_filter(['foo', 'bar'], 'file_exists');
11+
}
12+
13+
/**
14+
* @param array<int, string> $array
15+
* @return list<string>
16+
*/
17+
public function getList2(array $array): array
18+
{
19+
return array_intersect_key(['foo', 'bar'], $array);
20+
}
21+
}

tests/PHPStan/Type/Constant/ConstantArrayTypeBuilderTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,21 @@ public function testDegradedArrayIsNotAlwaysOversized(): void
111111
$this->assertSame('non-empty-array<string, string>', $array->describe(VerbosityLevel::precise()));
112112
}
113113

114+
public function testIsList(): void
115+
{
116+
$builder = ConstantArrayTypeBuilder::createEmpty();
117+
118+
$builder->setOffsetValueType(null, new ConstantIntegerType(0));
119+
$this->assertTrue($builder->isList());
120+
121+
$builder->setOffsetValueType(new ConstantIntegerType(0), new NullType());
122+
$this->assertTrue($builder->isList());
123+
124+
$builder->setOffsetValueType(new ConstantIntegerType(1), new NullType(), true);
125+
$this->assertTrue($builder->isList());
126+
127+
$builder->setOffsetValueType(new ConstantIntegerType(2), new NullType(), true);
128+
$this->assertFalse($builder->isList());
129+
}
130+
114131
}

0 commit comments

Comments
 (0)