Skip to content

Commit de1242e

Browse files
committed
Merge branch 2.1.x into 2.2.x
2 parents 7310fc9 + e2637c3 commit de1242e

File tree

6 files changed

+185
-6
lines changed

6 files changed

+185
-6
lines changed

src/Reflection/InitializerExprTypeResolver.php

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,12 @@ public function getBitwiseAndType(Expr $left, Expr $right, callable $getTypeCall
986986
$leftType = $getTypeCallback($left);
987987
$rightType = $getTypeCallback($right);
988988

989+
$specifiedTypes = $this->operatorTypeSpecifyingExtensionRegistryProvider->getRegistry()
990+
->callOperatorTypeSpecifyingExtensions(new BinaryOp\BitwiseAnd($left, $right), $leftType, $rightType);
991+
if ($specifiedTypes !== null) {
992+
return $specifiedTypes;
993+
}
994+
989995
return $this->getBitwiseAndTypeFromTypes($leftType, $rightType);
990996
}
991997

@@ -1044,6 +1050,12 @@ public function getBitwiseOrType(Expr $left, Expr $right, callable $getTypeCallb
10441050
$leftType = $getTypeCallback($left);
10451051
$rightType = $getTypeCallback($right);
10461052

1053+
$specifiedTypes = $this->operatorTypeSpecifyingExtensionRegistryProvider->getRegistry()
1054+
->callOperatorTypeSpecifyingExtensions(new BinaryOp\BitwiseOr($left, $right), $leftType, $rightType);
1055+
if ($specifiedTypes !== null) {
1056+
return $specifiedTypes;
1057+
}
1058+
10471059
return $this->getBitwiseOrTypeFromTypes($leftType, $rightType);
10481060
}
10491061

@@ -1092,6 +1104,12 @@ public function getBitwiseXorType(Expr $left, Expr $right, callable $getTypeCall
10921104
$leftType = $getTypeCallback($left);
10931105
$rightType = $getTypeCallback($right);
10941106

1107+
$specifiedTypes = $this->operatorTypeSpecifyingExtensionRegistryProvider->getRegistry()
1108+
->callOperatorTypeSpecifyingExtensions(new BinaryOp\BitwiseXor($left, $right), $leftType, $rightType);
1109+
if ($specifiedTypes !== null) {
1110+
return $specifiedTypes;
1111+
}
1112+
10951113
return $this->getBitwiseXorTypeFromTypes($leftType, $rightType);
10961114
}
10971115

@@ -1756,6 +1774,12 @@ public function getShiftLeftType(Expr $left, Expr $right, callable $getTypeCallb
17561774
$leftType = $getTypeCallback($left);
17571775
$rightType = $getTypeCallback($right);
17581776

1777+
$specifiedTypes = $this->operatorTypeSpecifyingExtensionRegistryProvider->getRegistry()
1778+
->callOperatorTypeSpecifyingExtensions(new BinaryOp\ShiftLeft($left, $right), $leftType, $rightType);
1779+
if ($specifiedTypes !== null) {
1780+
return $specifiedTypes;
1781+
}
1782+
17591783
return $this->getShiftLeftTypeFromTypes($left, $right, $leftType, $rightType);
17601784
}
17611785

@@ -1820,6 +1844,12 @@ public function getShiftRightType(Expr $left, Expr $right, callable $getTypeCall
18201844
$leftType = $getTypeCallback($left);
18211845
$rightType = $getTypeCallback($right);
18221846

1847+
$specifiedTypes = $this->operatorTypeSpecifyingExtensionRegistryProvider->getRegistry()
1848+
->callOperatorTypeSpecifyingExtensions(new BinaryOp\ShiftRight($left, $right), $leftType, $rightType);
1849+
if ($specifiedTypes !== null) {
1850+
return $specifiedTypes;
1851+
}
1852+
18231853
return $this->getShiftRightTypeFromTypes($left, $right, $leftType, $rightType);
18241854
}
18251855

