diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index f616b644ab..596b73f29b 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -1240,6 +1240,10 @@ public function processStmtNode( if ($stmt->valueVar instanceof Variable) { $this->callNodeCallback($nodeCallback, new VariableAssignNode($stmt->valueVar, new GetIterableValueTypeExpr($stmt->expr)), $originalScope, $storage); + } elseif ($stmt->valueVar instanceof List_) { + $virtualAssign = new Assign($stmt->valueVar, new GetIterableValueTypeExpr($stmt->expr)); + $virtualAssign->setAttributes($stmt->valueVar->getAttributes()); + $this->callNodeCallback($nodeCallback, $virtualAssign, $scope, $storage); } $originalStorage = $storage; diff --git a/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php b/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php index 252ba1b61a..2d1316f1b6 100644 --- a/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php @@ -68,6 +68,40 @@ public function testBug14270(): void $this->analyse([__DIR__ . '/data/bug-14270.php'], []); } + public function testBug8075(): void + { + $this->analyse([__DIR__ . '/data/bug-8075.php'], [ + [ + 'Offset \'b\' does not exist on array{a: 0}.', + 12, + ], + [ + 'Offset \'b\' does not exist on array{a: 0}.', + 14, + ], + [ + 'Offset \'b\' does not exist on array{a: 0}.', + 17, + ], + [ + 'Offset \'b\' does not exist on array{a: 0}.', + 24, + ], + [ + 'Offset \'missing\' does not exist on array{name: string, age: int}.', + 36, + ], + [ + 'Offset 2 does not exist on array{string, int}.', + 48, + ], + [ + 'Offset \'z\' does not exist on array{x: int, y: int}.', + 60, + ], + ]); + } + #[RequiresPhp('>= 8.0.0')] public function testRuleWithNullsafeVariant(): void { diff --git a/tests/PHPStan/Rules/Arrays/data/bug-8075.php b/tests/PHPStan/Rules/Arrays/data/bug-8075.php new file mode 100644 index 0000000000..fc20e67b98 --- /dev/null +++ b/tests/PHPStan/Rules/Arrays/data/bug-8075.php @@ -0,0 +1,64 @@ + 0]]; + + ['b' => $val] = $arr[0]; // error - works + + foreach ($arr as ['b' => $valueB]) { // error - should be reported + } + + foreach ($arr as ['b' => $valueB, 'a' => $valueA]) { // error on 'b' + } + + foreach ($arr as ['a' => $valueA]) { // no error - 'a' exists + } + + foreach ($arr as $item) { + ['b' => $valueB] = $item; // error - works + } + } + + /** + * @param array $people + */ + public function doBar(array $people): void + { + foreach ($people as ['name' => $name, 'age' => $age]) { // no error + } + + foreach ($people as ['name' => $name, 'missing' => $missing]) { // error on 'missing' + } + } + + /** + * @param list $tuples + */ + public function doBaz(array $tuples): void + { + foreach ($tuples as [$first, $second]) { // no error + } + + foreach ($tuples as [$first, $second, $third]) { // error on offset 2 + } + } + + /** + * @param list $nested + */ + public function doNested(array $nested): void + { + foreach ($nested as ['a' => ['x' => $x, 'y' => $y]]) { // no error + } + + foreach ($nested as ['a' => ['x' => $x, 'z' => $z]]) { // error on 'z' + } + } + +}