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

Remove object-like array under falsy assertion when it contains a sure key

This commit is contained in:
Matthew Brown 2019-05-28 00:32:17 -04:00
parent cf02e9c22c
commit a001616753
6 changed files with 40 additions and 16 deletions

View File

@ -190,6 +190,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
$codebase,
$context,
$lhs_type_part,
$lhs_type_part instanceof Type\Atomic\TNamedObject ? $lhs_type_part : null,
$lhs_var_id,
$return_type,
$returns_by_ref,
@ -393,6 +394,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
Codebase $codebase,
Context $context,
Type\Atomic $lhs_type_part,
?Type\Atomic\TNamedObject $static_type,
$lhs_var_id,
&$return_type,
&$returns_by_ref,
@ -591,6 +593,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
$codebase,
$context,
$intersection_type,
$lhs_type_part,
$lhs_var_id,
$intersection_return_type,
$returns_by_ref,
@ -1025,7 +1028,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
$codebase,
$return_type_candidate,
$fq_class_name,
$lhs_type_part,
$static_type,
$class_storage->parent_class
);
} else {
@ -1096,7 +1099,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
$codebase,
$return_type_candidate,
$self_fq_class_name,
$lhs_type_part,
$static_type,
$class_storage->parent_class
);

View File

@ -98,7 +98,7 @@ class TypeCombination
private $floats = [];
/**
* @var array<int, TNamedObject|TTemplateParam|TIterable>|null
* @var array<string, TNamedObject|TTemplateParam|TIterable>|null
*/
private $extra_types;
@ -400,7 +400,7 @@ class TypeCombination
if ($combination->extra_types) {
$combination->extra_types = array_values(
self::combineTypes($combination->extra_types, $codebase)->getTypes()
self::combineTypes(array_values($combination->extra_types), $codebase)->getTypes()
);
}

View File

@ -359,6 +359,8 @@ abstract class Type
$parse_tree->children
);
$keyed_intersection_types = [];
foreach ($intersection_types as $intersection_type) {
if (!$intersection_type instanceof TNamedObject
&& !$intersection_type instanceof TTemplateParam
@ -368,13 +370,13 @@ abstract class Type
'Intersection types must all be objects, ' . get_class($intersection_type) . ' provided'
);
}
$keyed_intersection_types[$intersection_type->getKey()] = $intersection_type;
}
/** @var TNamedObject|TTemplateParam */
$first_type = array_shift($intersection_types);
$first_type = array_shift($keyed_intersection_types);
/** @var array<int, TNamedObject|TTemplateParam> $intersection_types */
$first_type->extra_types = $intersection_types;
$first_type->extra_types = $keyed_intersection_types;
return $first_type;
}
@ -1357,13 +1359,14 @@ abstract class Type
$type_2_atomic_clone->extra_types = [];
$type_1_atomic->extra_types[] = $type_2_atomic_clone;
$type_1_atomic->extra_types[$type_2_atomic_clone->getKey()] = $type_2_atomic_clone;
$type_2_atomic_intersection_types = $type_2_atomic->getIntersectionTypes();
if ($type_2_atomic_intersection_types) {
foreach ($type_2_atomic_intersection_types as $type_2_intersection_type) {
$type_1_atomic->extra_types[] = clone $type_2_intersection_type;
$type_1_atomic->extra_types[$type_2_intersection_type->getKey()]
= clone $type_2_intersection_type;
}
}
}

View File

@ -8,7 +8,7 @@ use Psalm\Codebase;
trait HasIntersectionTrait
{
/**
* @var array<int, TNamedObject|TTemplateParam|TIterable>|null
* @var array<string, TNamedObject|TTemplateParam|TIterable>|null
*/
public $extra_types;
@ -58,11 +58,11 @@ trait HasIntersectionTrait
*/
public function addIntersectionType(TNamedObject $type)
{
$this->extra_types[] = $type;
$this->extra_types[$type->getKey()] = $type;
}
/**
* @return array<int, TNamedObject|TTemplateParam|TIterable>|null
* @return array<string, TNamedObject|TTemplateParam|TIterable>|null
*/
public function getIntersectionTypes()
{
@ -88,12 +88,12 @@ trait HasIntersectionTrait
foreach ($template_type->getTypes() as $template_type_part) {
if ($template_type_part instanceof TNamedObject) {
$new_types[] = $template_type_part;
$new_types[$template_type_part->getKey()] = $template_type_part;
}
}
} else {
$extra_type->replaceTemplateTypesWithArgTypes($template_types, $codebase);
$new_types[] = $extra_type;
$new_types[$extra_type->getKey()] = $extra_type;
}
}

View File

@ -558,7 +558,13 @@ class Reconciler
$array_atomic_type = $existing_var_atomic_types['array'];
if ($array_atomic_type instanceof Type\Atomic\TNonEmptyArray
|| ($array_atomic_type instanceof Type\Atomic\ObjectLike && $array_atomic_type->sealed)
|| ($array_atomic_type instanceof Type\Atomic\ObjectLike
&& array_filter(
$array_atomic_type->properties,
function (Type\Union $t) {
return !$t->possibly_undefined;
}
))
) {
$did_remove_type = true;

View File

@ -1321,6 +1321,18 @@ class TypeReconciliationTest extends TestCase
$a = false;
}',
],
'dontRewriteNullableArrayAfterEmptyCheck' => [
'<?php
/**
* @param array{x:int,y:int}|null $start_pos
* @return array{x:int,y:int}|null
*/
function foo(?array $start_pos) : ?array {
if ($start_pos) {}
return $start_pos;
}',
],
];
}