Skip to content

Commit 36c56ea

Browse files
Report non existent offset on non empty array
1 parent b0aa47e commit 36c56ea

File tree

4 files changed

+49
-8
lines changed

4 files changed

+49
-8
lines changed

src/Type/TypeUtils.php

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Type;
44

5+
use PHPStan\Internal\CombinationsHelper;
56
use PHPStan\Type\Accessory\AccessoryType;
67
use PHPStan\Type\Accessory\HasPropertyType;
78
use PHPStan\Type\Constant\ConstantArrayType;
@@ -133,17 +134,28 @@ public static function flattenTypes(Type $type): array
133134
return $type->getAllArrays();
134135
}
135136

137+
if ($type instanceof IntersectionType && $type->isConstantArray()->yes()) {
138+
$newTypes = [];
139+
foreach ($type->getTypes() as $innerType) {
140+
$newTypes[] = self::flattenTypes($innerType);
141+
}
142+
143+
return array_filter(
144+
array_map(
145+
static fn (array $types): Type => TypeCombinator::intersect(...$types),
146+
iterator_to_array(CombinationsHelper::combinations($newTypes)),
147+
),
148+
static fn (Type $type): bool => !$type instanceof NeverType,
149+
);
150+
}
151+
136152
if ($type instanceof UnionType) {
137153
$types = [];
138154
foreach ($type->getTypes() as $innerType) {
139-
if ($innerType instanceof ConstantArrayType) {
140-
foreach ($innerType->getAllArrays() as $array) {
141-
$types[] = $array;
142-
}
143-
continue;
155+
$flattenTypes = self::flattenTypes($innerType);
156+
foreach ($flattenTypes as $flattenType) {
157+
$types[] = $flattenType;
144158
}
145-
146-
$types[] = $innerType;
147159
}
148160

149161
return $types;

tests/PHPStan/Analyser/AnalyserIntegrationTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -983,7 +983,7 @@ public function testBug7581(): void
983983
public function testBug7903(): void
984984
{
985985
$errors = $this->runAnalyse(__DIR__ . '/data/bug-7903.php');
986-
$this->assertCount(23, $errors);
986+
$this->assertCount(28, $errors);
987987
}
988988

989989
public function testBug7901(): void

tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,20 @@ public function testBug13538(): void
10491049
]);
10501050
}
10511051

1052+
public function testBug7143(): void
1053+
{
1054+
$this->analyse([__DIR__ . '/data/bug-7143.php'], [
1055+
[
1056+
"Offset 'foo' might not exist on non-empty-array{foo?: string, bar?: string}.",
1057+
12,
1058+
],
1059+
[
1060+
"Offset 'bar' might not exist on non-empty-array{foo?: string, bar?: string}.",
1061+
13,
1062+
],
1063+
]);
1064+
}
1065+
10521066
public function testBug12805(): void
10531067
{
10541068
$this->reportPossiblyNonexistentGeneralArrayOffset = true;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Bug7143;
4+
5+
class Foo
6+
{
7+
/**
8+
* @param array{foo?: string, bar?: string}&non-empty-array $arr
9+
*/
10+
public function test(array $arr): void
11+
{
12+
echo $arr['foo'];
13+
echo $arr['bar'];
14+
}
15+
}

0 commit comments

Comments
 (0)