Skip to content

Commit

Permalink
Fixed assigning nested arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed May 10, 2020
1 parent 6b89297 commit 5d64483
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 7 deletions.
6 changes: 4 additions & 2 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2298,10 +2298,12 @@ private function processAssignVar(
$offsetValueTypeStack[] = $offsetValueType;
}

foreach (array_reverse($offsetTypes) as $offsetType) {
foreach (array_reverse($offsetTypes) as $i => $offsetType) {
/** @var Type $offsetValueType */
$offsetValueType = array_pop($offsetValueTypeStack);
$valueToWrite = $offsetValueType->setOffsetValueType($offsetType, $valueToWrite);

/** @phpstan-ignore-next-line */
$valueToWrite = $offsetValueType->setOffsetValueType($offsetType, $valueToWrite, $i === 0);
}

if ($var instanceof Variable && is_string($var->name)) {
Expand Down
4 changes: 2 additions & 2 deletions src/Type/ArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,15 +216,15 @@ public function getOffsetValueType(Type $offsetType): Type
return $type;
}

public function setOffsetValueType(?Type $offsetType, Type $valueType): Type
public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
{
if ($offsetType === null) {
$offsetType = new IntegerType();
}

return new self(
TypeCombinator::union($this->keyType, self::castToArrayKeyType($offsetType)),
TypeCombinator::union($this->itemType, $valueType)
$unionValues ? TypeCombinator::union($this->itemType, $valueType) : $valueType
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Type/Constant/ConstantArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ public function getOffsetValueType(Type $offsetType): Type
return new ErrorType(); // undefined offset
}

public function setOffsetValueType(?Type $offsetType, Type $valueType): Type
public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = false): Type
{
$builder = ConstantArrayTypeBuilder::createFromConstantArray($this);
$builder->setOffsetValueType($offsetType, $valueType);
Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9889,6 +9889,11 @@ public function dataBug3269(): array
return $this->gatherAssertTypes(__DIR__ . '/data/bug-3269.php');
}

public function dataAssignNestedArray(): array
{
return $this->gatherAssertTypes(__DIR__ . '/data/assign-nested-arrays.php');
}

/**
* @dataProvider dataBug2574
* @dataProvider dataBug2577
Expand Down Expand Up @@ -9935,6 +9940,7 @@ public function dataBug3269(): array
* @dataProvider dataInheritPhpDocMerging
* @dataProvider dataBug3266
* @dataProvider dataBug3269
* @dataProvider dataAssignNestedArray
* @param ConstantStringType $expectedType
* @param Type $actualType
*/
Expand Down
33 changes: 33 additions & 0 deletions tests/PHPStan/Analyser/data/assign-nested-arrays.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace AssignNestedArrays;

use function PHPStan\Analyser\assertType;

class Foo
{

public function doFoo(int $i)
{
$array = [];

$array[$i]['bar'] = 1;
$array[$i]['baz'] = 2;

assertType('array<int, array(\'bar\' => 1, \'baz\' => 2)>', $array);
}

public function doBar(int $i, int $j)
{
$array = [];

$array[$i][$j]['bar'] = 1;
$array[$i][$j]['baz'] = 2;

echo $array[$i][$j]['bar'];
echo $array[$i][$j]['baz'];

assertType('array<int, array<int, array(\'bar\' => 1, \'baz\' => 2)>>', $array);
}

}
4 changes: 2 additions & 2 deletions tests/PHPStan/Rules/Arrays/data/nonexistent-offset.php
Original file line number Diff line number Diff line change
Expand Up @@ -358,15 +358,15 @@ public function arrayWithMultipleKeysAfterForeaches(int $i, int $j)
$array[$i]['baz'] = 2;

echo $array[$i]['bar'];
//echo $array[$i]['baz'];
echo $array[$i]['baz'];

$array = [];

$array[$i][$j]['bar'] = 1;
$array[$i][$j]['baz'] = 2;

echo $array[$i][$j]['bar'];
//echo $array[$i][$j]['baz'];
echo $array[$i][$j]['baz'];
}
}

Expand Down

0 comments on commit 5d64483

Please sign in to comment.