mirror of
https://github.com/danog/psalm.git
synced 2024-12-04 18:48:03 +01:00
Merge pull request #6304 from vimeo/revert-6210-int-range3
This commit is contained in:
commit
4c26293260
@ -56,7 +56,6 @@
|
||||
<errorLevel type="suppress">
|
||||
<referencedClass name="PackageVersions\Versions"/>
|
||||
<referencedClass name="Psalm\Plugin\Hook\*" />
|
||||
<referencedClass name="Psalm\Type\Atomic\TPositiveInt" />
|
||||
</errorLevel>
|
||||
</DeprecatedClass>
|
||||
|
||||
|
@ -456,10 +456,6 @@ class Algebra
|
||||
array $right_clauses,
|
||||
int $conditional_object_id
|
||||
): array {
|
||||
if (count($left_clauses) > 60000 || count($right_clauses) > 60000) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$clauses = [];
|
||||
|
||||
$all_wedges = true;
|
||||
|
@ -93,7 +93,7 @@ class AssertionFinder
|
||||
|
||||
if ($var_name) {
|
||||
if ($candidate_if_types) {
|
||||
$if_types[$var_name] = [['@' . \json_encode($candidate_if_types[0])]];
|
||||
$if_types[$var_name] = [['>' . \json_encode($candidate_if_types[0])]];
|
||||
} else {
|
||||
$if_types[$var_name] = [['!falsy']];
|
||||
}
|
||||
@ -1579,42 +1579,6 @@ class AssertionFinder
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PhpParser\Node\Expr\BinaryOp\Greater|PhpParser\Node\Expr\BinaryOp\GreaterOrEqual $conditional
|
||||
* @return false|int
|
||||
*/
|
||||
protected static function hasSuperiorNumberCheck(
|
||||
PhpParser\Node\Expr\BinaryOp $conditional,
|
||||
?int &$literal_value_comparison
|
||||
) {
|
||||
if ($conditional->right instanceof PhpParser\Node\Scalar\LNumber) {
|
||||
$literal_value_comparison = $conditional->right->value +
|
||||
($conditional instanceof PhpParser\Node\Expr\BinaryOp\Greater ? 1 : 0);
|
||||
|
||||
return self::ASSIGNMENT_TO_RIGHT;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PhpParser\Node\Expr\BinaryOp\Smaller|PhpParser\Node\Expr\BinaryOp\SmallerOrEqual $conditional
|
||||
* @return false|int
|
||||
*/
|
||||
protected static function hasInferiorNumberCheck(
|
||||
PhpParser\Node\Expr\BinaryOp $conditional,
|
||||
?int &$literal_value_comparison
|
||||
) {
|
||||
if ($conditional->right instanceof PhpParser\Node\Scalar\LNumber) {
|
||||
$literal_value_comparison = $conditional->right->value +
|
||||
($conditional instanceof PhpParser\Node\Expr\BinaryOp\Smaller ? -1 : 0);
|
||||
|
||||
return self::ASSIGNMENT_TO_RIGHT;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PhpParser\Node\Expr\BinaryOp\Greater|PhpParser\Node\Expr\BinaryOp\GreaterOrEqual $conditional
|
||||
* @return false|int
|
||||
@ -3652,8 +3616,6 @@ class AssertionFinder
|
||||
$count_equality_position = self::hasNonEmptyCountEqualityCheck($conditional, $min_count);
|
||||
$min_comparison = null;
|
||||
$positive_number_position = self::hasPositiveNumberCheck($conditional, $min_comparison);
|
||||
$superior_value_comparison = null;
|
||||
$superior_value_position = self::hasSuperiorNumberCheck($conditional, $superior_value_comparison);
|
||||
$zero_comparison = null;
|
||||
$zero_position = self::hasZeroCheck($conditional, $zero_comparison);
|
||||
$max_count = null;
|
||||
@ -3713,28 +3675,6 @@ class AssertionFinder
|
||||
return $if_types ? [$if_types] : [];
|
||||
}
|
||||
|
||||
if ($superior_value_position) {
|
||||
if ($superior_value_position === self::ASSIGNMENT_TO_RIGHT) {
|
||||
$var_name = ExpressionIdentifier::getArrayVarId(
|
||||
$conditional->left,
|
||||
$this_class_name,
|
||||
$source
|
||||
);
|
||||
} else {
|
||||
$var_name = ExpressionIdentifier::getArrayVarId(
|
||||
$conditional->right,
|
||||
$this_class_name,
|
||||
$source
|
||||
);
|
||||
}
|
||||
|
||||
if ($var_name) {
|
||||
$if_types[$var_name] = [['=isset'], ['>' . $superior_value_comparison]];
|
||||
}
|
||||
|
||||
return $if_types ? [$if_types] : [];
|
||||
}
|
||||
|
||||
if ($positive_number_position) {
|
||||
if ($positive_number_position === self::ASSIGNMENT_TO_RIGHT) {
|
||||
$var_name = ExpressionIdentifier::getArrayVarId(
|
||||
@ -3864,8 +3804,6 @@ class AssertionFinder
|
||||
$min_count = null;
|
||||
$count_equality_position = self::hasNonEmptyCountEqualityCheck($conditional, $min_count);
|
||||
$typed_value_position = self::hasTypedValueComparison($conditional, $source);
|
||||
$inferior_value_comparison = null;
|
||||
$inferior_value_position = self::hasInferiorNumberCheck($conditional, $inferior_value_comparison);
|
||||
|
||||
$max_count = null;
|
||||
$count_inequality_position = self::hasLessThanCountEqualityCheck($conditional, $max_count);
|
||||
@ -3920,28 +3858,6 @@ class AssertionFinder
|
||||
return $if_types ? [$if_types] : [];
|
||||
}
|
||||
|
||||
if ($inferior_value_position) {
|
||||
if ($inferior_value_position === self::ASSIGNMENT_TO_RIGHT) {
|
||||
$var_name = ExpressionIdentifier::getArrayVarId(
|
||||
$conditional->left,
|
||||
$this_class_name,
|
||||
$source
|
||||
);
|
||||
} else {
|
||||
$var_name = ExpressionIdentifier::getArrayVarId(
|
||||
$conditional->right,
|
||||
$this_class_name,
|
||||
$source
|
||||
);
|
||||
}
|
||||
|
||||
if ($var_name) {
|
||||
$if_types[$var_name] = [['=isset'], ['<' . $inferior_value_comparison]];
|
||||
}
|
||||
|
||||
return $if_types ? [$if_types] : [];
|
||||
}
|
||||
|
||||
if ($typed_value_position) {
|
||||
if ($typed_value_position === self::ASSIGNMENT_TO_RIGHT) {
|
||||
$var_name = ExpressionIdentifier::getArrayVarId(
|
||||
|
@ -86,7 +86,7 @@ class AssertionReconciler extends \Psalm\Type\Reconciler
|
||||
|
||||
$original_assertion = $assertion;
|
||||
|
||||
if ($assertion[0] === '@') {
|
||||
if ($assertion[0] === '>') {
|
||||
$assertion = 'falsy';
|
||||
$is_negation = true;
|
||||
}
|
||||
|
@ -410,50 +410,6 @@ class ScalarTypeComparator
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($input_type_part instanceof TInt && $container_type_part instanceof TIntRange) {
|
||||
if ($input_type_part instanceof TPositiveInt) {
|
||||
if ($container_type_part->min_bound > 1) {
|
||||
//any positive int can't be pushed inside a range with a min > 1
|
||||
if ($atomic_comparison_result) {
|
||||
$atomic_comparison_result->type_coerced = true;
|
||||
$atomic_comparison_result->type_coerced_from_scalar = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($container_type_part->max_bound !== null) {
|
||||
//any positive int can't be pushed inside a range where the max bound isn't max without coercion
|
||||
if ($atomic_comparison_result) {
|
||||
$atomic_comparison_result->type_coerced = true;
|
||||
$atomic_comparison_result->type_coerced_from_scalar = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
if ($input_type_part instanceof TLiteralInt) {
|
||||
$min_bound = $container_type_part->min_bound;
|
||||
$max_bound = $container_type_part->max_bound;
|
||||
|
||||
return
|
||||
($min_bound === null || $min_bound <= $input_type_part->value) &&
|
||||
($max_bound === null || $max_bound >= $input_type_part->value);
|
||||
}
|
||||
|
||||
//any int can't be pushed inside a range without coercion (unless the range is from min to max)
|
||||
if ($container_type_part->min_bound !== null || $container_type_part->max_bound !== null) {
|
||||
if ($atomic_comparison_result) {
|
||||
$atomic_comparison_result->type_coerced = true;
|
||||
$atomic_comparison_result->type_coerced_from_scalar = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (get_class($input_type_part) === TFloat::class && $container_type_part instanceof TLiteralFloat) {
|
||||
if ($atomic_comparison_result) {
|
||||
$atomic_comparison_result->type_coerced = true;
|
||||
|
@ -40,8 +40,6 @@ use function array_filter;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function get_class;
|
||||
use function max;
|
||||
use function min;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
|
||||
@ -107,20 +105,6 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler
|
||||
);
|
||||
}
|
||||
|
||||
if ($assertion[0] === '>') {
|
||||
return self::reconcileSuperiorTo(
|
||||
$existing_var_type,
|
||||
substr($assertion, 1)
|
||||
);
|
||||
}
|
||||
|
||||
if ($assertion[0] === '<') {
|
||||
return self::reconcileInferiorTo(
|
||||
$existing_var_type,
|
||||
substr($assertion, 1)
|
||||
);
|
||||
}
|
||||
|
||||
if ($assertion === 'falsy' || $assertion === 'empty') {
|
||||
return self::reconcileFalsyOrEmpty(
|
||||
$assertion,
|
||||
@ -1574,49 +1558,6 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler
|
||||
return $existing_var_type;
|
||||
}
|
||||
|
||||
private static function reconcileSuperiorTo(
|
||||
Union $existing_var_type,
|
||||
string $assertion
|
||||
) : Union {
|
||||
foreach ($existing_var_type->getAtomicTypes() as $atomic_type) {
|
||||
if ($atomic_type instanceof Atomic\TIntRange) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
if ($atomic_type->min_bound === null) {
|
||||
$atomic_type->min_bound = (int)$assertion;
|
||||
} else {
|
||||
$atomic_type->min_bound = max($atomic_type->min_bound, (int)$assertion);
|
||||
}
|
||||
$existing_var_type->addType($atomic_type);
|
||||
} elseif ($atomic_type instanceof TInt) {
|
||||
$existing_var_type->removeType('int');
|
||||
$existing_var_type->addType(new Atomic\TIntRange((int)$assertion, null));
|
||||
}
|
||||
}
|
||||
|
||||
return $existing_var_type;
|
||||
}
|
||||
|
||||
private static function reconcileInferiorTo(
|
||||
Union $existing_var_type,
|
||||
string $assertion
|
||||
) : Union {
|
||||
foreach ($existing_var_type->getAtomicTypes() as $atomic_type) {
|
||||
if ($atomic_type instanceof Atomic\TIntRange) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
if ($atomic_type->max_bound === null) {
|
||||
$atomic_type->max_bound = (int)$assertion;
|
||||
} else {
|
||||
$atomic_type->max_bound = min($atomic_type->max_bound, (int)$assertion);
|
||||
}
|
||||
$existing_var_type->addType($atomic_type);
|
||||
} elseif ($atomic_type instanceof TInt) {
|
||||
$existing_var_type->removeType('int');
|
||||
$existing_var_type->addType(new Atomic\TIntRange(null, (int)$assertion));
|
||||
}
|
||||
}
|
||||
return $existing_var_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $suppressed_issues
|
||||
* @param 0|1|2 $failed_reconciliation
|
||||
|
@ -3,7 +3,6 @@ namespace Psalm\Type\Atomic;
|
||||
|
||||
/**
|
||||
* Denotes an int that is also positive (strictly > 0)
|
||||
* @deprecated will be removed in Psalm 5, this is replaced by TIntRange when min_bound is at least 1
|
||||
*/
|
||||
class TPositiveInt extends TInt
|
||||
{
|
||||
|
@ -162,9 +162,9 @@ class Reconciler
|
||||
$orred_type = null;
|
||||
|
||||
foreach ($new_type_part_parts as $new_type_part_part) {
|
||||
if ($new_type_part_part[0] === '@'
|
||||
if ($new_type_part_part[0] === '>'
|
||||
|| ($new_type_part_part[0] === '!'
|
||||
&& $new_type_part_part[1] === '@')
|
||||
&& $new_type_part_part[1] === '>')
|
||||
) {
|
||||
if ($new_type_part_part[0] === '!') {
|
||||
$nested_negated = !$negated;
|
||||
|
@ -42,16 +42,6 @@ class IntRangeTest extends TestCase
|
||||
return $a;
|
||||
}',
|
||||
],
|
||||
'intReduced' => [
|
||||
'<?php
|
||||
function getInt(): int{return 0;}
|
||||
$a = getInt();
|
||||
assert($a >= 500);
|
||||
assert($a < 5000);',
|
||||
'assertions' => [
|
||||
'$a===' => 'int<500, 4999>'
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user