Skip to content

Commit 03cd5a4

Browse files
Try
1 parent 37608db commit 03cd5a4

File tree

3 files changed

+51
-12
lines changed

3 files changed

+51
-12
lines changed

src/Reflection/InitializerExprTypeResolver.php

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,9 +1008,16 @@ public function getBitwiseAndTypeFromTypes(Type $leftType, Type $rightType): Typ
10081008
$rightType = $this->optimizeScalarType($rightType);
10091009
}
10101010

1011+
if ($leftType instanceof MixedType && $rightType instanceof MixedType) {
1012+
return new BenevolentUnionType([new IntegerType(), new StringType()]);
1013+
}
1014+
10111015
$leftIsString = $leftType->isString();
10121016
$rightIsString = $rightType->isString();
1013-
if ($leftIsString->yes() && $rightIsString->yes()) {
1017+
if (
1018+
($leftIsString->yes() || $leftType instanceof MixedType)
1019+
&& ($rightIsString->yes() || $rightType instanceof MixedType)
1020+
) {
10141021
return new StringType();
10151022
}
10161023
if ($leftIsString->maybe() && $rightIsString->maybe()) {
@@ -1087,9 +1094,16 @@ public function getBitwiseOrTypeFromTypes(Type $leftType, Type $rightType): Type
10871094
$rightType = $this->optimizeScalarType($rightType);
10881095
}
10891096

1097+
if ($leftType instanceof MixedType && $rightType instanceof MixedType) {
1098+
return new BenevolentUnionType([new IntegerType(), new StringType()]);
1099+
}
1100+
10901101
$leftIsString = $leftType->isString();
10911102
$rightIsString = $rightType->isString();
1092-
if ($leftIsString->yes() && $rightIsString->yes()) {
1103+
if (
1104+
($leftIsString->yes() || $leftType instanceof MixedType)
1105+
&& ($rightIsString->yes() || $rightType instanceof MixedType)
1106+
) {
10931107
return new StringType();
10941108
}
10951109
if ($leftIsString->maybe() && $rightIsString->maybe()) {
@@ -1156,9 +1170,16 @@ public function getBitwiseXorTypeFromTypes(Type $leftType, Type $rightType): Typ
11561170
$rightType = $this->optimizeScalarType($rightType);
11571171
}
11581172

1173+
if ($leftType instanceof MixedType && $rightType instanceof MixedType) {
1174+
return new BenevolentUnionType([new IntegerType(), new StringType()]);
1175+
}
1176+
11591177
$leftIsString = $leftType->isString();
11601178
$rightIsString = $rightType->isString();
1161-
if ($leftIsString->yes() && $rightIsString->yes()) {
1179+
if (
1180+
($leftIsString->yes() || $leftType instanceof MixedType)
1181+
&& ($rightIsString->yes() || $rightType instanceof MixedType)
1182+
) {
11621183
return new StringType();
11631184
}
11641185
if ($leftIsString->maybe() && $rightIsString->maybe()) {

tests/PHPStan/Analyser/Generator/data/gnsr.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public function doBitwiseNot($a, int $b): void
110110
public function doBitwiseAnd($a, $b, int $c, int $d): void
111111
{
112112
assertType('int', $a & $b);
113-
assertNativeType('*ERROR*', $a & $b);
113+
assertNativeType('(int|string)', $a & $b);
114114
assertType('1', 1 & 1);
115115
assertNativeType('1', 1 & 1);
116116
assertType('int', $c & $d);
@@ -125,7 +125,7 @@ public function doBitwiseAnd($a, $b, int $c, int $d): void
125125
public function doBitwiseOr($a, $b, int $c, int $d): void
126126
{
127127
assertType('int', $a | $b);
128-
assertNativeType('*ERROR*', $a | $b);
128+
assertNativeType('(int|string)', $a | $b);
129129
assertType('1', 1 | 1);
130130
assertNativeType('1', 1 | 1);
131131
assertType('int', $c | $d);
@@ -140,7 +140,7 @@ public function doBitwiseOr($a, $b, int $c, int $d): void
140140
public function doBitwiseXor($a, $b, int $c, int $d): void
141141
{
142142
assertType('int', $a ^ $b);
143-
assertNativeType('*ERROR*', $a ^ $b);
143+
assertNativeType('(int|string)', $a ^ $b);
144144
assertType('0', 1 ^ 1);
145145
assertNativeType('0', 1 ^ 1);
146146
assertType('int', $c ^ $d);

tests/PHPStan/Analyser/nsrt/bitwise.php

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,50 @@ function test(int $int, string $string, $stringOrInt, $mixed) : void
1414
assertType('*ERROR*', $int & $string);
1515
assertType('*ERROR*', $int & $stringOrInt);
1616
assertType('int', $int & $mixed);
17+
assertType('*ERROR*', $string & $int);
1718
assertType('string', $string & $string);
1819
assertType('*ERROR*', $string & $stringOrInt);
19-
assertType('*ERROR*', $string & $mixed);
20+
assertType('string', $string & $mixed);
21+
assertType('*ERROR*', $stringOrInt & $int);
22+
assertType('*ERROR*', $stringOrInt & $string);
2023
assertType('*ERROR*', $stringOrInt & $stringOrInt);
2124
assertType('*ERROR*', $stringOrInt & $mixed);
22-
assertType('*ERROR*', $mixed & $mixed);
25+
assertType('int', $mixed & $int);
26+
assertType('string', $mixed & $string);
27+
assertType('*ERROR*', $mixed & $stringOrInt);
28+
assertType('(int|string)', $mixed & $mixed);
2329

2430
assertType('int', $int | $int);
2531
assertType('*ERROR*', $int | $string);
2632
assertType('*ERROR*', $int | $stringOrInt);
2733
assertType('int', $int | $mixed);
34+
assertType('*ERROR*', $string | $int);
2835
assertType('string', $string | $string);
2936
assertType('*ERROR*', $string | $stringOrInt);
30-
assertType('*ERROR*', $string | $mixed);
37+
assertType('string', $string | $mixed);
38+
assertType('*ERROR*', $stringOrInt | $int);
39+
assertType('*ERROR*', $stringOrInt | $string);
3140
assertType('*ERROR*', $stringOrInt | $stringOrInt);
3241
assertType('*ERROR*', $stringOrInt | $mixed);
33-
assertType('*ERROR*', $mixed | $mixed);
42+
assertType('int', $mixed | $int);
43+
assertType('string', $mixed | $string);
44+
assertType('*ERROR*', $mixed | $stringOrInt);
45+
assertType('(int|string)', $mixed | $mixed);
3446

3547
assertType('int', $int ^ $int);
3648
assertType('*ERROR*', $int ^ $string);
3749
assertType('*ERROR*', $int ^ $stringOrInt);
3850
assertType('int', $int ^ $mixed);
51+
assertType('*ERROR*', $string ^ $int);
3952
assertType('string', $string ^ $string);
4053
assertType('*ERROR*', $string ^ $stringOrInt);
41-
assertType('*ERROR*', $string ^ $mixed);
54+
assertType('string', $string ^ $mixed);
55+
assertType('*ERROR*', $stringOrInt ^ $int);
56+
assertType('*ERROR*', $stringOrInt ^ $string);
4257
assertType('*ERROR*', $stringOrInt ^ $stringOrInt);
4358
assertType('*ERROR*', $stringOrInt ^ $mixed);
44-
assertType('*ERROR*', $mixed ^ $mixed);
59+
assertType('int', $mixed ^ $int);
60+
assertType('string', $mixed ^ $string);
61+
assertType('*ERROR*', $mixed ^ $stringOrInt);
62+
assertType('(int|string)', $mixed ^ $mixed);
4563
}

0 commit comments

Comments
 (0)