1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Respect possibly-undefined array keys while merging

Fixes #3393
This commit is contained in:
Brown 2020-05-19 20:10:01 -04:00
parent a4141a7581
commit 27cb660377
4 changed files with 57 additions and 6 deletions

View File

@ -451,7 +451,22 @@ class NonDivArithmeticOpAnalyzer
$left_type_part->properties
);
$properties = $left_type_part->properties + $right_type_part->properties;
$properties = $left_type_part->properties;
foreach ($right_type_part->properties as $key => $type) {
if (!isset($properties[$key])) {
$properties[$key] = $type;
} elseif ($properties[$key]->possibly_undefined) {
$properties[$key]->possibly_undefined = $properties[$key]->possibly_undefined
&& $type->possibly_undefined;
$properties[$key] = Type::combineUnionTypes(
$properties[$key],
$type,
$codebase
);
}
}
if (!$left_type_part->sealed) {
foreach ($definitely_existing_mixed_right_properties as $key => $type) {

View File

@ -81,10 +81,26 @@ class ArrayMergeReturnTypeProvider implements \Psalm\Plugin\Hook\FunctionReturnT
if ($unpacked_type_part instanceof Type\Atomic\ObjectLike) {
if ($generic_properties !== null) {
$generic_properties = array_merge(
$generic_properties,
$unpacked_type_part->properties
);
foreach ($unpacked_type_part->properties as $key => $type) {
if (!\is_string($key)) {
$generic_properties[] = $type;
continue;
}
if (!isset($generic_properties[$key]) || !$type->possibly_undefined) {
$generic_properties[$key] = $type;
} else {
$was_possibly_undefined = $generic_properties[$key]->possibly_undefined;
$generic_properties[$key] = Type::combineUnionTypes(
$generic_properties[$key],
$type,
$codebase
);
$generic_properties[$key]->possibly_undefined = $was_possibly_undefined;
}
}
}
if (!$unpacked_type_part->is_list) {

View File

@ -147,13 +147,23 @@ class ArrayFunctionCallTest extends TestCase
'$c' => 'array<string, int>|false',
],
],
'arrayMerge' => [
'arrayMergeIntArrays' => [
'<?php
$d = array_merge(["a", "b", "c"], [1, 2, 3]);',
'assertions' => [
'$d' => 'array{0: string, 1: string, 2: string, 3: int, 4: int, 5: int}',
],
],
'arrayMergePossiblyUndefined' => [
'<?php
/**
* @param array{host?:string} $opts
* @return array{host:string|int}
*/
function b(array $opts): array {
return array_merge(["host" => 5], $opts);
}',
],
'arrayMergeListResult' => [
'<?php
/**

View File

@ -242,6 +242,16 @@ class BinaryOperationTest extends TestCase
}
}'
],
'addArrays' => [
'<?php
/**
* @param array{host?:string} $opts
* @return array{host:string|int}
*/
function a(array $opts): array {
return $opts + ["host" => 5];
}'
],
];
}