Skip to content

Commit 34385de

Browse files
Fix bitwise on mixed
1 parent 1eead47 commit 34385de

File tree

4 files changed

+78
-3
lines changed

4 files changed

+78
-3
lines changed

src/Reflection/InitializerExprTypeResolver.php

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

1011-
if ($leftType->isString()->yes() && $rightType->isString()->yes()) {
1011+
$leftIsString = $leftType->isString();
1012+
$rightIsString = $rightType->isString();
1013+
if ($leftIsString->yes() && $rightIsString->yes()) {
10121014
return new StringType();
10131015
}
1016+
if ($leftIsString->maybe() && $rightIsString->maybe()) {
1017+
return new ErrorType();
1018+
}
10141019

10151020
$leftNumberType = $leftType->toNumber();
10161021
$rightNumberType = $rightType->toNumber();
@@ -1082,9 +1087,14 @@ public function getBitwiseOrTypeFromTypes(Type $leftType, Type $rightType): Type
10821087
$rightType = $this->optimizeScalarType($rightType);
10831088
}
10841089

1085-
if ($leftType->isString()->yes() && $rightType->isString()->yes()) {
1090+
$leftIsString = $leftType->isString();
1091+
$rightIsString = $rightType->isString();
1092+
if ($leftIsString->yes() && $rightIsString->yes()) {
10861093
return new StringType();
10871094
}
1095+
if ($leftIsString->maybe() && $rightIsString->maybe()) {
1096+
return new ErrorType();
1097+
}
10881098

10891099
if (TypeCombinator::union($leftType->toNumber(), $rightType->toNumber()) instanceof ErrorType) {
10901100
return new ErrorType();
@@ -1146,9 +1156,14 @@ public function getBitwiseXorTypeFromTypes(Type $leftType, Type $rightType): Typ
11461156
$rightType = $this->optimizeScalarType($rightType);
11471157
}
11481158

1149-
if ($leftType->isString()->yes() && $rightType->isString()->yes()) {
1159+
$leftIsString = $leftType->isString();
1160+
$rightIsString = $rightType->isString();
1161+
if ($leftIsString->yes() && $rightIsString->yes()) {
11501162
return new StringType();
11511163
}
1164+
if ($leftIsString->maybe() && $rightIsString->maybe()) {
1165+
return new ErrorType();
1166+
}
11521167

11531168
if (TypeCombinator::union($leftType->toNumber(), $rightType->toNumber()) instanceof ErrorType) {
11541169
return new ErrorType();
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace Bitwise;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/**
8+
* @param string|int $stringOrInt
9+
* @param mixed $mixed
10+
*/
11+
function test(int $int, string $string, $stringOrInt, $mixed) : void
12+
{
13+
assertType('int', $int & $int);
14+
assertType('*ERROR*', $int & $string);
15+
assertType('*ERROR*', $int & $stringOrInt);
16+
assertType('int', $int & $mixed);
17+
assertType('string', $string & $string);
18+
assertType('*ERROR*', $string & $stringOrInt);
19+
assertType('*ERROR*', $string & $mixed);
20+
assertType('*ERROR*', $stringOrInt & $stringOrInt);
21+
assertType('*ERROR*', $stringOrInt & $mixed);
22+
assertType('*ERROR*', $mixed & $mixed);
23+
24+
assertType('int', $int | $int);
25+
assertType('*ERROR*', $int | $string);
26+
assertType('*ERROR*', $int | $stringOrInt);
27+
assertType('int', $int | $mixed);
28+
assertType('string', $string | $string);
29+
assertType('*ERROR*', $string | $stringOrInt);
30+
assertType('*ERROR*', $string | $mixed);
31+
assertType('*ERROR*', $stringOrInt | $stringOrInt);
32+
assertType('*ERROR*', $stringOrInt | $mixed);
33+
assertType('*ERROR*', $mixed | $mixed);
34+
35+
assertType('int', $int ^ $int);
36+
assertType('*ERROR*', $int ^ $string);
37+
assertType('*ERROR*', $int ^ $stringOrInt);
38+
assertType('int', $int ^ $mixed);
39+
assertType('string', $string ^ $string);
40+
assertType('*ERROR*', $string ^ $stringOrInt);
41+
assertType('*ERROR*', $string ^ $mixed);
42+
assertType('*ERROR*', $stringOrInt ^ $stringOrInt);
43+
assertType('*ERROR*', $stringOrInt ^ $mixed);
44+
assertType('*ERROR*', $mixed ^ $mixed);
45+
}

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2404,6 +2404,11 @@ public function testBug13784(): void
24042404
$this->analyse([__DIR__ . '/data/bug-13784.php'], []);
24052405
}
24062406

2407+
public function testBug8094(): void
2408+
{
2409+
$this->analyse([__DIR__ . '/data/bug-8094.php'], []);
2410+
}
2411+
24072412
public function testBug13556(): void
24082413
{
24092414
$this->checkExplicitMixed = true;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Bug8094;
4+
5+
function mask_encode($data, $mask)
6+
{
7+
$mask = substr($mask, 0, strlen($data));
8+
$data ^= $mask;
9+
return(base64_encode($data));
10+
}

0 commit comments

Comments
 (0)