Skip to content

Commit 48a38a3

Browse files
committed
Fix BcMath\Number unary plus/minus/bitwise-not
1 parent 40b3f24 commit 48a38a3

File tree

5 files changed

+62
-3
lines changed

5 files changed

+62
-3
lines changed

src/Reflection/InitializerExprTypeResolver.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,10 @@ public function getBitwiseAndTypeFromTypes(Type $leftType, Type $rightType): Typ
993993
return $this->getNeverType($leftType, $rightType);
994994
}
995995

996+
if ((new ObjectType('BcMath\Number'))->isSuperTypeOf($leftType)->yes()) {
997+
return new ErrorType();
998+
}
999+
9961000
$result = $this->getFiniteOrConstantScalarTypes($leftType, $rightType, static fn ($a, $b) => $a & $b);
9971001
if ($result instanceof Type) {
9981002
return $result;
@@ -1051,6 +1055,10 @@ public function getBitwiseOrTypeFromTypes(Type $leftType, Type $rightType): Type
10511055
return $this->getNeverType($leftType, $rightType);
10521056
}
10531057

1058+
if ((new ObjectType('BcMath\Number'))->isSuperTypeOf($leftType)->yes()) {
1059+
return new ErrorType();
1060+
}
1061+
10541062
$result = $this->getFiniteOrConstantScalarTypes($leftType, $rightType, static fn ($a, $b) => $a | $b);
10551063
if ($result instanceof Type) {
10561064
return $result;
@@ -1159,6 +1167,10 @@ public function getBitwiseXorTypeFromTypes(Type $leftType, Type $rightType): Typ
11591167
return $this->getNeverType($leftType, $rightType);
11601168
}
11611169

1170+
if ((new ObjectType('BcMath\Number'))->isSuperTypeOf($leftType)->yes()) {
1171+
return new ErrorType();
1172+
}
1173+
11621174
$result = $this->getFiniteOrConstantScalarTypes($leftType, $rightType, static fn ($a, $b) => $a ^ $b);
11631175
if ($result instanceof Type) {
11641176
return $result;
@@ -1765,6 +1777,10 @@ public function getShiftLeftTypeFromTypes(Expr $left, Expr $right, Type $leftTyp
17651777
return $this->getNeverType($leftType, $rightType);
17661778
}
17671779

1780+
if ((new ObjectType('BcMath\Number'))->isSuperTypeOf($leftType)->yes()) {
1781+
return new ErrorType();
1782+
}
1783+
17681784
$leftTypes = $leftType->getConstantScalarTypes();
17691785
$rightTypes = $rightType->getConstantScalarTypes();
17701786
$leftTypesCount = count($leftTypes);
@@ -1829,6 +1845,10 @@ public function getShiftRightTypeFromTypes(Expr $left, Expr $right, Type $leftTy
18291845
return $this->getNeverType($leftType, $rightType);
18301846
}
18311847

1848+
if ((new ObjectType('BcMath\Number'))->isSuperTypeOf($leftType)->yes()) {
1849+
return new ErrorType();
1850+
}
1851+
18321852
$leftTypes = $leftType->getConstantScalarTypes();
18331853
$rightTypes = $rightType->getConstantScalarTypes();
18341854
$leftTypesCount = count($leftTypes);

src/Type/ObjectType.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,10 @@ public function toNumber(): Type
762762
]);
763763
}
764764

765+
if ($this->isInstanceOf('BcMath\Number')->yes()) {
766+
return new ObjectType('BcMath\Number');
767+
}
768+
765769
return new ErrorType();
766770
}
767771

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,9 @@ public function bcVsNever(Number $a): void
380380
{
381381
for ($b = 1; $b < count([]); $b++) {
382382
assertType('*NEVER*', $a + $b);
383-
assertType('*ERROR*', $a - $b); // Inconsistency: getPlusType handles never types right at the beginning, getMinusType doesn't.
384-
assertType('*ERROR*', $a * $b);
385-
assertType('*ERROR*', $a / $b);
383+
assertType('*NEVER*', $a - $b);
384+
assertType('*NEVER*', $a * $b);
385+
assertType('*NEVER*', $a / $b);
386386
assertType('*NEVER*', $a % $b);
387387
assertType('non-empty-string&numeric-string', $a . $b);
388388
assertType('*ERROR*', $a ** $b);
@@ -413,4 +413,11 @@ public function bcIncDec(Number $a): void
413413
assertType('BcMath\Number', --$a);
414414
assertType('BcMath\Number', $a--);
415415
}
416+
417+
public function bcUnaryOp(Number $a): void
418+
{
419+
assertType('BcMath\Number', +$a);
420+
assertType('BcMath\Number', -$a);
421+
assertType('*ERROR*', ~$a);
422+
}
416423
}

tests/PHPStan/Rules/Operators/InvalidUnaryOperationRuleTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,15 @@ public function testUnion(): void
169169
]);
170170
}
171171

172+
#[RequiresPhp('>= 8.4')]
173+
public function testBcMathNumber(): void
174+
{
175+
$this->analyse([__DIR__ . '/data/unary-bcmath-number.php'], [
176+
[
177+
'Unary operation "~" on BcMath\Number results in an error.',
178+
16,
179+
],
180+
]);
181+
}
182+
172183
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace BcMathNumberUnaryOperators;
4+
5+
use BcMath\Number;
6+
7+
function testUnaryPlus(Number $x): void {
8+
+$x;
9+
}
10+
11+
function testUnaryMinus(Number $x): void {
12+
-$x;
13+
}
14+
15+
function testBitwiseNot(Number $x): void {
16+
~$x;
17+
}

0 commit comments

Comments
 (0)