mirror of
https://github.com/danog/psalm.git
synced 2024-12-02 17:52:45 +01:00
Cleanup
This commit is contained in:
parent
546f2b325b
commit
51e6b1155d
@ -386,8 +386,6 @@ class ForeachAnalyzer
|
||||
/**
|
||||
* @param PhpParser\Node\Stmt\Foreach_|PhpParser\Node\Expr\YieldFrom $stmt
|
||||
*
|
||||
* @psalm-suppress ComplexMethod
|
||||
*
|
||||
* @return false|null
|
||||
*/
|
||||
public static function checkIteratorType(
|
||||
|
@ -597,21 +597,30 @@ class ArrayAssignmentAnalyzer
|
||||
&& $atomic_root_types['array']->isNonEmpty()
|
||||
)
|
||||
) {
|
||||
$prop_count = null;
|
||||
if ($atomic_root_types['array'] instanceof TNonEmptyArray) {
|
||||
$prop_count = $atomic_root_types['array']->count;
|
||||
} else {
|
||||
$min_count = $atomic_root_types['array']->getMinCount();
|
||||
if ($min_count === $atomic_root_types['array']->getMaxCount()) {
|
||||
$prop_count = $min_count;
|
||||
}
|
||||
}
|
||||
if ($array_atomic_type_array) {
|
||||
$array_atomic_type = new TNonEmptyArray(
|
||||
$array_atomic_type_array,
|
||||
$atomic_root_types['array']->count
|
||||
$prop_count
|
||||
);
|
||||
} else {
|
||||
} else if ($prop_count !== null) {
|
||||
$array_atomic_type = new TKeyedArray(
|
||||
array_fill(
|
||||
0,
|
||||
$atomic_root_types['array']->count,
|
||||
$prop_count,
|
||||
$array_atomic_type_list
|
||||
),
|
||||
null,
|
||||
[
|
||||
new Union([new TIntRange($atomic_root_types['array']->count, null)]),
|
||||
new Union([new TIntRange($prop_count, null)]),
|
||||
$array_atomic_type_list
|
||||
],
|
||||
true
|
||||
@ -623,7 +632,7 @@ class ArrayAssignmentAnalyzer
|
||||
if ($array_atomic_type_array) {
|
||||
$array_atomic_type = new TNonEmptyArray(
|
||||
$array_atomic_type_array,
|
||||
$atomic_root_types['array']->count
|
||||
count($atomic_root_types['array']->properties)
|
||||
);
|
||||
} elseif ($atomic_root_types['array']->is_list) {
|
||||
$array_atomic_type = $atomic_root_types['array'];
|
||||
@ -634,12 +643,12 @@ class ArrayAssignmentAnalyzer
|
||||
$array_atomic_type = new TKeyedArray(
|
||||
array_fill(
|
||||
0,
|
||||
$atomic_root_types['array']->count,
|
||||
count($atomic_root_types['array']->properties),
|
||||
$array_atomic_type_list
|
||||
),
|
||||
null,
|
||||
[
|
||||
new Union([new TIntRange($atomic_root_types['array']->count, null)]),
|
||||
new Union([new TIntRange(count($atomic_root_types['array']->properties), null)]),
|
||||
$array_atomic_type_list
|
||||
],
|
||||
true
|
||||
|
@ -127,8 +127,8 @@ class ArgumentAnalyzer
|
||||
$array_type = $param_type->getAtomicTypes()['array'];
|
||||
|
||||
if ($array_type instanceof TKeyedArray && $array_type->is_list) {
|
||||
$param_type = $array_type->type_param;
|
||||
} else {
|
||||
$param_type = $array_type->getGenericValueType();
|
||||
} elseif ($array_type instanceof TArray) {
|
||||
$param_type = $array_type->type_params[1];
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ class ArrayMapReturnTypeProvider implements FunctionReturnTypeProviderInterface
|
||||
if (($array_arg_atomic_type instanceof TKeyedArray && $array_arg_atomic_type->is_list)
|
||||
|| count($call_args) !== 2
|
||||
) {
|
||||
if ($array_arg_atomic_type->isNonEmpty()) {
|
||||
if ($array_arg_atomic_type instanceof TKeyedArray && $array_arg_atomic_type->isNonEmpty()) {
|
||||
return Type::getNonEmptyList(
|
||||
$mapping_return_type
|
||||
);
|
||||
|
@ -217,10 +217,6 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
|
||||
$inner_value_type = null;
|
||||
|
||||
if ($inner_key_types) {
|
||||
/**
|
||||
* Truthy&array-shape-list doesn't reconcile correctly, will be fixed for 5.x by #8050.
|
||||
* @psalm-suppress InvalidScalarArgument
|
||||
*/
|
||||
$inner_key_type = TypeCombiner::combine($inner_key_types, $codebase, true);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ class ArrayReverseReturnTypeProvider implements FunctionReturnTypeProviderInterf
|
||||
return $first_arg_type;
|
||||
}
|
||||
|
||||
if ($first_arg_array instanceof TKeyedArray && $first_arg_array->is_list) {
|
||||
if ($first_arg_array->is_list) {
|
||||
$second_arg = $call_args[1]->value ?? null;
|
||||
|
||||
if (!$second_arg
|
||||
@ -64,7 +64,7 @@ class ArrayReverseReturnTypeProvider implements FunctionReturnTypeProviderInterf
|
||||
return $first_arg_type;
|
||||
}
|
||||
|
||||
return $first_arg_array->setProperties(array_reverse($first_arg_array->properties));
|
||||
return new Union([$first_arg_array->setProperties(array_reverse($first_arg_array->properties))]);
|
||||
}
|
||||
|
||||
return new Union([$first_arg_array->getGenericArrayType()]);
|
||||
|
@ -33,7 +33,7 @@ class ArraySpliceReturnTypeProvider implements FunctionReturnTypeProviderInterfa
|
||||
|
||||
$first_arg = $call_args[0]->value ?? null;
|
||||
|
||||
$first_arg_array = $first_arg
|
||||
$array_type = $first_arg
|
||||
&& ($first_arg_type = $statements_source->node_data->getType($first_arg))
|
||||
&& $first_arg_type->hasType('array')
|
||||
&& ($array_atomic_type = $first_arg_type->getAtomicTypes()['array'])
|
||||
@ -42,18 +42,12 @@ class ArraySpliceReturnTypeProvider implements FunctionReturnTypeProviderInterfa
|
||||
? $array_atomic_type
|
||||
: null;
|
||||
|
||||
if (!$first_arg_array) {
|
||||
if (!$array_type) {
|
||||
return Type::getArray();
|
||||
}
|
||||
|
||||
if ($first_arg_array instanceof TKeyedArray) {
|
||||
$first_arg_array = $first_arg_array->getGenericArrayType();
|
||||
}
|
||||
|
||||
if ($first_arg_array instanceof TArray) {
|
||||
$array_type = new TArray($first_arg_array->type_params);
|
||||
} else {
|
||||
$array_type = new TArray([Type::getInt(), $first_arg_array->type_param]);
|
||||
if ($array_type instanceof TKeyedArray) {
|
||||
$array_type = $array_type->getGenericArrayType();
|
||||
}
|
||||
|
||||
if (!$array_type->type_params[0]->hasString()) {
|
||||
|
@ -55,24 +55,6 @@ class ArrayUniqueReturnTypeProvider implements FunctionReturnTypeProviderInterfa
|
||||
return new Union([$first_arg_array]);
|
||||
}
|
||||
|
||||
if ($first_arg_array instanceof TKeyedArray && $first_arg_array->is_list) {
|
||||
if (!$first_arg_array->properties[0]->possibly_undefined) {
|
||||
return new Union([
|
||||
new TNonEmptyArray([
|
||||
Type::getInt(),
|
||||
$first_arg_array->type_param
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
return new Union([
|
||||
new TArray([
|
||||
Type::getInt(),
|
||||
$first_arg_array->type_param
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
return new Union([$first_arg_array->getGenericArrayType()]);
|
||||
}
|
||||
}
|
||||
|
@ -3,22 +3,16 @@
|
||||
namespace Psalm\Internal\Type\Comparator;
|
||||
|
||||
use Psalm\Codebase;
|
||||
use Psalm\Type;
|
||||
use Psalm\Type\Atomic;
|
||||
use Psalm\Type\Atomic\TArray;
|
||||
use Psalm\Type\Atomic\TClassStringMap;
|
||||
use Psalm\Type\Atomic\TKeyedArray;
|
||||
use Psalm\Type\Atomic\TList;
|
||||
use Psalm\Type\Atomic\TLiteralInt;
|
||||
use Psalm\Type\Atomic\TLiteralString;
|
||||
use Psalm\Type\Atomic\TNever;
|
||||
use Psalm\Type\Atomic\TNonEmptyArray;
|
||||
use Psalm\Type\Atomic\TNonEmptyList;
|
||||
use Psalm\Type\Union;
|
||||
|
||||
use function array_map;
|
||||
use function range;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@ -128,40 +122,7 @@ class ArrayTypeComparator
|
||||
);
|
||||
}
|
||||
|
||||
if ($input_type_part instanceof TList
|
||||
&& $container_type_part instanceof TList
|
||||
) {
|
||||
if (!UnionTypeComparator::isContainedBy(
|
||||
$codebase,
|
||||
$input_type_part->type_param,
|
||||
$container_type_part->type_param,
|
||||
$input_type_part->type_param->ignore_nullable_issues,
|
||||
$input_type_part->type_param->ignore_falsable_issues,
|
||||
$atomic_comparison_result,
|
||||
$allow_interface_equality
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $input_type_part instanceof TNonEmptyList
|
||||
|| !$container_type_part instanceof TNonEmptyList;
|
||||
}
|
||||
|
||||
if ($container_type_part instanceof TKeyedArray) {
|
||||
if ($container_type_part->is_list) {
|
||||
$container_type_part = $container_type_part->isNonEmpty()
|
||||
? Type::getNonEmptyListAtomic($container_type_part->getGenericValueType())
|
||||
: Type::getListAtomic($container_type_part->getGenericValueType());
|
||||
|
||||
return self::isContainedBy(
|
||||
$codebase,
|
||||
$input_type_part,
|
||||
$container_type_part,
|
||||
$allow_interface_equality,
|
||||
$atomic_comparison_result
|
||||
);
|
||||
}
|
||||
|
||||
$container_type_part = $container_type_part->getGenericArrayType();
|
||||
}
|
||||
|
||||
@ -183,37 +144,6 @@ class ArrayTypeComparator
|
||||
]);
|
||||
}
|
||||
|
||||
if ($container_type_part instanceof TList) {
|
||||
$all_types_contain = false;
|
||||
|
||||
if ($atomic_comparison_result) {
|
||||
$atomic_comparison_result->type_coerced = true;
|
||||
}
|
||||
|
||||
$container_type_part = new TArray([Type::getInt(), $container_type_part->type_param]);
|
||||
}
|
||||
|
||||
if ($input_type_part instanceof TList) {
|
||||
if ($input_type_part instanceof TNonEmptyList) {
|
||||
// if the array has a known size < 10, make sure the array keys are literal ints
|
||||
if ($input_type_part->count !== null && $input_type_part->count < 10) {
|
||||
$literal_ints = array_map(
|
||||
static fn($i): TLiteralInt => new TLiteralInt($i),
|
||||
range(0, $input_type_part->count - 1)
|
||||
);
|
||||
|
||||
$input_type_part = new TNonEmptyArray([
|
||||
new Union($literal_ints),
|
||||
$input_type_part->type_param
|
||||
]);
|
||||
} else {
|
||||
$input_type_part = new TNonEmptyArray([Type::getInt(), $input_type_part->type_param]);
|
||||
}
|
||||
} else {
|
||||
$input_type_part = new TArray([Type::getInt(), $input_type_part->type_param]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($input_type_part->type_params as $i => $input_param) {
|
||||
if ($i > 1) {
|
||||
break;
|
||||
|
@ -20,13 +20,11 @@ use Psalm\Type\Atomic\TGenericObject;
|
||||
use Psalm\Type\Atomic\TIterable;
|
||||
use Psalm\Type\Atomic\TKeyOf;
|
||||
use Psalm\Type\Atomic\TKeyedArray;
|
||||
use Psalm\Type\Atomic\TList;
|
||||
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\TNull;
|
||||
use Psalm\Type\Atomic\TObject;
|
||||
use Psalm\Type\Atomic\TObjectWithProperties;
|
||||
@ -740,18 +738,6 @@ class AtomicTypeComparator
|
||||
Atomic $type2_part,
|
||||
bool $allow_interface_equality = true
|
||||
): bool {
|
||||
if ((get_class($type1_part) === TList::class
|
||||
&& $type2_part instanceof TNonEmptyList)
|
||||
|| (get_class($type2_part) === TList::class
|
||||
&& $type1_part instanceof TNonEmptyList)
|
||||
) {
|
||||
return UnionTypeComparator::canExpressionTypesBeIdentical(
|
||||
$codebase,
|
||||
$type1_part->type_param,
|
||||
$type2_part->type_param
|
||||
);
|
||||
}
|
||||
|
||||
if ((get_class($type1_part) === TArray::class
|
||||
&& $type2_part instanceof TNonEmptyArray)
|
||||
|| (get_class($type2_part) === TArray::class
|
||||
|
@ -46,7 +46,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\TLiteralInt;
|
||||
use Psalm\Type\Atomic\TLiteralString;
|
||||
use Psalm\Type\Atomic\TLowercaseString;
|
||||
@ -359,7 +358,7 @@ class SimpleAssertionReconciler extends Reconciler
|
||||
|
||||
if ($assertion_type instanceof TKeyedArray
|
||||
&& $assertion_type->is_list
|
||||
&& $assertion_type->type_param->isMixed()
|
||||
&& $assertion_type->getGenericValueType()->isMixed()
|
||||
) {
|
||||
return self::reconcileList(
|
||||
$assertion,
|
||||
@ -690,6 +689,9 @@ class SimpleAssertionReconciler extends Reconciler
|
||||
return $existing_var_type->freeze();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $suppressed_issues
|
||||
*/
|
||||
private static function reconcileExactlyCountable(
|
||||
Union $existing_var_type,
|
||||
HasExactCount $assertion,
|
||||
@ -747,12 +749,10 @@ class SimpleAssertionReconciler extends Reconciler
|
||||
$array_atomic_type->properties
|
||||
)
|
||||
));
|
||||
} elseif ($existing_var_type->is_list) {
|
||||
} elseif ($array_atomic_type->is_list) {
|
||||
$properties = $array_atomic_type->properties;
|
||||
for ($x = $prop_min_count; $x < $assertion->count; $x++) {
|
||||
$properties[$x] = isset($properties[$x])
|
||||
? $properties[$x]->setPossiblyUndefined(false)
|
||||
: $array_atomic_type->fallback_params[1];
|
||||
$properties[$x] = $properties[$x]->setPossiblyUndefined(false);
|
||||
}
|
||||
$array_atomic_type = new TKeyedArray(
|
||||
$properties,
|
||||
|
@ -59,13 +59,10 @@ use Psalm\Type\Reconciler;
|
||||
use Psalm\Type\Union;
|
||||
|
||||
use function assert;
|
||||
use function count;
|
||||
use function get_class;
|
||||
use function max;
|
||||
use function strpos;
|
||||
|
||||
use const INF;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -1488,12 +1488,21 @@ class TypeCombiner
|
||||
true
|
||||
);
|
||||
} else {
|
||||
/** @psalm-suppress ArgumentTypeCoercion */
|
||||
$array_type = Type::getNonEmptyListAtomic(
|
||||
$generic_type_params[1],
|
||||
$combination->array_min_counts
|
||||
? min(array_keys($combination->array_min_counts))
|
||||
: null
|
||||
$cnt = $combination->array_min_counts
|
||||
? min(array_keys($combination->array_min_counts))
|
||||
: 0;
|
||||
$properties = [];
|
||||
for ($x = 0; $x < $cnt; $x++) {
|
||||
$properties []= $generic_type_params[1];
|
||||
}
|
||||
if (!$properties) {
|
||||
$properties []= $generic_type_params[1]->setPossiblyUndefined(true);
|
||||
}
|
||||
$array_type = new TKeyedArray(
|
||||
$properties,
|
||||
null,
|
||||
[new Union([new TIntRange($cnt, null)]), $generic_type_params[1]],
|
||||
true
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -464,7 +464,8 @@ abstract class Type
|
||||
[$of->setPossiblyUndefined(true)],
|
||||
null,
|
||||
[self::getInt(), $of],
|
||||
true
|
||||
true,
|
||||
$from_docblock
|
||||
);
|
||||
}
|
||||
|
||||
@ -477,26 +478,11 @@ abstract class Type
|
||||
[$of->setPossiblyUndefined(false)],
|
||||
null,
|
||||
[self::getInt(), $of],
|
||||
true
|
||||
true,
|
||||
$from_docblock
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function getCallableListAtomic(Union $of, bool $from_docblock = false): Atomic
|
||||
{
|
||||
// The following code will be uncommented in Psalm 5.1
|
||||
//$of = $of->setPossiblyUndefined(false);
|
||||
//return new TCallableKeyedArray(
|
||||
// [$of, $of],
|
||||
// null,
|
||||
// [self::getInt(), $of],
|
||||
// true
|
||||
//);
|
||||
return new TCallableList($of, null, null, $from_docblock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*/
|
||||
|
@ -370,6 +370,9 @@ class TKeyedArray extends Atomic
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int<0, max>
|
||||
*/
|
||||
public function getMinCount(): int
|
||||
{
|
||||
if ($this->is_list) {
|
||||
@ -380,7 +383,7 @@ class TKeyedArray extends Atomic
|
||||
}
|
||||
}
|
||||
$prop_min_count = 0;
|
||||
foreach ($this->properties as $k => $property) {
|
||||
foreach ($this->properties as $property) {
|
||||
if (!$property->possibly_undefined) {
|
||||
$prop_min_count++;
|
||||
}
|
||||
@ -390,6 +393,7 @@ class TKeyedArray extends Atomic
|
||||
|
||||
/**
|
||||
* Returns null if there is no upper limit.
|
||||
* @return int<1, max>|null
|
||||
*/
|
||||
public function getMaxCount(): ?int
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user