Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6b0d8c3

Browse files
schlndhondrejmirtes
andauthored
Handle BcMath\Number operators for simple cases
Co-authored-by: Ondrej Mirtes <ondrej@mirtes.cz>
1 parent 2be8600 commit 6b0d8c3

File tree

6 files changed

+494
-6
lines changed

6 files changed

+494
-6
lines changed

‎conf/config.neon‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,10 @@ services:
10531053
arguments:
10541054
reportMagicProperties: %reportMagicProperties%
10551055
checkDynamicProperties: %checkDynamicProperties%
1056+
-
1057+
class: PHPStan\Type\Php\BcMathNumberOperatorTypeSpecifyingExtension
1058+
tags:
1059+
- phpstan.broker.operatorTypeSpecifyingExtension
10561060

10571061
-
10581062
class: PHPStan\Rules\Properties\UninitializedPropertyRule

‎src/Php/PhpVersion.php‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,4 +400,9 @@ public function substrReturnFalseInsteadOfEmptyString(): bool
400400
return $this->versionId < 80000;
401401
}
402402

403+
public function supportsBcMathNumberOperatorOverloading(): bool
404+
{
405+
return $this->versionId >= 80400;
406+
}
407+
403408
}

‎src/Reflection/InitializerExprTypeResolver.php‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,11 @@ public function getModType(Expr $left, Expr $right, callable $getTypeCallback):
872872
return $this->getNeverType($leftType, $rightType);
873873
}
874874

875+
$extensionSpecified = $this->callOperatorTypeSpecifyingExtensions(new BinaryOp\Mod($left, $right), $leftType, $rightType);
876+
if ($extensionSpecified !== null) {
877+
return $extensionSpecified;
878+
}
879+
875880
if ($leftType->toNumber() instanceof ErrorType || $rightType->toNumber() instanceof ErrorType) {
876881
return new ErrorType();
877882
}
@@ -1234,16 +1239,16 @@ public function getPowType(Expr $left, Expr $right, callable $getTypeCallback):
12341239
$leftType = $getTypeCallback($left);
12351240
$rightType = $getTypeCallback($right);
12361241

1237-
$exponentiatedTyped = $leftType->exponentiate($rightType);
1238-
if (!$exponentiatedTyped instanceof ErrorType) {
1239-
return $exponentiatedTyped;
1240-
}
1241-
12421242
$extensionSpecified = $this->callOperatorTypeSpecifyingExtensions(new BinaryOp\Pow($left, $right), $leftType, $rightType);
12431243
if ($extensionSpecified !== null) {
12441244
return $extensionSpecified;
12451245
}
12461246

1247+
$exponentiatedTyped = $leftType->exponentiate($rightType);
1248+
if (!$exponentiatedTyped instanceof ErrorType) {
1249+
return $exponentiatedTyped;
1250+
}
1251+
12471252
return new ErrorType();
12481253
}
12491254

‎src/Type/ObjectType.php‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection;
3232
use PHPStan\ShouldNotHappenException;
3333
use PHPStan\TrinaryLogic;
34+
use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
35+
use PHPStan\Type\Accessory\AccessoryNumericStringType;
3436
use PHPStan\Type\Constant\ConstantArrayType;
3537
use PHPStan\Type\Constant\ConstantBooleanType;
3638
use PHPStan\Type\Constant\ConstantStringType;
@@ -593,6 +595,14 @@ public function toFloat(): Type
593595

594596
public function toString(): Type
595597
{
598+
if ($this->isInstanceOf('BcMath\Number')->yes()) {
599+
return new IntersectionType([
600+
new StringType(),
601+
new AccessoryNumericStringType(),
602+
new AccessoryNonEmptyStringType(),
603+
]);
604+
}
605+
596606
$classReflection = $this->getClassReflection();
597607
if ($classReflection === null) {
598608
return new ErrorType();
@@ -678,7 +688,10 @@ public function toCoercedArgumentType(bool $strictTypes): Type
678688

679689
public function toBoolean(): BooleanType
680690
{
681-
if ($this->isInstanceOf('SimpleXMLElement')->yes()) {
691+
if (
692+
$this->isInstanceOf('SimpleXMLElement')->yes()
693+
|| $this->isInstanceOf('BcMath\Number')->yes()
694+
) {
682695
return new BooleanType();
683696
}
684697

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Php;
4+
5+
use PHPStan\Php\PhpVersion;
6+
use PHPStan\Type\ErrorType;
7+
use PHPStan\Type\NeverType;
8+
use PHPStan\Type\ObjectType;
9+
use PHPStan\Type\OperatorTypeSpecifyingExtension;
10+
use PHPStan\Type\Type;
11+
use function in_array;
12+
13+
final class BcMathNumberOperatorTypeSpecifyingExtension implements OperatorTypeSpecifyingExtension
14+
{
15+
16+
public function __construct(private PhpVersion $phpVersion)
17+
{
18+
}
19+
20+
public function isOperatorSupported(string $operatorSigil, Type $leftSide, Type $rightSide): bool
21+
{
22+
if (!$this->phpVersion->supportsBcMathNumberOperatorOverloading() || $leftSide instanceof NeverType || $rightSide instanceof NeverType) {
23+
return false;
24+
}
25+
26+
$bcMathNumberType = new ObjectType('BcMath\Number');
27+
28+
return in_array($operatorSigil, ['-', '+', '*', '/', '**', '%'], true)
29+
&& (
30+
$bcMathNumberType->isSuperTypeOf($leftSide)->yes()
31+
|| $bcMathNumberType->isSuperTypeOf($rightSide)->yes()
32+
);
33+
}
34+
35+
public function specifyType(string $operatorSigil, Type $leftSide, Type $rightSide): Type
36+
{
37+
$bcMathNumberType = new ObjectType('BcMath\Number');
38+
$otherSide = $bcMathNumberType->isSuperTypeOf($leftSide)->yes()
39+
? $rightSide
40+
: $leftSide;
41+
42+
if (
43+
$otherSide->isInteger()->yes()
44+
|| $otherSide->isNumericString()->yes()
45+
|| $bcMathNumberType->isSuperTypeOf($otherSide)->yes()
46+
) {
47+
return $bcMathNumberType;
48+
}
49+
50+
return new ErrorType();
51+
}
52+
53+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /