@@ -637,6 +637,9 @@ public function getBitwiseAndType(Expr $left, Expr $right, callable $getTypeCall
637637 }
638638 return TypeCombinator::union (...$ resultTypes );
639639 }
640+
641+ $ leftType = $ this ->optimizeScalarType ($ leftType );
642+ $ rightType = $ this ->optimizeScalarType ($ rightType );
640643 }
641644
642645 if ($ leftType ->isString ()->yes () && $ rightType ->isString ()->yes ()) {
@@ -703,6 +706,9 @@ public function getBitwiseOrType(Expr $left, Expr $right, callable $getTypeCallb
703706 }
704707 return TypeCombinator::union (...$ resultTypes );
705708 }
709+
710+ $ leftType = $ this ->optimizeScalarType ($ leftType );
711+ $ rightType = $ this ->optimizeScalarType ($ rightType );
706712 }
707713
708714 if ($ leftType ->isString ()->yes () && $ rightType ->isString ()->yes ()) {
@@ -759,6 +765,9 @@ public function getBitwiseXorType(Expr $left, Expr $right, callable $getTypeCall
759765 }
760766 return TypeCombinator::union (...$ resultTypes );
761767 }
768+
769+ $ leftType = $ this ->optimizeScalarType ($ leftType );
770+ $ rightType = $ this ->optimizeScalarType ($ rightType );
762771 }
763772
764773 if ($ leftType ->isString ()->yes () && $ rightType ->isString ()->yes ()) {
@@ -844,6 +853,9 @@ public function getDivType(Expr $left, Expr $right, callable $getTypeCallback):
844853 }
845854 return TypeCombinator::union (...$ resultTypes );
846855 }
856+
857+ $ leftType = $ this ->optimizeScalarType ($ leftType );
858+ $ rightType = $ this ->optimizeScalarType ($ rightType );
847859 }
848860
849861 $ rightScalarValues = $ rightType ->toNumber ()->getConstantScalarValues ();
@@ -909,6 +921,9 @@ public function getModType(Expr $left, Expr $right, callable $getTypeCallback):
909921 }
910922 return TypeCombinator::union (...$ resultTypes );
911923 }
924+
925+ $ leftType = $ this ->optimizeScalarType ($ leftType );
926+ $ rightType = $ this ->optimizeScalarType ($ rightType );
912927 }
913928
914929 $ integerType = $ rightType ->toInteger ();
@@ -1001,6 +1016,9 @@ public function getPlusType(Expr $left, Expr $right, callable $getTypeCallback):
10011016
10021017 return TypeCombinator::union (...$ resultTypes );
10031018 }
1019+
1020+ $ leftType = $ this ->optimizeScalarType ($ leftType );
1021+ $ rightType = $ this ->optimizeScalarType ($ rightType );
10041022 }
10051023
10061024 $ leftConstantArrays = $ leftType ->getConstantArrays ();
@@ -1162,6 +1180,9 @@ public function getMinusType(Expr $left, Expr $right, callable $getTypeCallback)
11621180
11631181 return TypeCombinator::union (...$ resultTypes );
11641182 }
1183+
1184+ $ leftType = $ this ->optimizeScalarType ($ leftType );
1185+ $ rightType = $ this ->optimizeScalarType ($ rightType );
11651186 }
11661187
11671188 return $ this ->resolveCommonMath (new BinaryOp \Minus ($ left , $ right ), $ leftType , $ rightType );
@@ -1203,6 +1224,9 @@ public function getMulType(Expr $left, Expr $right, callable $getTypeCallback):
12031224
12041225 return TypeCombinator::union (...$ resultTypes );
12051226 }
1227+
1228+ $ leftType = $ this ->optimizeScalarType ($ leftType );
1229+ $ rightType = $ this ->optimizeScalarType ($ rightType );
12061230 }
12071231
12081232 $ leftNumberType = $ leftType ->toNumber ();
@@ -1288,6 +1312,9 @@ public function getShiftLeftType(Expr $left, Expr $right, callable $getTypeCallb
12881312
12891313 return TypeCombinator::union (...$ resultTypes );
12901314 }
1315+
1316+ $ leftType = $ this ->optimizeScalarType ($ leftType );
1317+ $ rightType = $ this ->optimizeScalarType ($ rightType );
12911318 }
12921319
12931320 $ leftNumberType = $ leftType ->toNumber ();
@@ -1344,6 +1371,9 @@ public function getShiftRightType(Expr $left, Expr $right, callable $getTypeCall
13441371
13451372 return TypeCombinator::union (...$ resultTypes );
13461373 }
1374+
1375+ $ leftType = $ this ->optimizeScalarType ($ leftType );
1376+ $ rightType = $ this ->optimizeScalarType ($ rightType );
13471377 }
13481378
13491379 $ leftNumberType = $ leftType ->toNumber ();
@@ -1356,6 +1386,33 @@ public function getShiftRightType(Expr $left, Expr $right, callable $getTypeCall
13561386 return $ this ->resolveCommonMath (new Expr \BinaryOp \ShiftRight ($ left , $ right ), $ leftType , $ rightType );
13571387 }
13581388
1389+ private function optimizeScalarType (Type $ type ): Type
1390+ {
1391+ $ types = [];
1392+ if ($ type ->isInteger ()->yes ()) {
1393+ $ types [] = new IntegerType ();
1394+ }
1395+ if ($ type ->isString ()->yes ()) {
1396+ $ types [] = new StringType ();
1397+ }
1398+ if ($ type ->isFloat ()->yes ()) {
1399+ $ types [] = new FloatType ();
1400+ }
1401+ if ($ type ->isNull ()->yes ()) {
1402+ $ types [] = new NullType ();
1403+ }
1404+
1405+ if (count ($ types ) === 0 ) {
1406+ return new ErrorType ();
1407+ }
1408+
1409+ if (count ($ types ) === 1 ) {
1410+ return $ types [0 ];
1411+ }
1412+
1413+ return new UnionType ($ types );
1414+ }
1415+
13591416 /**
13601417 * @return TypeResult<BooleanType>
13611418 */
0 commit comments