Skip to content

Commit ca5edd1

Browse files
Fix bitwise on mixed
1 parent 31e52fa commit ca5edd1

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
@@ -647,9 +647,14 @@ public function getBitwiseAndType(Expr $left, Expr $right, callable $getTypeCall
647647
$rightType = $this->optimizeScalarType($rightType);
648648
}
649649

650-
if ($leftType->isString()->yes() && $rightType->isString()->yes()) {
650+
$leftIsString = $leftType->isString();
651+
$rightIsString = $rightType->isString();
652+
if ($leftIsString->yes() && $rightIsString->yes()) {
651653
return new StringType();
652654
}
655+
if ($leftIsString->maybe() && $rightIsString->maybe()) {
656+
return new ErrorType();
657+
}
653658

654659
$leftNumberType = $leftType->toNumber();
655660
$rightNumberType = $rightType->toNumber();
@@ -716,9 +721,14 @@ public function getBitwiseOrType(Expr $left, Expr $right, callable $getTypeCallb
716721
$rightType = $this->optimizeScalarType($rightType);
717722
}
718723

719-
if ($leftType->isString()->yes() && $rightType->isString()->yes()) {
724+
$leftIsString = $leftType->isString();
725+
$rightIsString = $rightType->isString();
726+
if ($leftIsString->yes() && $rightIsString->yes()) {
720727
return new StringType();
721728
}
729+
if ($leftIsString->maybe() && $rightIsString->maybe()) {
730+
return new ErrorType();
731+
}
722732

723733
if (TypeCombinator::union($leftType->toNumber(), $rightType->toNumber()) instanceof ErrorType) {
724734
return new ErrorType();
@@ -775,9 +785,14 @@ public function getBitwiseXorType(Expr $left, Expr $right, callable $getTypeCall
775785
$rightType = $this->optimizeScalarType($rightType);
776786
}
777787

778-
if ($leftType->isString()->yes() && $rightType->isString()->yes()) {
788+
$leftIsString = $leftType->isString();
789+
$rightIsString = $rightType->isString();
790+
if ($leftIsString->yes() && $rightIsString->yes()) {
779791
return new StringType();
780792
}
793+
if ($leftIsString->maybe() && $rightIsString->maybe()) {
794+
return new ErrorType();
795+
}
781796

782797
if (TypeCombinator::union($leftType->toNumber(), $rightType->toNumber()) instanceof ErrorType) {
783798
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
@@ -2361,6 +2361,11 @@ public function testBug11863(): void
23612361
$this->analyse([__DIR__ . '/data/bug-11863.php'], []);
23622362
}
23632363

2364+
public function testBug8094(): void
2365+
{
2366+
$this->analyse([__DIR__ . '/data/bug-8094.php'], []);
2367+
}
2368+
23642369
public function testBug13556(): void
23652370
{
23662371
$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)