Skip to content

Commit 7d723e8

Browse files
committed
Support ArrayAccess in AppendedArrayItemTypeRule
1 parent 7c2c857 commit 7d723e8

File tree

4 files changed

+44
-2
lines changed

4 files changed

+44
-2
lines changed

src/Rules/Arrays/AppendedArrayItemTypeRule.php

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

33
namespace PHPStan\Rules\Arrays;
44

5+
use ArrayAccess;
56
use PhpParser\Node;
67
use PhpParser\Node\Expr\ArrayDimFetch;
78
use PhpParser\Node\Expr\Assign;
@@ -13,6 +14,7 @@
1314
use PHPStan\Rules\RuleErrorBuilder;
1415
use PHPStan\Rules\RuleLevelHelper;
1516
use PHPStan\Type\ArrayType;
17+
use PHPStan\Type\ObjectType;
1618
use PHPStan\Type\VerbosityLevel;
1719
use function sprintf;
1820

@@ -67,7 +69,7 @@ public function processNode(Node $node, Scope $scope): array
6769
}
6870

6971
$assignedToType = $propertyReflection->getWritableType();
70-
if (!($assignedToType instanceof ArrayType)) {
72+
if (!($assignedToType instanceof ArrayType) && !(new ObjectType(ArrayAccess::class))->isSuperTypeOf($assignedToType)->yes()) {
7173
return [];
7274
}
7375

@@ -77,7 +79,7 @@ public function processNode(Node $node, Scope $scope): array
7779
$assignedValueType = $scope->getType($node);
7880
}
7981

80-
$itemType = $assignedToType->getItemType();
82+
$itemType = $assignedToType->getIterableValueType();
8183
if (!$this->ruleLevelHelper->accepts($itemType, $assignedValueType, $scope->isDeclareStrictTypes())) {
8284
$verbosityLevel = VerbosityLevel::getRecommendedLevelByType($itemType, $assignedValueType);
8385
return [

src/Type/ObjectType.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,15 @@ public function getIterableValueType(): Type
746746
return new MixedType();
747747
}
748748

749+
if ($this->isInstanceOf(ArrayAccess::class)->yes()) {
750+
$tValue = GenericTypeVariableResolver::getType($this, ArrayAccess::class, 'TValue');
751+
if ($tValue !== null) {
752+
return $tValue;
753+
}
754+
755+
return new MixedType();
756+
}
757+
749758
return new ErrorType();
750759
}
751760

tests/PHPStan/Rules/Arrays/AppendedArrayItemTypeRuleTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ public function testAppendedArrayItemType(): void
5858
'Array (array<AppendedArrayItem\Lorem>) does not accept AppendedArrayItem\Baz.',
5959
79,
6060
],
61+
[
62+
'Array (ArrayAccess<int, string>) does not accept int.',
63+
95,
64+
],
65+
[
66+
'Array (ArrayAccess<int, string>&Countable) does not accept int.',
67+
96,
68+
],
69+
[
70+
'Array (ArrayAccess<int, string>&Countable&iterable<int, string>) does not accept int.',
71+
97,
72+
],
6173
]
6274
);
6375
}

tests/PHPStan/Rules/Arrays/data/appended-array-item.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,22 @@ function (Lorem $lorem)
7878
{
7979
$lorem->staticProperty[] = new Baz();
8080
};
81+
82+
class ArrayAccess
83+
{
84+
/** @var \ArrayAccess<int, string> */
85+
private $collection1;
86+
87+
/** @var \ArrayAccess<int, string>&\Countable */
88+
private $collection2;
89+
90+
/** @var \ArrayAccess<int, string>&\Countable&iterable<int, string> */
91+
private $collection3;
92+
93+
public function doFoo()
94+
{
95+
$this->collection1[] = 1;
96+
$this->collection2[] = 2;
97+
$this->collection3[] = 3;
98+
}
99+
}

0 commit comments

Comments
 (0)