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

Refine lists with object-like array types

Fixes #2357
This commit is contained in:
Brown 2019-11-26 12:22:28 -05:00
parent 532e2d64be
commit 842b2a53df
2 changed files with 68 additions and 0 deletions

View File

@ -2125,6 +2125,8 @@ class AssertionReconciler extends \Psalm\Type\Reconciler
) : Type\Union {
$matching_atomic_types = [];
$has_cloned_type = false;
foreach ($new_type->getTypes() as $new_type_part) {
$has_local_match = false;
@ -2167,6 +2169,42 @@ class AssertionReconciler extends \Psalm\Type\Reconciler
$matching_atomic_types[] = $existing_type_part;
}
if ($new_type_part instanceof Type\Atomic\ObjectLike
&& $existing_type_part instanceof Type\Atomic\TList
) {
$new_type_key = $new_type_part->getGenericKeyType();
$new_type_value = $new_type_part->getGenericValueType();
if (!$new_type_key->hasString()) {
$has_param_match = false;
$new_type_value = self::filterTypeWithAnother(
$codebase,
$existing_type_part->type_param,
$new_type_value,
$template_type_map,
$has_param_match,
$any_scalar_type_match_found
);
$hybrid_type_part = new Type\Atomic\ObjectLike($new_type_part->properties);
$hybrid_type_part->previous_key_type = Type::getInt();
$hybrid_type_part->previous_value_type = $new_type_value;
$hybrid_type_part->is_list = true;
if (!$has_cloned_type) {
$new_type = clone $new_type;
}
$has_local_match = true;
$new_type->removeType($key);
$new_type->addType($hybrid_type_part);
continue;
}
}
if (($new_type_part instanceof Type\Atomic\TGenericObject
|| $new_type_part instanceof Type\Atomic\TArray
|| $new_type_part instanceof Type\Atomic\TIterable)
@ -2232,6 +2270,10 @@ class AssertionReconciler extends \Psalm\Type\Reconciler
}
)
) {
if (!$has_cloned_type) {
$new_type = clone $new_type;
}
$new_type->removeType($key);
$new_type->addType($existing_type_part);
$new_type->from_docblock = $existing_type_part->from_docblock;

View File

@ -666,6 +666,32 @@ class AssertAnnotationTest extends TestCase
if (rand(0, 1) && f($q)) {}
if (!f($q)) {}'
],
'assertDifferentTypeOfArray' => [
'<?php
/**
* @psalm-assert array{0: string, 1: string} $value
* @param mixed $value
*/
function isStringTuple($value): void {
if (!is_array($value)
|| !isset($value[0])
|| !isset($value[1])
|| !is_string($value[0])
|| !is_string($value[1])
) {
throw new \Exception("bad");
}
}
$s = "";
$parts = explode(":", $s, 2);
isStringTuple($parts);
echo $parts[0];
echo $parts[1];'
],
];
}