1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-11 16:59:45 +01:00
This commit is contained in:
Daniil Gentili 2022-11-26 16:21:27 +01:00
parent 0a20c10e00
commit e2da9c9dc4
11 changed files with 77 additions and 43 deletions

View File

@ -35,7 +35,6 @@ use Psalm\Type\Atomic\TLiteralInt;
use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TMixed;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TNonEmptyList;
use Psalm\Type\Atomic\TObjectWithProperties;
use Psalm\Type\Atomic\TString;
use Psalm\Type\Atomic\TTemplateParam;

View File

@ -29,7 +29,6 @@ use Psalm\Type\Atomic\TLiteralClassString;
use Psalm\Type\Atomic\TLiteralInt;
use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TNonEmptyList;
use Psalm\Type\Atomic\TString;
use Psalm\Type\Atomic\TTemplateIndexedAccess;
use Psalm\Type\Atomic\TTemplateKeyOf;
@ -684,14 +683,34 @@ class ArrayAssignmentAnalyzer
if ($from_countable_object_like) {
$atomic_root_types = $new_child_type->getAtomicTypes();
if (isset($atomic_root_types['array'])
&& ($atomic_root_types['array'] instanceof TNonEmptyArray
|| $atomic_root_types['array'] instanceof TNonEmptyList)
if (isset($atomic_root_types['array'])) {
if ($atomic_root_types['array'] instanceof TNonEmptyArray
&& $atomic_root_types['array']->count !== null
) {
$atomic_root_types['array'] =
$atomic_root_types['array']->setCount($atomic_root_types['array']->count+1);
$new_child_type = new Union($atomic_root_types);
} elseif ($atomic_root_types['array'] instanceof TKeyedArray
&& $atomic_root_types['array']->is_list) {
$properties = $atomic_root_types['array']->properties;
$had_undefined = false;
foreach ($properties as &$property) {
if ($property->possibly_undefined) {
$property = $property->setPossiblyUndefined(true);
$had_undefined = true;
break;
}
}
if (!$had_undefined && $atomic_root_types['array']->fallback_params) {
$properties []= $atomic_root_types['array']->fallback_params[1];
}
$atomic_root_types['array'] =
$atomic_root_types['array']->setProperties($properties);
$new_child_type = new Union($atomic_root_types);
}
}
}

View File

@ -36,7 +36,6 @@ use Psalm\Type\Atomic\TCallable;
use Psalm\Type\Atomic\TClosure;
use Psalm\Type\Atomic\TKeyedArray;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TNonEmptyList;
use Psalm\Type\Union;
use UnexpectedValueException;
@ -540,15 +539,25 @@ class ArrayFunctionArgumentsAnalyzer
}
$array_atomic_types[] = $array_atomic_type;
} elseif ($array_atomic_type instanceof TNonEmptyList) {
if (!$context->inside_loop && $array_atomic_type->count !== null) {
if ($array_atomic_type->count === 1) {
$array_atomic_type = Type::getListAtomic(Type::getNever());
} elseif ($array_atomic_type instanceof TKeyedArray && $array_atomic_type->is_list) {
if (!$context->inside_loop
&& ($prop_count = $array_atomic_type->getMaxCount())
&& $prop_count === $array_atomic_type->getMinCount()
) {
if ($prop_count === 1) {
$array_atomic_type = new TArray(
[
Type::getNever(),
Type::getNever(),
]
);
} else {
$array_atomic_type = $array_atomic_type->setCount($array_atomic_type->count-1);
$properties = $array_atomic_type->properties;
unset($properties[$prop_count-1]);
$array_atomic_type = $array_atomic_type->setProperties($properties);
}
} else {
$array_atomic_type = Type::getListAtomic($array_atomic_type->type_param);
$array_atomic_type = Type::getListAtomic($array_atomic_type->getGenericValueType());
}
$array_atomic_types[] = $array_atomic_type;

View File

@ -37,7 +37,6 @@ use Psalm\Type\Atomic\TLiteralInt;
use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TNonEmptyList;
use Psalm\Type\Atomic\TNull;
use Psalm\Type\Atomic\TString;
use Psalm\Type\Union;

View File

@ -35,7 +35,6 @@ use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TMixed;
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TNonEmptyList;
use Psalm\Type\Atomic\TNonEmptyString;
use Psalm\Type\Atomic\TNonspecificLiteralInt;
use Psalm\Type\Atomic\TNonspecificLiteralString;

View File

@ -9,7 +9,6 @@ use Psalm\Type;
use Psalm\Type\Atomic\TArray;
use Psalm\Type\Atomic\TKeyedArray;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TNonEmptyList;
use Psalm\Type\Union;
use function count;

View File

@ -11,7 +11,6 @@ use Psalm\Type\Atomic\TArray;
use Psalm\Type\Atomic\TFalse;
use Psalm\Type\Atomic\TInt;
use Psalm\Type\Atomic\TKeyedArray;
use Psalm\Type\Atomic\TList;
use Psalm\Type\Atomic\TMixed;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TNull;

View File

@ -41,7 +41,6 @@ use Psalm\Type\Atomic\TInt;
use Psalm\Type\Atomic\TIntRange;
use Psalm\Type\Atomic\TIterable;
use Psalm\Type\Atomic\TKeyedArray;
use Psalm\Type\Atomic\TList;
use Psalm\Type\Atomic\TLiteralFloat;
use Psalm\Type\Atomic\TLiteralInt;
use Psalm\Type\Atomic\TLiteralString;

View File

@ -54,7 +54,6 @@ use Psalm\Type\Atomic\TMixed;
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Atomic\TNever;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TNonEmptyList;
use Psalm\Type\Atomic\TNonEmptyLowercaseString;
use Psalm\Type\Atomic\TNonEmptyMixed;
use Psalm\Type\Atomic\TNonEmptyNonspecificLiteralString;
@ -607,12 +606,7 @@ class SimpleAssertionReconciler extends Reconciler
}
} elseif ($array_atomic_type instanceof TKeyedArray) {
$prop_max_count = count($array_atomic_type->properties);
$prop_min_count = 0;
foreach ($array_atomic_type->properties as $property_type) {
if (!$property_type->possibly_undefined) {
$prop_min_count++;
}
}
$prop_min_count = $array_atomic_type->getMinCount();
if ($assertion instanceof HasAtLeastCount) {
if ($array_atomic_type->fallback_params === null) {
@ -731,12 +725,7 @@ class SimpleAssertionReconciler extends Reconciler
}
} elseif ($array_atomic_type instanceof TKeyedArray) {
$prop_max_count = count($array_atomic_type->properties);
$prop_min_count = 0;
foreach ($array_atomic_type->properties as $prop) {
if (!$prop->possibly_undefined) {
$prop_min_count++;
}
}
$prop_min_count = $array_atomic_type->getMinCount();
if ($assertion->count < $prop_min_count) {
// Impossible

View File

@ -45,8 +45,6 @@ use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TMixed;
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Atomic\TNever;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TNonEmptyList;
use Psalm\Type\Atomic\TNonEmptyLowercaseString;
use Psalm\Type\Atomic\TNonEmptyNonspecificLiteralString;
use Psalm\Type\Atomic\TNonEmptyString;
@ -66,6 +64,8 @@ use function get_class;
use function max;
use function strpos;
use const INF;
/**
* @internal
*/
@ -527,12 +527,7 @@ class SimpleNegatedAssertionReconciler extends Reconciler
$prop_max_count = $array_atomic_type->fallback_params === null
? count($array_atomic_type->properties)
: INF;
$prop_min_count = 0;
foreach ($array_atomic_type->properties as $property_type) {
if (!$property_type->possibly_undefined) {
$prop_min_count++;
}
}
$prop_min_count = $array_atomic_type->getMinCount();
// !(count($a) >= 3)
// count($a) < 3

View File

@ -370,6 +370,34 @@ class TKeyedArray extends Atomic
return false;
}
public function getMinCount(): int
{
if ($this->is_list) {
foreach ($this->properties as $k => $property) {
if ($property->possibly_undefined) {
return $k;
}
}
}
$prop_min_count = 0;
foreach ($this->properties as $k => $property) {
if (!$property->possibly_undefined) {
$prop_min_count++;
}
}
return $prop_min_count;
}
/**
* Returns null if there is no upper limit.
*/
public function getMaxCount(): ?int
{
if ($this->fallback_params) {
return null;
}
return count($this->properties);
}
/**
* Whether all keys are always defined (ignores unsealedness).
*/