1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-03 18:17:55 +01:00
This commit is contained in:
Daniil Gentili 2022-11-26 15:45:01 +01:00
parent 956fa4458e
commit fca60dcae8
2 changed files with 104 additions and 36 deletions

View File

@ -625,7 +625,7 @@ class AssertionReconciler extends Reconciler
return $type_2_atomic->addIntersectionType($type_1_atomic); return $type_2_atomic->addIntersectionType($type_1_atomic);
} }
if ($type_2_atomic instanceof TKeyedArray /*if ($type_2_atomic instanceof TKeyedArray
&& $type_1_atomic instanceof TList && $type_1_atomic instanceof TList
) { ) {
$type_2_key = $type_2_atomic->getGenericKeyType(); $type_2_key = $type_2_atomic->getGenericKeyType();
@ -678,7 +678,7 @@ class AssertionReconciler extends Reconciler
true true
); );
} }
} }*/
if ($type_2_atomic instanceof TTemplateParam if ($type_2_atomic instanceof TTemplateParam
&& $type_1_atomic instanceof TTemplateParam && $type_1_atomic instanceof TTemplateParam
@ -730,7 +730,7 @@ class AssertionReconciler extends Reconciler
} }
//we filter the second part of a list with the second part of standard iterables //we filter the second part of a list with the second part of standard iterables
if (($type_2_atomic instanceof TArray /*if (($type_2_atomic instanceof TArray
|| $type_2_atomic instanceof TIterable) || $type_2_atomic instanceof TIterable)
&& $type_1_atomic instanceof TList && $type_1_atomic instanceof TList
) { ) {
@ -756,7 +756,7 @@ class AssertionReconciler extends Reconciler
$matching_atomic_type = $type_1_atomic; $matching_atomic_type = $type_1_atomic;
$atomic_comparison_results->type_coerced = true; $atomic_comparison_results->type_coerced = true;
} }*/
//we filter each property of a Keyed Array with the second part of standard iterables //we filter each property of a Keyed Array with the second part of standard iterables
if (($type_2_atomic instanceof TArray if (($type_2_atomic instanceof TArray

View File

@ -261,7 +261,12 @@ class SimpleAssertionReconciler extends Reconciler
if ($assertion instanceof HasExactCount) { if ($assertion instanceof HasExactCount) {
return self::reconcileExactlyCountable( return self::reconcileExactlyCountable(
$existing_var_type, $existing_var_type,
$assertion->count $assertion,
$key,
$negated,
$code_location,
$suppressed_issues,
$is_equality,
); );
} }
@ -653,7 +658,7 @@ class SimpleAssertionReconciler extends Reconciler
$redundant = false; $redundant = false;
$properties = $array_atomic_type->properties; $properties = $array_atomic_type->properties;
for ($i = $prop_max_count; $i < $assertion->count; $i++) { for ($i = $prop_max_count; $i < $assertion->count; $i++) {
$properties[$i] = $properties[$i] $properties[$i] = isset($properties[$i])
? $properties[$i]->setPossiblyUndefined(false) ? $properties[$i]->setPossiblyUndefined(false)
: $array_atomic_type->fallback_params[1]; : $array_atomic_type->fallback_params[1];
} }
@ -691,46 +696,61 @@ class SimpleAssertionReconciler extends Reconciler
return $existing_var_type->freeze(); return $existing_var_type->freeze();
} }
/**
* @param positive-int $count
*/
private static function reconcileExactlyCountable( private static function reconcileExactlyCountable(
Union $existing_var_type, Union $existing_var_type,
int $count HasExactCount $assertion,
?string $key,
bool $negated,
?CodeLocation $code_location,
array $suppressed_issues,
bool $is_equality
): Union { ): Union {
$existing_var_type = $existing_var_type->getBuilder(); $existing_var_type = $existing_var_type->getBuilder();
if ($existing_var_type->hasType('array')) { if ($existing_var_type->hasType('array')) {
$old_var_type_string = $existing_var_type->getId();
$array_atomic_type = $existing_var_type->getAtomicTypes()['array']; $array_atomic_type = $existing_var_type->getAtomicTypes()['array'];
$redundant = true;
if ($array_atomic_type instanceof TArray) { if ($array_atomic_type instanceof TArray) {
$non_empty_array = new TNonEmptyArray( if (!$array_atomic_type instanceof TNonEmptyArray
$array_atomic_type->type_params, || $array_atomic_type->count !== $assertion->count
$count ) {
); $non_empty_array = new TNonEmptyArray(
$array_atomic_type->type_params,
$assertion->count
);
$existing_var_type->removeType('array'); $existing_var_type->removeType('array');
$existing_var_type->addType( $existing_var_type->addType(
$non_empty_array $non_empty_array
); );
} elseif ($array_atomic_type instanceof TList) {
$properties = []; $redundant = false;
for ($x = 0; $x < $count; $x++) { } else {
$properties []= $array_atomic_type->type_param; $redundant = true;
} }
$non_empty_list = new TKeyedArray(
$properties,
null,
null,
true
);
$existing_var_type->removeType('array');
$existing_var_type->addType(
$non_empty_list
);
} elseif ($array_atomic_type instanceof TKeyedArray) { } elseif ($array_atomic_type instanceof TKeyedArray) {
if ($array_atomic_type->fallback_params === null) { $prop_max_count = count($array_atomic_type->properties);
if (count($array_atomic_type->properties) === $count) { $prop_min_count = 0;
foreach ($array_atomic_type->properties as $prop) {
if (!$prop->possibly_undefined) {
$prop_min_count++;
}
}
if ($assertion->count < $prop_min_count) {
// Impossible
$existing_var_type->removeType('array');
$redundant = false;
} elseif ($assertion->count === $prop_min_count) {
// Redundant
$redundant = true;
} elseif ($array_atomic_type->fallback_params === null) {
if ($assertion->count > $prop_max_count) {
// Impossible
$existing_var_type->removeType('array');
$redundant = false;
} elseif ($assertion->count === $prop_max_count) {
$existing_var_type->removeType('array'); $existing_var_type->removeType('array');
$existing_var_type->addType($array_atomic_type->setProperties( $existing_var_type->addType($array_atomic_type->setProperties(
array_map( array_map(
@ -738,14 +758,62 @@ class SimpleAssertionReconciler extends Reconciler
$array_atomic_type->properties $array_atomic_type->properties
) )
)); ));
} elseif ($existing_var_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];
}
$array_atomic_type = new TKeyedArray(
$properties,
null,
null,
true
);
$existing_var_type->removeType('array');
$existing_var_type->addType($array_atomic_type);
} }
} else { } else {
if ($array_atomic_type->allShapeKeysAlwaysDefined() && count($array_atomic_type->properties) === $count) { if ($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];
}
$array_atomic_type = new TKeyedArray(
$properties,
null,
null,
true
);
$existing_var_type->removeType('array');
$existing_var_type->addType($array_atomic_type);
} elseif ($prop_max_count === $prop_min_count && $prop_max_count === $assertion->count) {
$existing_var_type->removeType('array'); $existing_var_type->removeType('array');
$existing_var_type->addType($array_atomic_type->makeSealed()); $existing_var_type->addType($array_atomic_type->makeSealed());
} }
} }
} }
if (!$is_equality
&& !$existing_var_type->hasMixed()
&& ($redundant || $existing_var_type->isUnionEmpty())
) {
if ($key && $code_location) {
self::triggerIssueForImpossible(
$existing_var_type,
$old_var_type_string,
$key,
$assertion,
$redundant,
$negated,
$code_location,
$suppressed_issues
);
}
}
} }
return $existing_var_type->freeze(); return $existing_var_type->freeze();