Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 194ba99

Browse files
authored
Offset on list definitely exists if there's HasOffsetType with higher number
1 parent ae5562f commit 194ba99

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

‎src/Type/IntersectionType.php‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
use PHPStan\Type\Accessory\AccessoryNumericStringType;
2929
use PHPStan\Type\Accessory\AccessoryType;
3030
use PHPStan\Type\Accessory\AccessoryUppercaseStringType;
31+
use PHPStan\Type\Accessory\HasOffsetType;
32+
use PHPStan\Type\Accessory\HasOffsetValueType;
3133
use PHPStan\Type\Accessory\NonEmptyArrayType;
3234
use PHPStan\Type\Constant\ConstantArrayType;
3335
use PHPStan\Type\Constant\ConstantIntegerType;
@@ -45,6 +47,7 @@
4547
use function count;
4648
use function implode;
4749
use function in_array;
50+
use function is_int;
4851
use function ksort;
4952
use function md5;
5053
use function sprintf;
@@ -738,6 +741,21 @@ public function hasOffsetValueType(Type $offsetType): TrinaryLogic
738741
if ((new ConstantIntegerType(0))->isSuperTypeOf($arrayKeyOffsetType)->yes()) {
739742
return TrinaryLogic::createYes();
740743
}
744+
745+
foreach ($this->types as $type) {
746+
if (!$type instanceof HasOffsetValueType && !$type instanceof HasOffsetType) {
747+
continue;
748+
}
749+
750+
foreach ($type->getOffsetType()->getConstantScalarValues() as $constantScalarValue) {
751+
if (!is_int($constantScalarValue)) {
752+
continue;
753+
}
754+
if (IntegerRangeType::fromInterval(0, $constantScalarValue)->isSuperTypeOf($arrayKeyOffsetType)->yes()) {
755+
return TrinaryLogic::createYes();
756+
}
757+
}
758+
}
741759
}
742760

743761
return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->hasOffsetValueType($offsetType));

‎tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,22 @@ public function testNarrowSuperglobals(): void
900900
$this->analyse([__DIR__ . '/data/narrow-superglobal.php'], []);
901901
}
902902

903+
public function testBug12605(): void
904+
{
905+
$this->reportPossiblyNonexistentGeneralArrayOffset = true;
906+
907+
$this->analyse([__DIR__ . '/data/bug-12605.php'], [
908+
[
909+
'Offset 1 might not exist on list<int>.',
910+
19,
911+
],
912+
[
913+
'Offset 10 might not exist on non-empty-list<int>.',
914+
26,
915+
],
916+
]);
917+
}
918+
903919
public function testBug11602(): void
904920
{
905921
$this->reportPossiblyNonexistentGeneralArrayOffset = true;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Bug12605;
4+
5+
/**
6+
* @return list<int>
7+
*/
8+
function test(): array
9+
{
10+
return [];
11+
}
12+
13+
function doFoo(): void {
14+
$test = test();
15+
16+
if (isset($test[3])) {
17+
echo $test[1];
18+
}
19+
echo $test[1];
20+
}
21+
22+
function doFooBar(): void {
23+
$test = test();
24+
25+
if (isset($test[4])) {
26+
echo $test[10];
27+
}
28+
}
29+
30+
function doBaz(): void {
31+
$test = test();
32+
33+
if (array_key_exists(5, $test) && is_int($test[5])) {
34+
echo $test[3];
35+
}
36+
}
37+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /