mirror of
https://github.com/danog/psalm.git
synced 2024-11-27 04:45:20 +01:00
fix reconciliation when the assertions is not part of the existing range and add tests
This commit is contained in:
parent
c0864b2652
commit
af28687708
@ -1653,6 +1653,7 @@ class SimpleAssertionReconciler extends Reconciler
|
||||
|
||||
if ($atomic_type instanceof TIntRange) {
|
||||
if ($atomic_type->contains($assertion_value)) {
|
||||
// if the range contains the assertion, the range must be adapted
|
||||
$did_remove_type = true;
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
if ($atomic_type->min_bound === null) {
|
||||
@ -1664,6 +1665,12 @@ class SimpleAssertionReconciler extends Reconciler
|
||||
);
|
||||
}
|
||||
$existing_var_type->addType($atomic_type);
|
||||
} elseif ($atomic_type->isLesserThan($assertion_value)) {
|
||||
// if the range is lesser than the assertion, the type must be removed
|
||||
$did_remove_type = true;
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
} elseif ($atomic_type->isGreaterThan($assertion_value)) {
|
||||
// if the range is greater than the assertion, the check is redundant
|
||||
}
|
||||
} elseif ($atomic_type instanceof TLiteralInt) {
|
||||
if ($atomic_type->value < $assertion_value) {
|
||||
@ -1751,6 +1758,7 @@ class SimpleAssertionReconciler extends Reconciler
|
||||
|
||||
if ($atomic_type instanceof TIntRange) {
|
||||
if ($atomic_type->contains($assertion_value)) {
|
||||
// if the range contains the assertion, the range must be adapted
|
||||
$did_remove_type = true;
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
if ($atomic_type->max_bound === null) {
|
||||
@ -1759,6 +1767,12 @@ class SimpleAssertionReconciler extends Reconciler
|
||||
$atomic_type->max_bound = min($atomic_type->max_bound, $assertion_value);
|
||||
}
|
||||
$existing_var_type->addType($atomic_type);
|
||||
} elseif ($atomic_type->isLesserThan($assertion_value)) {
|
||||
// if the range is lesser than the assertion, the check is redundant
|
||||
} elseif ($atomic_type->isGreaterThan($assertion_value)) {
|
||||
// if the range is greater than the assertion, the type must be removed
|
||||
$did_remove_type = true;
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
}
|
||||
} elseif ($atomic_type instanceof TLiteralInt) {
|
||||
if ($atomic_type->value > $assertion_value) {
|
||||
|
@ -1638,6 +1638,7 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
||||
|
||||
if ($atomic_type instanceof TIntRange) {
|
||||
if ($atomic_type->contains($assertion_value)) {
|
||||
// if the range contains the assertion, the range must be adapted
|
||||
$did_remove_type = true;
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
if ($atomic_type->max_bound === null) {
|
||||
@ -1649,6 +1650,12 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
||||
);
|
||||
}
|
||||
$existing_var_type->addType($atomic_type);
|
||||
} elseif ($atomic_type->isLesserThan($assertion_value)) {
|
||||
// if the range is lesser than the assertion, the check is redundant
|
||||
} elseif ($atomic_type->isGreaterThan($assertion_value)) {
|
||||
// if the range is greater than the assertion, the type must be removed
|
||||
$did_remove_type = true;
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
}
|
||||
} elseif ($atomic_type instanceof TLiteralInt) {
|
||||
if ($atomic_type->value > $assertion_value) {
|
||||
@ -1736,6 +1743,7 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
||||
|
||||
if ($atomic_type instanceof TIntRange) {
|
||||
if ($atomic_type->contains($assertion_value)) {
|
||||
// if the range contains the assertion, the range must be adapted
|
||||
$did_remove_type = true;
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
if ($atomic_type->min_bound === null) {
|
||||
@ -1744,6 +1752,12 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
||||
$atomic_type->min_bound = max($atomic_type->min_bound, $assertion_value);
|
||||
}
|
||||
$existing_var_type->addType($atomic_type);
|
||||
} elseif ($atomic_type->isLesserThan($assertion_value)) {
|
||||
// if the range is lesser than the assertion, the type must be removed
|
||||
$did_remove_type = true;
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
} elseif ($atomic_type->isGreaterThan($assertion_value)) {
|
||||
// if the range is greater than the assertion, the check is redundant
|
||||
}
|
||||
} elseif ($atomic_type instanceof TLiteralInt) {
|
||||
if ($atomic_type->value < $assertion_value) {
|
||||
|
@ -86,6 +86,22 @@ class TIntRange extends TInt
|
||||
($this->min_bound <= $i && $this->max_bound >= $i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if every part of the Range is lesser than the given value
|
||||
*/
|
||||
public function isLesserThan(int $i): bool
|
||||
{
|
||||
return $this->max_bound !== null && $this->max_bound < $i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if every part of the Range is greater than the given value
|
||||
*/
|
||||
public function isGreaterThan(int $i): bool
|
||||
{
|
||||
return $this->min_bound !== null && $this->min_bound > $i;
|
||||
}
|
||||
|
||||
public static function getNewLowestBound(?int $bound1, ?int $bound2): ?int
|
||||
{
|
||||
if ($bound1 === null || $bound2 === null) {
|
||||
|
@ -702,6 +702,36 @@ class IntRangeTest extends TestCase
|
||||
}',
|
||||
'error_message' => 'InvalidReturnType',
|
||||
],
|
||||
'assertOutOfRange' => [
|
||||
'<?php
|
||||
/**
|
||||
* @param int<1, 5> $a
|
||||
*/
|
||||
function scope(int $a): void{
|
||||
assert($a === 0);
|
||||
}',
|
||||
'error_message' => 'DocblockTypeContradiction',
|
||||
],
|
||||
'assertRedundantInferior' => [
|
||||
'<?php
|
||||
/**
|
||||
* @param int<min, 5> $a
|
||||
*/
|
||||
function scope(int $a): void{
|
||||
assert($a < 10);
|
||||
}',
|
||||
'error_message' => 'RedundantConditionGivenDocblockType',
|
||||
],
|
||||
'assertImpossibleInferior' => [
|
||||
'<?php
|
||||
/**
|
||||
* @param int<5, max> $a
|
||||
*/
|
||||
function scope(int $a): void{
|
||||
assert($a < 4);
|
||||
}',
|
||||
'error_message' => 'DocblockTypeContradiction',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user