Skip to content

Commit 09e30b4

Browse files
VincentLangletondrejmirtes
authored andcommitted
Nothing is lower than Null
1 parent 0c32152 commit 09e30b4

File tree

7 files changed

+96
-5
lines changed

7 files changed

+96
-5
lines changed

src/Type/NullType.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryL
110110
return $otherType->isGreaterThan($this, $phpVersion);
111111
}
112112

113+
if ($otherType->isObject()->yes()) {
114+
return TrinaryLogic::createYes();
115+
}
116+
113117
return TrinaryLogic::createMaybe();
114118
}
115119

@@ -123,6 +127,10 @@ public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): T
123127
return $otherType->isGreaterThanOrEqual($this, $phpVersion);
124128
}
125129

130+
if ($otherType->isObject()->yes()) {
131+
return TrinaryLogic::createYes();
132+
}
133+
126134
return TrinaryLogic::createMaybe();
127135
}
128136

src/Type/Traits/UndecidedComparisonCompoundTypeTrait.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,19 @@ trait UndecidedComparisonCompoundTypeTrait
1313

1414
public function isGreaterThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic
1515
{
16+
if ($otherType->isNull()->yes() && $this->isObject()->yes()) {
17+
return TrinaryLogic::createYes();
18+
}
19+
1620
return TrinaryLogic::createMaybe();
1721
}
1822

1923
public function isGreaterThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic
2024
{
25+
if ($otherType->isNull()->yes()) {
26+
return TrinaryLogic::createYes();
27+
}
28+
2129
return TrinaryLogic::createMaybe();
2230
}
2331

src/Type/Traits/UndecidedComparisonTypeTrait.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,27 @@
55
use PHPStan\Php\PhpVersion;
66
use PHPStan\TrinaryLogic;
77
use PHPStan\Type\MixedType;
8+
use PHPStan\Type\NullType;
89
use PHPStan\Type\Type;
910

1011
trait UndecidedComparisonTypeTrait
1112
{
1213

1314
public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic
1415
{
16+
if ($otherType->isNull()->yes()) {
17+
return TrinaryLogic::createNo();
18+
}
19+
1520
return TrinaryLogic::createMaybe();
1621
}
1722

1823
public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic
1924
{
25+
if ($otherType->isNull()->yes() && $this->isObject()->yes()) {
26+
return TrinaryLogic::createNo();
27+
}
28+
2029
return TrinaryLogic::createMaybe();
2130
}
2231

@@ -32,11 +41,15 @@ public function getSmallerOrEqualType(PhpVersion $phpVersion): Type
3241

3342
public function getGreaterType(PhpVersion $phpVersion): Type
3443
{
35-
return new MixedType();
44+
return new MixedType(subtractedType: new NullType());
3645
}
3746

3847
public function getGreaterOrEqualType(PhpVersion $phpVersion): Type
3948
{
49+
if ($this->isObject()->yes()) {
50+
return new MixedType(subtractedType: new NullType());
51+
}
52+
4053
return new MixedType();
4154
}
4255

tests/PHPStan/Analyser/nsrt/bcmath-number.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,10 @@ public function bcVsNull(Number $a): void
190190
assertType('*ERROR*', $a ** $b);
191191
assertType('*ERROR*', $a << $b);
192192
assertType('*ERROR*', $a >> $b);
193-
assertType('bool', $a < $b);
194-
assertType('bool', $a <= $b);
195-
assertType('bool', $a > $b);
196-
assertType('bool', $a >= $b);
193+
assertType('false', $a < $b);
194+
assertType('false', $a <= $b);
195+
assertType('true', $a > $b);
196+
assertType('true', $a >= $b);
197197
assertType('int<-1, 1>', $a <=> $b);
198198
assertType('bool', $a == $b);
199199
assertType('bool', $a != $b);

tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3588,6 +3588,26 @@ public function testBug13171(): void
35883588
]);
35893589
}
35903590

3591+
public function testBug10719(): void
3592+
{
3593+
$this->checkThisOnly = false;
3594+
$this->checkNullables = true;
3595+
$this->checkUnionTypes = true;
3596+
$this->checkExplicitMixed = true;
3597+
3598+
$this->analyse([__DIR__ . '/data/bug-10719.php'], []);
3599+
}
3600+
3601+
public function testBug9141(): void
3602+
{
3603+
$this->checkThisOnly = false;
3604+
$this->checkNullables = true;
3605+
$this->checkUnionTypes = true;
3606+
$this->checkExplicitMixed = true;
3607+
3608+
$this->analyse([__DIR__ . '/data/bug-9141.php'], []);
3609+
}
3610+
35913611
public function testBug3396(): void
35923612
{
35933613
$this->checkThisOnly = false;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug10719;
4+
5+
use DateTime;
6+
7+
$dt1 = null;
8+
$dt2 = new DateTime();
9+
10+
if (rand(0, 1)) {
11+
$dt1 = (clone $dt2)->setTimestamp($dt2->getTimestamp() + 1000);
12+
}
13+
14+
if ($dt1 > $dt2) {
15+
echo $dt1->getTimestamp();
16+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug9141;
4+
5+
use DateTimeImmutable;
6+
7+
class HelloWorld
8+
{
9+
10+
private ?DateTimeImmutable $startTime;
11+
12+
public function __construct() {
13+
$this->startTime = new DateTimeImmutable();
14+
}
15+
16+
public function getStartTime(): ?DateTimeImmutable
17+
{
18+
return $this->startTime;
19+
}
20+
21+
}
22+
23+
$helloWorld = new HelloWorld();
24+
if ($helloWorld->getStartTime() > new DateTimeImmutable()) {
25+
echo sprintf('%s', $helloWorld->getStartTime()->format('d.m.y.'));
26+
}

0 commit comments

Comments
 (0)