Skip to content

Commit 3c99850

Browse files
VincentLangletondrejmirtes
authored andcommitted
Fix ArrayType::hasOffsetValueType
1 parent f23422c commit 3c99850

File tree

8 files changed

+104
-1
lines changed

8 files changed

+104
-1
lines changed

src/Type/ArrayType.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ public function hasOffsetValueType(Type $offsetType): TrinaryLogic
272272
if ($offsetArrayKeyType instanceof ErrorType) {
273273
$allowedArrayKeys = AllowedArrayKeysTypes::getType();
274274
$offsetArrayKeyType = TypeCombinator::intersect($allowedArrayKeys, $offsetType)->toArrayKey();
275+
if ($offsetArrayKeyType instanceof NeverType) {
276+
return TrinaryLogic::createNo();
277+
}
275278
}
276279
$offsetType = $offsetArrayKeyType;
277280

src/Type/Constant/ConstantArrayType.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,9 @@ public function hasOffsetValueType(Type $offsetType): TrinaryLogic
586586
if ($offsetArrayKeyType instanceof ErrorType) {
587587
$allowedArrayKeys = AllowedArrayKeysTypes::getType();
588588
$offsetArrayKeyType = TypeCombinator::intersect($allowedArrayKeys, $offsetType)->toArrayKey();
589+
if ($offsetArrayKeyType instanceof NeverType) {
590+
return TrinaryLogic::createNo();
591+
}
589592
}
590593

591594
return $this->recursiveHasOffsetValueType($offsetArrayKeyType);

tests/PHPStan/Levels/data/arrayOffsetAccess-3.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,10 @@
33
"message": "Invalid array key type DateTimeImmutable.",
44
"line": 17,
55
"ignorable": true
6+
},
7+
{
8+
"message": "Offset DateTimeImmutable does not exist on array.",
9+
"line": 17,
10+
"ignorable": true
611
}
7-
]
12+
]

tests/PHPStan/Levels/data/arrayOffsetAccess-7.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,49 @@
11
[
2+
{
3+
"message": "Offset int|object might not exist on array.",
4+
"line": 19,
5+
"ignorable": true
6+
},
27
{
38
"message": "Possibly invalid array key type int|object.",
49
"line": 19,
510
"ignorable": true
611
},
12+
{
13+
"message": "Offset object|null might not exist on array.",
14+
"line": 20,
15+
"ignorable": true
16+
},
717
{
818
"message": "Possibly invalid array key type object|null.",
919
"line": 20,
1020
"ignorable": true
1121
},
22+
{
23+
"message": "Offset DateTimeImmutable might not exist on array|ArrayAccess.",
24+
"line": 26,
25+
"ignorable": true
26+
},
1227
{
1328
"message": "Possibly invalid array key type DateTimeImmutable.",
1429
"line": 26,
1530
"ignorable": true
1631
},
32+
{
33+
"message": "Offset int|object might not exist on array|ArrayAccess.",
34+
"line": 28,
35+
"ignorable": true
36+
},
1737
{
1838
"message": "Possibly invalid array key type int|object.",
1939
"line": 28,
2040
"ignorable": true
2141
},
42+
{
43+
"message": "Offset object|null might not exist on array|ArrayAccess.",
44+
"line": 29,
45+
"ignorable": true
46+
},
2247
{
2348
"message": "Possibly invalid array key type object|null.",
2449
"line": 29,

tests/PHPStan/Levels/data/stringOffsetAccess-3.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,10 @@
1818
"message": "Invalid array key type stdClass.",
1919
"line": 59,
2020
"ignorable": true
21+
},
22+
{
23+
"message": "Offset stdClass does not exist on array{baz: 21}|array{foo: 17, bar: 19}.",
24+
"line": 59,
25+
"ignorable": true
2126
}
2227
]

tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,10 @@ public function testBugObject(): void
949949
'Offset int|object does not exist on array{baz: 21}|array{foo: 17, bar: 19}.',
950950
12,
951951
],
952+
[
953+
'Offset object does not exist on array<string, int>.',
954+
21,
955+
],
952956
]);
953957
}
954958

tests/PHPStan/Type/ArrayTypeTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,36 @@ public function testResolveTemplateTypes(Type $received, Type $template, array $
269269
);
270270
}
271271

272+
public static function dataHasOffsetValueType(): array
273+
{
274+
return [
275+
[
276+
new ArrayType(new BenevolentUnionType([
277+
new IntegerType(),
278+
new StringType(),
279+
]), new IntegerType()),
280+
new ArrayType(new BenevolentUnionType([
281+
new IntegerType(),
282+
new StringType(),
283+
]), new IntegerType()),
284+
TrinaryLogic::createNo(),
285+
],
286+
];
287+
}
288+
289+
#[DataProvider('dataHasOffsetValueType')]
290+
public function testHasOffsetValueType(
291+
ArrayType $type,
292+
Type $offsetType,
293+
TrinaryLogic $expectedResult,
294+
): void
295+
{
296+
$actualResult = $type->hasOffsetValueType($offsetType);
297+
$this->assertSame(
298+
$expectedResult->describe(),
299+
$actualResult->describe(),
300+
sprintf('%s -> hasOffsetValueType(%s)', $type->describe(VerbosityLevel::precise()), $offsetType->describe(VerbosityLevel::precise())),
301+
);
302+
}
303+
272304
}

tests/PHPStan/Type/Constant/ConstantArrayTypeTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,4 +1044,30 @@ public function testValuesArray(ConstantArrayType $type, ConstantArrayType $expe
10441044
$this->assertSame($expectedType->getNextAutoIndexes(), $actualType->getNextAutoIndexes());
10451045
}
10461046

1047+
public static function dataHasOffsetValueType(): array
1048+
{
1049+
return [
1050+
[
1051+
new ConstantArrayType([new ConstantIntegerType(0)], [new ConstantStringType('a')]),
1052+
new ConstantArrayType([new ConstantIntegerType(0)], [new ConstantStringType('a')]),
1053+
TrinaryLogic::createNo(),
1054+
],
1055+
];
1056+
}
1057+
1058+
#[DataProvider('dataHasOffsetValueType')]
1059+
public function testHasOffsetValueType(
1060+
ConstantArrayType $type,
1061+
Type $offsetType,
1062+
TrinaryLogic $expectedResult,
1063+
): void
1064+
{
1065+
$actualResult = $type->hasOffsetValueType($offsetType);
1066+
$this->assertSame(
1067+
$expectedResult->describe(),
1068+
$actualResult->describe(),
1069+
sprintf('%s -> hasOffsetValueType(%s)', $type->describe(VerbosityLevel::precise()), $offsetType->describe(VerbosityLevel::precise())),
1070+
);
1071+
}
1072+
10471073
}

0 commit comments

Comments
 (0)