Skip to content

Commit b50ac58

Browse files
authored
Narrow offset after isset() on list
1 parent 0626464 commit b50ac58

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

src/Rules/Arrays/AllowedArrayKeysTypes.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ public static function narrowOffsetKeyType(Type $varType, Type $keyType): ?Type
7171
return $narrowedKey;
7272
} elseif ($varIterableKeyType->isInteger()->yes() && $keyType->isString()->yes()) {
7373
return TypeCombinator::intersect($varIterableKeyType->toString(), $keyType);
74+
} elseif ($varType->isList()->yes()) {
75+
return TypeCombinator::intersect(
76+
$varIterableKeyType,
77+
$keyType,
78+
);
7479
}
7580

7681
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: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
40+
/**
41+
* @param int<5, 15> $index
42+
*/
43+
public function issetNotWidensIntRange(int $index, string $name): void
44+
{
45+
assert(isset($this->list[$index]));
46+
assertType('int<5, 15>', $index);
47+
}
48+
}

0 commit comments

Comments
 (0)