Skip to content

Commit 2e249ab

Browse files
committed
Create keyed arrays when assigning literal union keys
1 parent f9f8bac commit 2e249ab

File tree

2 files changed

+37
-22
lines changed

2 files changed

+37
-22
lines changed

src/Psalm/Internal/Analyzer/Statements/Expression/Assignment/ArrayAssignmentAnalyzer.php

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -349,29 +349,23 @@ private static function updateTypeWithKeyValues(
349349
}
350350

351351
if (!$has_matching_objectlike_property && !$has_matching_string) {
352-
if (count($key_values) === 1) {
353-
$key_value = $key_values[0];
354-
355-
$object_like = new TKeyedArray(
356-
[$key_value->value => $current_type],
357-
$key_value instanceof TLiteralClassString
358-
? [$key_value->value => true]
359-
: null,
360-
);
361-
362-
$array_assignment_type = new Union([
363-
$object_like,
364-
]);
365-
} else {
366-
$array_assignment_literals = $key_values;
367-
368-
$array_assignment_type = new Union([
369-
new TNonEmptyArray([
370-
new Union($array_assignment_literals),
371-
$current_type,
372-
]),
373-
]);
352+
$properties = [];
353+
$classStrings = [];
354+
$current_type = $current_type->setPossiblyUndefined(count($key_values) > 1);
355+
foreach ($key_values as $key_value) {
356+
$properties[$key_value->value] = $current_type;
357+
if ($key_value instanceof TLiteralClassString) {
358+
$classStrings[$key_value->value] = true;
359+
}
374360
}
361+
$object_like = new TKeyedArray(
362+
$properties,
363+
$classStrings ?: null,
364+
);
365+
366+
$array_assignment_type = new Union([
367+
$object_like,
368+
]);
375369

376370
return Type::combineUnionTypes(
377371
$child_stmt_type,

tests/ArrayAssignmentTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,27 @@ public function testConditionalAssignment(): void
3434
public function providerValidCodeParse(): iterable
3535
{
3636
return [
37+
'assignUnionOfLiterals' => [
38+
'code' => '<?php
39+
$result = [];
40+
41+
foreach (["a", "b"] as $k) {
42+
$result[$k] = true;
43+
}
44+
45+
$resultOpt = [];
46+
47+
foreach (["a", "b"] as $k) {
48+
if (random_int(0, 1)) {
49+
continue;
50+
}
51+
$resultOpt[$k] = true;
52+
}',
53+
'assertions' => [
54+
'$result===' => 'array{a: true, b: true}',
55+
'$resultOpt===' => 'array{a?: true, b?: true}',
56+
],
57+
],
3758
'genericArrayCreationWithSingleIntValue' => [
3859
'code' => '<?php
3960
$out = [];

0 commit comments

Comments
 (0)