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

Fix #4081 - better inference of positive ints

This commit is contained in:
Brown 2020-08-28 16:38:50 -04:00
parent d29620a42b
commit df0d426f61
4 changed files with 43 additions and 8 deletions

View File

@ -568,11 +568,29 @@ class NonDivArithmeticOpAnalyzer
}
if ($left_type_part instanceof TInt && $right_type_part instanceof TInt) {
$always_positive = !$parent instanceof PhpParser\Node\Expr\BinaryOp\Minus
&& ($left_type_part instanceof TPositiveInt
|| ($left_type_part instanceof TLiteralInt && $left_type_part->value > 0))
&& ($right_type_part instanceof TPositiveInt
|| ($right_type_part instanceof TLiteralInt && $right_type_part->value > 0));
$left_is_positive = $left_type_part instanceof TPositiveInt
|| ($left_type_part instanceof TLiteralInt && $left_type_part->value > 0);
$right_is_positive = $right_type_part instanceof TPositiveInt
|| ($right_type_part instanceof TLiteralInt && $right_type_part->value > 0);
if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Minus) {
$always_positive = false;
} elseif ($left_is_positive && $right_is_positive) {
$always_positive = true;
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Plus
&& ($left_type_part instanceof TLiteralInt && $left_type_part->value === 0)
&& $right_is_positive
) {
$always_positive = true;
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Plus
&& ($right_type_part instanceof TLiteralInt && $right_type_part->value === 0)
&& $left_is_positive
) {
$always_positive = true;
} else {
$always_positive = false;
}
if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mod) {
$result_type = $always_positive ? Type::getPositiveInt() : Type::getInt();

View File

@ -992,8 +992,10 @@ class AssertionReconciler extends \Psalm\Type\Reconciler
$can_be_equal = false;
$did_remove_type = false;
foreach ($existing_var_atomic_types as $atomic_key => $_) {
if ($atomic_key !== $assertion) {
foreach ($existing_var_atomic_types as $atomic_key => $atomic_type) {
if ($atomic_key !== $assertion
&& !($atomic_type instanceof Type\Atomic\TPositiveInt && $value > 0)
) {
$existing_var_type->removeType($atomic_key);
$did_remove_type = true;
} else {

View File

@ -184,7 +184,7 @@ abstract class Type
*/
public static function getPositiveInt(bool $from_calculation = false)
{
$union = new Union([new TInt()]);
$union = new Union([new Type\Atomic\TPositiveInt()]);
$union->from_calculation = $from_calculation;
return $union;

View File

@ -284,6 +284,21 @@ class BinaryOperationTest extends TestCase
return $opts + ["host" => 5];
}'
],
'addIntToZero' => [
'<?php
$tick = 0;
test($tick + 1);
$tick++;
test($tick);
/**
* @psalm-param positive-int $tickedTimes
*/
function test(int $tickedTimes): void {}'
],
];
}