mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Merge pull request #7106 from orklah/7098
fix reconciliation between positive-int and inferior/superior assertions
This commit is contained in:
commit
604f47d52a
@ -1638,8 +1638,7 @@ class SimpleAssertionReconciler extends Reconciler
|
||||
}
|
||||
$existing_var_type->addType($atomic_type);
|
||||
} elseif ($atomic_type instanceof Atomic\TLiteralInt) {
|
||||
$new_range = new Atomic\TIntRange($assertion_value, null);
|
||||
if (!$new_range->contains($atomic_type->value)) {
|
||||
if ($atomic_type->value < $assertion_value) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
} /*elseif ($inside_loop) {
|
||||
//when inside a loop, allow the range to extends the type
|
||||
@ -1651,11 +1650,10 @@ class SimpleAssertionReconciler extends Reconciler
|
||||
}
|
||||
}*/
|
||||
} elseif ($atomic_type instanceof Atomic\TPositiveInt) {
|
||||
if ($assertion_value <= 0) {
|
||||
//emit an issue here in the future about incompatible type
|
||||
if ($assertion_value > 1) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
$existing_var_type->addType(new Atomic\TIntRange($assertion_value, null));
|
||||
}
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
$existing_var_type->addType(new Atomic\TIntRange($assertion_value, null));
|
||||
} elseif ($atomic_type instanceof TInt) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
$existing_var_type->addType(new Atomic\TIntRange($assertion_value, null));
|
||||
@ -1685,10 +1683,9 @@ class SimpleAssertionReconciler extends Reconciler
|
||||
}
|
||||
$existing_var_type->addType($atomic_type);
|
||||
} elseif ($atomic_type instanceof Atomic\TLiteralInt) {
|
||||
$new_range = new Atomic\TIntRange(null, $assertion_value);
|
||||
if (!$new_range->contains($atomic_type->value)) {
|
||||
if ($atomic_type->value > $assertion_value) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
}/* elseif ($inside_loop) {
|
||||
} /* elseif ($inside_loop) {
|
||||
//when inside a loop, allow the range to extends the type
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
if ($atomic_type->value < $assertion_value) {
|
||||
@ -1698,11 +1695,10 @@ class SimpleAssertionReconciler extends Reconciler
|
||||
}
|
||||
}*/
|
||||
} elseif ($atomic_type instanceof Atomic\TPositiveInt) {
|
||||
if ($assertion_value <= 0) {
|
||||
//emit an issue here in the future about incompatible type
|
||||
}
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
$existing_var_type->addType(new Atomic\TIntRange(1, $assertion_value));
|
||||
if ($assertion_value >= 1) {
|
||||
$existing_var_type->addType(new Atomic\TIntRange(1, $assertion_value));
|
||||
}
|
||||
} elseif ($atomic_type instanceof TInt) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
$existing_var_type->addType(new Atomic\TIntRange(null, $assertion_value));
|
||||
|
@ -1519,9 +1519,7 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
||||
}
|
||||
$existing_var_type->addType($atomic_type);
|
||||
} elseif ($atomic_type instanceof Atomic\TLiteralInt) {
|
||||
$new_range = new Atomic\TIntRange(null, $assertion_value);
|
||||
if (!$new_range->contains($atomic_type->value)) {
|
||||
//emit an issue here in the future about incompatible type
|
||||
if ($atomic_type->value > $assertion_value) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
} /*elseif ($inside_loop) {
|
||||
//when inside a loop, allow the range to extends the type
|
||||
@ -1533,11 +1531,10 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
||||
}
|
||||
}*/
|
||||
} elseif ($atomic_type instanceof Atomic\TPositiveInt) {
|
||||
if ($assertion_value > 0) {
|
||||
//emit an issue here in the future about incompatible type
|
||||
}
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
$existing_var_type->addType(new Atomic\TIntRange(null, $assertion_value));
|
||||
if ($assertion_value >= 1) {
|
||||
$existing_var_type->addType(new Atomic\TIntRange(1, $assertion_value));
|
||||
}
|
||||
} elseif ($atomic_type instanceof TInt) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
$existing_var_type->addType(new Atomic\TIntRange(null, $assertion_value));
|
||||
@ -1564,11 +1561,9 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
||||
}
|
||||
$existing_var_type->addType($atomic_type);
|
||||
} elseif ($atomic_type instanceof Atomic\TLiteralInt) {
|
||||
$new_range = new Atomic\TIntRange($assertion_value, null);
|
||||
if (!$new_range->contains($atomic_type->value)) {
|
||||
//emit an issue here in the future about incompatible type
|
||||
if ($atomic_type->value < $assertion_value) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
}/* elseif ($inside_loop) {
|
||||
} /* elseif ($inside_loop) {
|
||||
//when inside a loop, allow the range to extends the type
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
if ($atomic_type->value < $assertion_value) {
|
||||
@ -1578,11 +1573,10 @@ class SimpleNegatedAssertionReconciler extends Reconciler
|
||||
}
|
||||
}*/
|
||||
} elseif ($atomic_type instanceof Atomic\TPositiveInt) {
|
||||
if ($assertion_value > 0) {
|
||||
//emit an issue here in the future about incompatible type
|
||||
if ($assertion_value > 1) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
$existing_var_type->addType(new Atomic\TIntRange($assertion_value, null));
|
||||
}
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
$existing_var_type->addType(new Atomic\TIntRange($assertion_value, 1));
|
||||
} elseif ($atomic_type instanceof TInt) {
|
||||
$existing_var_type->removeType($atomic_type->getKey());
|
||||
$existing_var_type->addType(new Atomic\TIntRange($assertion_value, null));
|
||||
|
@ -106,6 +106,10 @@ class TIntRange extends TInt
|
||||
*/
|
||||
public static function convertToIntRange(TInt $int_atomic): TIntRange
|
||||
{
|
||||
if ($int_atomic instanceof TIntRange) {
|
||||
return $int_atomic;
|
||||
}
|
||||
|
||||
if ($int_atomic instanceof TPositiveInt) {
|
||||
return new TIntRange(1, null);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ use Psalm\Storage\FileStorage;
|
||||
use Psalm\Type;
|
||||
use Psalm\Type\Atomic\TFloat;
|
||||
use Psalm\Type\Atomic\TInt;
|
||||
use Psalm\Type\Atomic\TIntRange;
|
||||
use Psalm\Type\Atomic\TLiteralFloat;
|
||||
use Psalm\Type\Atomic\TLiteralInt;
|
||||
use Psalm\Type\Atomic\TLiteralString;
|
||||
@ -280,8 +281,12 @@ class Union implements TypeNode
|
||||
}
|
||||
}
|
||||
} elseif ($type instanceof TInt && $this->literal_int_types) {
|
||||
foreach ($this->literal_int_types as $key => $_) {
|
||||
unset($this->literal_int_types[$key], $this->types[$key]);
|
||||
//we remove any literal that is already included in a wider type
|
||||
$int_type_in_range = TIntRange::convertToIntRange($type);
|
||||
foreach ($this->literal_int_types as $key => $literal_int_type) {
|
||||
if ($int_type_in_range->contains($literal_int_type->value)) {
|
||||
unset($this->literal_int_types[$key], $this->types[$key]);
|
||||
}
|
||||
}
|
||||
} elseif ($type instanceof TFloat && $this->literal_float_types) {
|
||||
foreach ($this->literal_float_types as $key => $_) {
|
||||
|
@ -644,6 +644,30 @@ class IntRangeTest extends TestCase
|
||||
}
|
||||
}',
|
||||
],
|
||||
'positiveIntToRangeWithInferior' => [
|
||||
'<?php
|
||||
/** @var positive-int $length */
|
||||
$length = 0;
|
||||
|
||||
if ($length < 8) {
|
||||
throw new \RuntimeException();
|
||||
}',
|
||||
'assertions' => [
|
||||
'$length===' => 'int<8, max>',
|
||||
],
|
||||
],
|
||||
'positiveIntToRangeWithSuperiorOrEqual' => [
|
||||
'<?php
|
||||
/** @var positive-int $length */
|
||||
$length = 0;
|
||||
|
||||
if ($length >= 8) {
|
||||
throw new \RuntimeException();
|
||||
}',
|
||||
'assertions' => [
|
||||
'$length===' => 'int<1, 7>',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user