Skip to content

Commit 17e0dd6

Browse files
committed
Narrow offset after isset() on list
1 parent dd41088 commit 17e0dd6

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

src/Rules/Arrays/AllowedArrayKeysTypes.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\Type\Constant\ConstantIntegerType;
99
use PHPStan\Type\Constant\ConstantStringType;
1010
use PHPStan\Type\FloatType;
11+
use PHPStan\Type\IntegerRangeType;
1112
use PHPStan\Type\IntegerType;
1213
use PHPStan\Type\MixedType;
1314
use PHPStan\Type\NullType;
@@ -71,6 +72,11 @@ public static function narrowOffsetKeyType(Type $varType, Type $keyType): ?Type
7172
return $narrowedKey;
7273
} elseif ($varIterableKeyType->isInteger()->yes() && $keyType->isString()->yes()) {
7374
return TypeCombinator::intersect($varIterableKeyType->toString(), $keyType);
75+
} elseif ($varType->isList()->yes()) {
76+
return TypeCombinator::intersect(
77+
IntegerRangeType::fromInterval(0, null),
78+
$varIterableKeyType,
79+
);
7480
}
7581

7682
return new MixedType(

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ function testShouldLooseListbyAst(array $list, int $i): void
9292

9393
assertType('list<int>', $list);
9494
$list[1+$i] = 21;
95-
assertType('non-empty-array<int, int>', $list);
95+
assertType('non-empty-array<int<0, max>, int>', $list);
9696
}
97-
assertType('array<int, int>', $list);
97+
assertType('array<int<0, max>, int>', $list);
9898
}
9999

100100
/** @param list<int> $list */
@@ -103,7 +103,7 @@ function testShouldLooseListbyAst2(array $list, int $i): void
103103
if (isset($list[$i])) {
104104
assertType('list<int>', $list);
105105
$list[2+$i] = 21;
106-
assertType('non-empty-array<int, int>', $list);
106+
assertType('non-empty-array<int<0, max>, int>', $list);
107107
}
108-
assertType('array<int, int>', $list);
108+
assertType('array<int<0, max>, int>', $list);
109109
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php // lint >= 8.0
2+
3+
namespace Bug12933;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/**
8+
* @phpstan-type record array{id: positive-int, name: string}
9+
*/
10+
class Collection
11+
{
12+
/** @param list<record> $list */
13+
public function __construct(
14+
public array $list
15+
)
16+
{
17+
}
18+
19+
public function updateNameIsset(int $index, string $name): void
20+
{
21+
assert(isset($this->list[$index]));
22+
assertType('int<0, max>', $index);
23+
}
24+
25+
public function updateNameArrayKeyExists(int $index, string $name): void
26+
{
27+
assert(array_key_exists($index, $this->list));
28+
assertType('int<0, max>', $index);
29+
}
30+
31+
/**
32+
* @param int<-5, 5> $index
33+
*/
34+
public function issetNarrowsIntRange(int $index, string $name): void
35+
{
36+
assert(isset($this->list[$index]));
37+
assertType('int<0, 5>', $index);
38+
}
39+
}

0 commit comments

Comments
 (0)