@@ -2034,6 +2064,12 @@ private function resolveConstantArrayTypeComparison(ConstantArrayType $leftType,
20342064
*/
20352065
private function resolveCommonMath(Expr\BinaryOp $expr, Type $leftType, Type $rightType): Type
20362066
{
2067+
$specifiedTypes = $this->operatorTypeSpecifyingExtensionRegistryProvider->getRegistry()
2068+
->callOperatorTypeSpecifyingExtensions($expr, $leftType, $rightType);
2069+
if ($specifiedTypes !== null) {
2070+
return $specifiedTypes;
2071+
}
2072+
20372073
$types = TypeCombinator::union($leftType, $rightType);
20382074
$leftNumberType = $leftType->toNumber();
20392075
$rightNumberType = $rightType->toNumber();
@@ -2073,12 +2109,6 @@ private function resolveCommonMath(Expr\BinaryOp $expr, Type $leftType, Type $ri
20732109
}
20742110
}
20752111

2076-
$specifiedTypes = $this->operatorTypeSpecifyingExtensionRegistryProvider->getRegistry()
2077-
->callOperatorTypeSpecifyingExtensions($expr, $leftType, $rightType);
2078-
if ($specifiedTypes !== null) {
2079-
return $specifiedTypes;
2080-
}
2081-
20822112
if (
20832113
$leftType->isArray()->yes()
20842114
|| $rightType->isArray()->yes()
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser;
4+
5+
use PHPStan\Testing\TypeInferenceTestCase;
6+
use PHPUnit\Framework\Attributes\DataProvider;
7+
8+
class OperatorTypeSpecifyingExtensionTypeInferenceTest extends TypeInferenceTestCase
9+
{
10+
11+
public static function dataAsserts(): iterable
12+
{
13+
yield from self::gatherAssertTypes(__DIR__ . '/data/operator-type-specifying-extension.php');
14+
}
15+
16+
/**
17+
* @param mixed ...$args
18+
*/
19+
#[DataProvider('dataAsserts')]
20+
public function testAsserts(
21+
string $assertType,
22+
string $file,
23+
...$args,
24+
): void
25+
{
26+
$this->assertFileAsserts($assertType, $file, ...$args);
27+
}
28+
29+
public static function getAdditionalConfigFiles(): array
30+
{
31+
return [
32+
__DIR__ . '/operator-type-specifying-extension.neon',
33+
];
34+
}
35+
36+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace OperatorExtensionTest;
4+
5+
use PHPStan\Fixture\TestBitwiseOperand;
6+
use PHPStan\Fixture\TestDecimal;
7+
use function PHPStan\Testing\assertType;
8+
9+
// =============================================================================
10+
// Bitwise operator extension tests
11+
// =============================================================================
12+
13+
function testBitwiseAnd(TestBitwiseOperand $a, TestBitwiseOperand $b): void
14+
{
15+
assertType('PHPStan\Fixture\TestBitwiseOperand', $a & $b);
16+
}
17+
18+
function testBitwiseOr(TestBitwiseOperand $a, TestBitwiseOperand $b): void
19+
{
20+
assertType('PHPStan\Fixture\TestBitwiseOperand', $a | $b);
21+
}
22+
23+
function testBitwiseXor(TestBitwiseOperand $a, TestBitwiseOperand $b): void
24+
{
25+
assertType('PHPStan\Fixture\TestBitwiseOperand', $a ^ $b);
26+
}
27+
28+
function testShiftLeft(TestBitwiseOperand $a, TestBitwiseOperand $b): void
29+
{
30+
assertType('PHPStan\Fixture\TestBitwiseOperand', $a << $b);
31+
}
32+
33+
function testShiftRight(TestBitwiseOperand $a, TestBitwiseOperand $b): void
34+
{
35+
assertType('PHPStan\Fixture\TestBitwiseOperand', $a >> $b);
36+
}
37+
38+
// =============================================================================
39+
// Arithmetic operator extension tests (via TestDecimal)
40+
// =============================================================================
41+
42+
function testArithmeticAdd(TestDecimal $a, TestDecimal $b): void
43+
{
44+
assertType('PHPStan\Fixture\TestDecimal', $a + $b);
45+
}
46+
47+
function testArithmeticSub(TestDecimal $a, TestDecimal $b): void
48+
{
49+
assertType('PHPStan\Fixture\TestDecimal', $a - $b);
50+
}
51+
52+
function testArithmeticMul(TestDecimal $a, TestDecimal $b): void
53+
{
54+
assertType('PHPStan\Fixture\TestDecimal', $a * $b);
55+
}
56+
57+
function testArithmeticDiv(TestDecimal $a, TestDecimal $b): void
58+
{
59+
assertType('PHPStan\Fixture\TestDecimal', $a / $b);
60+
}
61+
62+
function testArithmeticPow(TestDecimal $a, TestDecimal $b): void
63+
{
64+
assertType('PHPStan\Fixture\TestDecimal', $a ** $b);
65+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
services:
2+
-
3+
class: PHPStan\Type\TestBitwiseOperatorTypeSpecifyingExtension
4+
tags:
5+
- phpstan.broker.operatorTypeSpecifyingExtension
6+
-
7+
class: PHPStan\Type\TestDecimalOperatorTypeSpecifyingExtension
8+
tags:
9+
- phpstan.broker.operatorTypeSpecifyingExtension
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Fixture;
4+
5+
/**
6+
* Test fixture for verifying bitwise operator type specifying extensions.
7+
*/
8+
final class TestBitwiseOperand
9+
{
10+
11+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type;
4+
5+
use PHPStan\Fixture\TestBitwiseOperand;
6+
use function in_array;
7+
8+
/**
9+
* Test extension for verifying that bitwise operators call type specifying extensions.
10+
*/
11+
final class TestBitwiseOperatorTypeSpecifyingExtension implements OperatorTypeSpecifyingExtension
12+
{
13+
14+
public function isOperatorSupported(string $operatorSigil, Type $leftSide, Type $rightSide): bool
15+
{
16+
$testType = new ObjectType(TestBitwiseOperand::class);
17+
18+
return in_array($operatorSigil, ['&', '|', '^', '<<', '>>'], true)
19+
&& $testType->isSuperTypeOf($leftSide)->yes()
20+
&& $testType->isSuperTypeOf($rightSide)->yes();
21+
}
22+
23+
public function specifyType(string $operatorSigil, Type $leftSide, Type $rightSide): Type
24+
{
25+
return new ObjectType(TestBitwiseOperand::class);
26+
}
27+
28+
}

0 commit comments

Comments
 (0)