1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Support more array intersections in type parsing

This commit is contained in:
Brown 2020-09-14 12:13:33 -04:00 committed by Daniil Gentili
parent f8f83e88f1
commit 95cc274192
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
2 changed files with 39 additions and 2 deletions

View File

@ -412,8 +412,17 @@ class TypeParser
);
$onlyTKeyedArray = true;
$first_type = reset($intersection_types);
$last_type = end($intersection_types);
foreach ($intersection_types as $intersection_type) {
if (!$intersection_type instanceof TKeyedArray) {
if (!$intersection_type instanceof TKeyedArray
&& ($intersection_type !== $first_type
|| !$first_type instanceof TArray)
&& ($intersection_type !== $last_type
|| !$last_type instanceof TArray)
) {
$onlyTKeyedArray = false;
break;
}
@ -422,6 +431,13 @@ class TypeParser
if ($onlyTKeyedArray) {
/** @var non-empty-array<string|int, Union> */
$properties = [];
if ($first_type instanceof TArray) {
array_shift($intersection_types);
} elseif ($last_type instanceof TArray) {
array_pop($intersection_types);
}
/** @var TKeyedArray $intersection_type */
foreach ($intersection_types as $intersection_type) {
foreach ($intersection_type->properties as $property => $property_type) {
@ -445,7 +461,18 @@ class TypeParser
$properties[$property] = $intersection_type;
}
}
return new TKeyedArray($properties);
$keyed_array = new TKeyedArray($properties);
if ($first_type instanceof TArray) {
$keyed_array->previous_key_type = $first_type->type_params[0];
$keyed_array->previous_value_type = $first_type->type_params[1];
} elseif ($last_type instanceof TArray) {
$keyed_array->previous_key_type = $last_type->type_params[0];
$keyed_array->previous_value_type = $last_type->type_params[1];
}
return $keyed_array;
}
$keyed_intersection_types = [];

View File

@ -177,6 +177,16 @@ class TypeParseTest extends TestCase
$this->assertSame('array{a: int, b: int}', (string) Type::parseString('array{a: int}&array{b: int}'));
}
public function testIntersectionOfTwoDifferentArrays(): void
{
$this->assertSame('array{a: int}<string, string>', Type::parseString('array{a: int}&array<string, string>')->getId());
}
public function testIntersectionOfTwoDifferentArraysReversed(): void
{
$this->assertSame('array{a: int}<string, string>', Type::parseString('array<string, string>&array{a: int}')->getId());
}
public function testIntersectionOfTKeyedArrayWithMergedProperties(): void
{
$this->assertSame('array{a: int}', (string) Type::parseString('array{a: int}&array{a: mixed}'));