Skip to content

Commit 4ed0fe9

Browse files
committed
Fix shaped array class string key combination
1 parent c620f6e commit 4ed0fe9

File tree

5 files changed

+38
-3
lines changed

5 files changed

+38
-3
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,9 @@ private static function updateTypeWithKeyValues(
351351
if (!$has_matching_objectlike_property && !$has_matching_string) {
352352
$properties = [];
353353
$classStrings = [];
354-
$current_type = $current_type->setPossiblyUndefined(count($key_values) > 1);
354+
$current_type = $current_type->setPossiblyUndefined(
355+
$current_type->possibly_undefined || count($key_values) > 1,
356+
);
355357
foreach ($key_values as $key_value) {
356358
$properties[$key_value->value] = $current_type;
357359
if ($key_value instanceof TLiteralClassString) {

src/Psalm/Internal/Type/TypeCombination.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ final class TypeCombination
5555
/** @var array<string|int, Union> */
5656
public array $objectlike_entries = [];
5757

58+
/** @var array<string, true> */
59+
public array $objectlike_class_string_keys = [];
60+
5861
public bool $objectlike_sealed = true;
5962

6063
public ?Union $objectlike_key_type = null;

src/Psalm/Internal/Type/TypeCombiner.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ private static function scrapeTypeProperties(
667667

668668
$has_defined_keys = false;
669669

670+
$class_strings = $type->class_strings ?? [];
670671
foreach ($type->properties as $candidate_property_name => $candidate_property_type) {
671672
$value_type = $combination->objectlike_entries[$candidate_property_name] ?? null;
672673

@@ -705,6 +706,15 @@ private static function scrapeTypeProperties(
705706
);
706707
}
707708

709+
if (isset($combination->objectlike_class_string_keys[$candidate_property_name])) {
710+
$combination->objectlike_class_string_keys[$candidate_property_name] =
711+
$combination->objectlike_class_string_keys[$candidate_property_name]
712+
&& ($class_strings[$candidate_property_name] ?? false);
713+
} else {
714+
$combination->objectlike_class_string_keys[$candidate_property_name] =
715+
($class_strings[$candidate_property_name] ?? false);
716+
}
717+
708718
unset($missing_entries[$candidate_property_name]);
709719
}
710720

@@ -1421,7 +1431,7 @@ private static function handleKeyedArrayEntries(
14211431
} else {
14221432
$objectlike = new TKeyedArray(
14231433
$combination->objectlike_entries,
1424-
null,
1434+
$combination->objectlike_class_string_keys,
14251435
$sealed || $fallback_key_type === null || $fallback_value_type === null
14261436
? null
14271437
: [$fallback_key_type, $fallback_value_type],

src/Psalm/Type/Reconciler.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,9 @@ private static function adjustTKeyedArrayType(
11321132

11331133
$base_key = implode($key_parts);
11341134

1135-
$result_type = $result_type->setPossiblyUndefined(count($array_key_offsets) > 1);
1135+
$result_type = $result_type->setPossiblyUndefined(
1136+
$result_type->possibly_undefined || count($array_key_offsets) > 1,
1137+
);
11361138

11371139
foreach ($array_key_offsets as $array_key_offset) {
11381140
if (isset($existing_types[$base_key]) && $array_key_offset !== false) {

tests/ArrayAssignmentTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,24 @@ public function providerValidCodeParse(): iterable
5555
'$resultOpt===' => 'array{a?: true, b?: true}',
5656
],
5757
],
58+
'assignUnionOfLiteralsClassKeys' => [
59+
'code' => '<?php
60+
class a {}
61+
class b {}
62+
63+
$result = [];
64+
65+
foreach ([a::class, b::class] as $k) {
66+
$result[$k] = true;
67+
}
68+
69+
foreach ($result as $k => $v) {
70+
$vv = new $k;
71+
}',
72+
'assertions' => [
73+
'$result===' => 'array{a::class: true, b::class: true}',
74+
],
75+
],
5876
'genericArrayCreationWithSingleIntValue' => [
5977
'code' => '<?php
6078
$out = [];

0 commit comments

Comments
 (0)