1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

fix reconciliation when the assertions is not part of the existing range and add tests

This commit is contained in:
orklah 2022-01-07 19:38:15 +01:00
parent c0864b2652
commit af28687708
4 changed files with 74 additions and 0 deletions

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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',
],
];
}
}