Skip to content

Commit b482a5b

Browse files
authored
Subtract zero-float when comparing against zero-int
1 parent a7188ef commit b482a5b

File tree

6 files changed

+100
-7
lines changed

6 files changed

+100
-7
lines changed

src/Type/Traits/ConstantNumericComparisonTypeTrait.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Type\Traits;
44

55
use PHPStan\Type\Constant\ConstantBooleanType;
6+
use PHPStan\Type\Constant\ConstantFloatType;
67
use PHPStan\Type\IntegerRangeType;
78
use PHPStan\Type\MixedType;
89
use PHPStan\Type\NullType;
@@ -22,6 +23,7 @@ public function getSmallerType(): Type
2223
if (!(bool) $this->value) {
2324
$subtractedTypes[] = new NullType();
2425
$subtractedTypes[] = new ConstantBooleanType(false);
26+
$subtractedTypes[] = new ConstantFloatType(0.0); // subtract range when we support float-ranges
2527
}
2628

2729
return TypeCombinator::remove(new MixedType(), TypeCombinator::union(...$subtractedTypes));
@@ -31,6 +33,7 @@ public function getSmallerOrEqualType(): Type
3133
{
3234
$subtractedTypes = [
3335
IntegerRangeType::createAllGreaterThan($this->value),
36+
// subtract range when we support float-ranges
3437
];
3538

3639
if (!(bool) $this->value) {
@@ -45,6 +48,7 @@ public function getGreaterType(): Type
4548
$subtractedTypes = [
4649
new NullType(),
4750
new ConstantBooleanType(false),
51+
new ConstantFloatType(0.0), // subtract range when we support float-ranges
4852
IntegerRangeType::createAllSmallerThanOrEqualTo($this->value),
4953
];
5054

@@ -64,6 +68,7 @@ public function getGreaterOrEqualType(): Type
6468
if ((bool) $this->value) {
6569
$subtractedTypes[] = new NullType();
6670
$subtractedTypes[] = new ConstantBooleanType(false);
71+
$subtractedTypes[] = new ConstantFloatType(0.0); // subtract range when we support float-ranges
6772
}
6873

6974
return TypeCombinator::remove(new MixedType(), TypeCombinator::union(...$subtractedTypes));

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,7 @@ public function dataFileAsserts(): iterable
14891489
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10468.php');
14901490
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6613.php');
14911491
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10187.php');
1492+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-5309.php');
14921493
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10834.php');
14931494
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-11035.php');
14941495
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-10952.php');

tests/PHPStan/Analyser/TypeSpecifierTest.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ public function dataCondition(): iterable
822822
'$n' => 'mixed~int<3, max>|true',
823823
],
824824
[
825-
'$n' => 'mixed~int<min, 2>|false|null',
825+
'$n' => 'mixed~0.0|int<min, 2>|false|null',
826826
],
827827
],
828828
[
@@ -834,7 +834,7 @@ public function dataCondition(): iterable
834834
'$n' => 'mixed~int<' . PHP_INT_MIN . ', max>|true',
835835
],
836836
[
837-
'$n' => 'mixed~false|null',
837+
'$n' => 'mixed~0.0|false|null',
838838
],
839839
],
840840
[
@@ -843,7 +843,7 @@ public function dataCondition(): iterable
843843
new LNumber(PHP_INT_MAX),
844844
),
845845
[
846-
'$n' => 'mixed~bool|int<min, ' . PHP_INT_MAX . '>|null',
846+
'$n' => 'mixed~0.0|bool|int<min, ' . PHP_INT_MAX . '>|null',
847847
],
848848
[
849849
'$n' => 'mixed',
@@ -858,7 +858,7 @@ public function dataCondition(): iterable
858858
'$n' => 'mixed~int<' . (PHP_INT_MIN + 1) . ', max>',
859859
],
860860
[
861-
'$n' => 'mixed~bool|int<min, ' . PHP_INT_MIN . '>|null',
861+
'$n' => 'mixed~0.0|bool|int<min, ' . PHP_INT_MIN . '>|null',
862862
],
863863
],
864864
[
@@ -867,7 +867,7 @@ public function dataCondition(): iterable
867867
new LNumber(PHP_INT_MAX),
868868
),
869869
[
870-
'$n' => 'mixed~int<min, ' . (PHP_INT_MAX - 1) . '>|false|null',
870+
'$n' => 'mixed~0.0|int<min, ' . (PHP_INT_MAX - 1) . '>|false|null',
871871
],
872872
[
873873
'$n' => 'mixed~int<' . PHP_INT_MAX . ', max>|true',
@@ -885,7 +885,7 @@ public function dataCondition(): iterable
885885
),
886886
),
887887
[
888-
'$n' => 'mixed~int<min, 2>|int<6, max>|false|null',
888+
'$n' => 'mixed~0.0|int<min, 2>|int<6, max>|false|null',
889889
],
890890
[
891891
'$n' => 'mixed~int<3, 5>|true',
@@ -1250,7 +1250,7 @@ public function dataCondition(): iterable
12501250
),
12511251
[
12521252
'$foo' => 'non-empty-array',
1253-
'count($foo)' => 'mixed~int<min, 1>|false|null',
1253+
'count($foo)' => 'mixed~0.0|int<min, 1>|false|null',
12541254
],
12551255
[],
12561256
],
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace Bug5309;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
function greater(float $y): float {
8+
$x = 0.0;
9+
if($y > 0) {
10+
$x += 1;
11+
}
12+
assertType('0.0|1.0', $x);
13+
if($x > 0) {
14+
assertType('1.0', $x);
15+
return 5 / $x;
16+
}
17+
assertType('0.0|1.0', $x); // could be '0.0' when we support float-ranges
18+
19+
return 1.0;
20+
}
21+
22+
function greaterEqual(float $y): float {
23+
$x = 0.0;
24+
if($y > 0) {
25+
$x += 1;
26+
}
27+
assertType('0.0|1.0', $x);
28+
if($x >= 0) {
29+
assertType('0.0|1.0', $x);
30+
return 5 / $x;
31+
}
32+
assertType('0.0|1.0', $x); // could be '*NEVER*' when we support float-ranges
33+
34+
return 1.0;
35+
}
36+
37+
function smaller(float $y): float {
38+
$x = 0.0;
39+
if($y > 0) {
40+
$x -= 1;
41+
}
42+
assertType('-1.0|0.0', $x);
43+
if($x < 0) {
44+
assertType('-1.0', $x);
45+
return 5 / $x;
46+
}
47+
assertType('-1.0|0.0', $x); // could be '0.0' when we support float-ranges
48+
49+
return 1.0;
50+
}
51+
52+
function smallerEqual(float $y): float {
53+
$x = 0.0;
54+
if($y > 0) {
55+
$x -= 1;
56+
}
57+
assertType('-1.0|0.0', $x);
58+
if($x <= 0) {
59+
assertType('-1.0|0.0', $x);
60+
return 5 / $x;
61+
}
62+
assertType('*NEVER*', $x);
63+
64+
return 1.0;
65+
}

tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,4 +278,9 @@ public function testRuleWithNullsafeVariant(): void
278278
]);
279279
}
280280

281+
public function testBug5309(): void
282+
{
283+
$this->analyse([__DIR__ . '/data/bug-5309.php'], []);
284+
}
285+
281286
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Bug5309;
4+
5+
function sayHello(float $y): float
6+
{
7+
$x = 0.0;
8+
if ($y > 0) {
9+
$x += 1;
10+
}
11+
if ($x > 0) {
12+
return 5 / $x;
13+
}
14+
15+
return 1.0;
16+
}
17+

0 commit comments

Comments
 (0)