1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-11 16:59:45 +01:00

Merge pull request #10450 from nicelocal/fix_class_string_key

Fix shaped array class string key combination
This commit is contained in:
orklah 2023-12-07 17:52:15 +01:00 committed by GitHub
commit f4e9837e27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 3 deletions

View File

@ -351,7 +351,9 @@ final class ArrayAssignmentAnalyzer
if (!$has_matching_objectlike_property && !$has_matching_string) { if (!$has_matching_objectlike_property && !$has_matching_string) {
$properties = []; $properties = [];
$classStrings = []; $classStrings = [];
$current_type = $current_type->setPossiblyUndefined(count($key_values) > 1); $current_type = $current_type->setPossiblyUndefined(
$current_type->possibly_undefined || count($key_values) > 1,
);
foreach ($key_values as $key_value) { foreach ($key_values as $key_value) {
$properties[$key_value->value] = $current_type; $properties[$key_value->value] = $current_type;
if ($key_value instanceof TLiteralClassString) { if ($key_value instanceof TLiteralClassString) {

View File

@ -55,6 +55,9 @@ final class TypeCombination
/** @var array<string|int, Union> */ /** @var array<string|int, Union> */
public array $objectlike_entries = []; public array $objectlike_entries = [];
/** @var array<string, bool> */
public array $objectlike_class_string_keys = [];
public bool $objectlike_sealed = true; public bool $objectlike_sealed = true;
public ?Union $objectlike_key_type = null; public ?Union $objectlike_key_type = null;

View File

@ -667,6 +667,7 @@ final class TypeCombiner
$has_defined_keys = false; $has_defined_keys = false;
$class_strings = $type->class_strings ?? [];
foreach ($type->properties as $candidate_property_name => $candidate_property_type) { foreach ($type->properties as $candidate_property_name => $candidate_property_type) {
$value_type = $combination->objectlike_entries[$candidate_property_name] ?? null; $value_type = $combination->objectlike_entries[$candidate_property_name] ?? null;
@ -706,6 +707,19 @@ final class TypeCombiner
} }
unset($missing_entries[$candidate_property_name]); unset($missing_entries[$candidate_property_name]);
if (is_int($candidate_property_name)) {
continue;
}
if (isset($combination->objectlike_class_string_keys[$candidate_property_name])) {
$combination->objectlike_class_string_keys[$candidate_property_name] =
$combination->objectlike_class_string_keys[$candidate_property_name]
&& ($class_strings[$candidate_property_name] ?? false);
} else {
$combination->objectlike_class_string_keys[$candidate_property_name] =
($class_strings[$candidate_property_name] ?? false);
}
} }
if ($type->fallback_params) { if ($type->fallback_params) {
@ -1421,7 +1435,7 @@ final class TypeCombiner
} else { } else {
$objectlike = new TKeyedArray( $objectlike = new TKeyedArray(
$combination->objectlike_entries, $combination->objectlike_entries,
null, array_filter($combination->objectlike_class_string_keys),
$sealed || $fallback_key_type === null || $fallback_value_type === null $sealed || $fallback_key_type === null || $fallback_value_type === null
? null ? null
: [$fallback_key_type, $fallback_value_type], : [$fallback_key_type, $fallback_value_type],

View File

@ -1148,7 +1148,9 @@ class Reconciler
$base_key = implode($key_parts); $base_key = implode($key_parts);
$result_type = $result_type->setPossiblyUndefined(count($array_key_offsets) > 1); $result_type = $result_type->setPossiblyUndefined(
$result_type->possibly_undefined || count($array_key_offsets) > 1,
);
foreach ($array_key_offsets as $array_key_offset) { foreach ($array_key_offsets as $array_key_offset) {
if (isset($existing_types[$base_key]) && $array_key_offset !== false) { if (isset($existing_types[$base_key]) && $array_key_offset !== false) {

View File

@ -55,6 +55,24 @@ class ArrayAssignmentTest extends TestCase
'$resultOpt===' => 'array{a?: true, b?: true}', '$resultOpt===' => 'array{a?: true, b?: true}',
], ],
], ],
'assignUnionOfLiteralsClassKeys' => [
'code' => '<?php
class a {}
class b {}
$result = [];
foreach ([a::class, b::class] as $k) {
$result[$k] = true;
}
foreach ($result as $k => $v) {
$vv = new $k;
}',
'assertions' => [
'$result===' => 'array{a::class: true, b::class: true}',
],
],
'genericArrayCreationWithSingleIntValue' => [ 'genericArrayCreationWithSingleIntValue' => [
'code' => '<?php 'code' => '<?php
$out = []; $out = [];