Skip to content
Permalink
Browse files

Fix #2379 - support spread array RFC

  • Loading branch information
muglug committed Nov 27, 2019
1 parent f7ec5c5 commit 3f2d57c7a3a69ae1d3b6544db0ae0796c73ae2c9
Showing with 92 additions and 4 deletions.
  1. +77 −4 src/Psalm/Internal/Analyzer/Statements/Expression/ArrayAnalyzer.php
  2. +15 −0 tests/ArrayAssignmentTest.php
@@ -65,6 +65,83 @@ public static function analyze(
continue;
}
if (ExpressionAnalyzer::analyze($statements_analyzer, $item->value, $context) === false) {
return false;
}
if ($item->unpack) {
$unpacked_array_type = $statements_analyzer->node_data->getType($item->value);
if (!$unpacked_array_type) {
continue;
}
foreach ($unpacked_array_type->getTypes() as $unpacked_atomic_type) {
if ($unpacked_atomic_type instanceof Type\Atomic\ObjectLike) {
$unpacked_array_offset = 0;
foreach ($unpacked_atomic_type->properties as $key => $property_value) {
if (is_string($key)) {
if (IssueBuffer::accepts(
new DuplicateArrayKey(
'String keys are not supported in unpacked arrays',
new CodeLocation($statements_analyzer->getSource(), $item->value)
),
$statements_analyzer->getSuppressedIssues()
)) {
// fall through
}
continue;
}
$item_key_atomic_types[] = new Type\Atomic\TLiteralInt($key);
$item_value_atomic_types = array_merge(
$item_value_atomic_types,
array_values($property_value->getTypes())
);
$array_keys[$int_offset + $int_offset_diff + $unpacked_array_offset] = true;
$property_types[$int_offset + $int_offset_diff + $unpacked_array_offset] = $property_value;
$unpacked_array_offset++;
}
$int_offset_diff += $unpacked_array_offset - 1;
} else {
$can_create_objectlike = false;
if ($unpacked_atomic_type instanceof Type\Atomic\TArray) {
if ($unpacked_atomic_type->type_params[0]->hasString()) {
if (IssueBuffer::accepts(
new DuplicateArrayKey(
'String keys are not supported in unpacked arrays',
new CodeLocation($statements_analyzer->getSource(), $item->value)
),
$statements_analyzer->getSuppressedIssues()
)) {
// fall through
}
} elseif ($unpacked_atomic_type->type_params[0]->hasInt()) {
$item_key_atomic_types[] = new Type\Atomic\TInt();
}
$item_value_atomic_types = array_merge(
$item_value_atomic_types,
array_values($unpacked_atomic_type->type_params[1]->getTypes())
);
} elseif ($unpacked_atomic_type instanceof Type\Atomic\TList) {
$item_key_atomic_types[] = new Type\Atomic\TInt();
$item_value_atomic_types = array_merge(
$item_value_atomic_types,
array_values($unpacked_atomic_type->type_param->getTypes())
);
}
}
}
continue;
}
$item_key_value = null;
if ($item->key) {
@@ -125,10 +202,6 @@ public static function analyze(
$array_keys[$item_key_value] = true;
}
if (ExpressionAnalyzer::analyze($statements_analyzer, $item->value, $context) === false) {
return false;
}
if ($codebase->taint) {
if ($item_value_type = $statements_analyzer->node_data->getType($item->value)) {
$taint_sources = array_merge($taint_sources, $item_value_type->sources ?: []);
@@ -1258,6 +1258,21 @@ function foo(array $arr) : string {
return $arr[0];
}'
],
'arraySpread' => [
'<?php
$arrayA = [1, 2, 3];
$arrayB = [4, 5];
$result = [0, ...$arrayA, ...$arrayB, 6 ,7];
$arr1 = [3 => 1, 1 => 2, 3];
$arr2 = [...$arr1];
$arr3 = [1 => 0, ...$arr1];',
[
'$result' => 'array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int, 6: int, 7: int}',
'$arr2' => 'array{0: int, 1: int, 2: int}',
'$arr3' => 'array{1: int, 2: int, 3: int, 4: int}',
]
],
];
}

0 comments on commit 3f2d57c

Please sign in to comment.
You can’t perform that action at this time.