@@ -632,6 +632,9 @@ public function getBitwiseAndType(Expr $left, Expr $right, callable $getTypeCall
632632 }
633633 return TypeCombinator::union (...$ resultTypes );
634634 }
635+
636+ $ leftType = $ this ->optimizeScalarType ($ leftType );
637+ $ rightType = $ this ->optimizeScalarType ($ rightType );
635638 }
636639
637640 if ($ leftType ->isString ()->yes () && $ rightType ->isString ()->yes ()) {
@@ -698,6 +701,9 @@ public function getBitwiseOrType(Expr $left, Expr $right, callable $getTypeCallb
698701 }
699702 return TypeCombinator::union (...$ resultTypes );
700703 }
704+
705+ $ leftType = $ this ->optimizeScalarType ($ leftType );
706+ $ rightType = $ this ->optimizeScalarType ($ rightType );
701707 }
702708
703709 if ($ leftType ->isString ()->yes () && $ rightType ->isString ()->yes ()) {
@@ -754,6 +760,9 @@ public function getBitwiseXorType(Expr $left, Expr $right, callable $getTypeCall
754760 }
755761 return TypeCombinator::union (...$ resultTypes );
756762 }
763+
764+ $ leftType = $ this ->optimizeScalarType ($ leftType );
765+ $ rightType = $ this ->optimizeScalarType ($ rightType );
757766 }
758767
759768 if ($ leftType ->isString ()->yes () && $ rightType ->isString ()->yes ()) {
@@ -839,6 +848,9 @@ public function getDivType(Expr $left, Expr $right, callable $getTypeCallback):
839848 }
840849 return TypeCombinator::union (...$ resultTypes );
841850 }
851+
852+ $ leftType = $ this ->optimizeScalarType ($ leftType );
853+ $ rightType = $ this ->optimizeScalarType ($ rightType );
842854 }
843855
844856 $ rightScalarValues = $ rightType ->toNumber ()->getConstantScalarValues ();
@@ -899,6 +911,9 @@ public function getModType(Expr $left, Expr $right, callable $getTypeCallback):
899911 }
900912 return TypeCombinator::union (...$ resultTypes );
901913 }
914+
915+ $ leftType = $ this ->optimizeScalarType ($ leftType );
916+ $ rightType = $ this ->optimizeScalarType ($ rightType );
902917 }
903918
904919 $ integerType = $ rightType ->toInteger ();
@@ -991,6 +1006,9 @@ public function getPlusType(Expr $left, Expr $right, callable $getTypeCallback):
9911006
9921007 return TypeCombinator::union (...$ resultTypes );
9931008 }
1009+
1010+ $ leftType = $ this ->optimizeScalarType ($ leftType );
1011+ $ rightType = $ this ->optimizeScalarType ($ rightType );
9941012 }
9951013
9961014 $ leftConstantArrays = $ leftType ->getConstantArrays ();
@@ -1152,6 +1170,9 @@ public function getMinusType(Expr $left, Expr $right, callable $getTypeCallback)
11521170
11531171 return TypeCombinator::union (...$ resultTypes );
11541172 }
1173+
1174+ $ leftType = $ this ->optimizeScalarType ($ leftType );
1175+ $ rightType = $ this ->optimizeScalarType ($ rightType );
11551176 }
11561177
11571178 return $ this ->resolveCommonMath (new BinaryOp \Minus ($ left , $ right ), $ leftType , $ rightType );
@@ -1193,6 +1214,9 @@ public function getMulType(Expr $left, Expr $right, callable $getTypeCallback):
11931214
11941215 return TypeCombinator::union (...$ resultTypes );
11951216 }
1217+
1218+ $ leftType = $ this ->optimizeScalarType ($ leftType );
1219+ $ rightType = $ this ->optimizeScalarType ($ rightType );
11961220 }
11971221
11981222 $ leftNumberType = $ leftType ->toNumber ();
@@ -1278,6 +1302,9 @@ public function getShiftLeftType(Expr $left, Expr $right, callable $getTypeCallb
12781302
12791303 return TypeCombinator::union (...$ resultTypes );
12801304 }
1305+
1306+ $ leftType = $ this ->optimizeScalarType ($ leftType );
1307+ $ rightType = $ this ->optimizeScalarType ($ rightType );
12811308 }
12821309
12831310 $ leftNumberType = $ leftType ->toNumber ();
@@ -1334,6 +1361,9 @@ public function getShiftRightType(Expr $left, Expr $right, callable $getTypeCall
13341361
13351362 return TypeCombinator::union (...$ resultTypes );
13361363 }
1364+
1365+ $ leftType = $ this ->optimizeScalarType ($ leftType );
1366+ $ rightType = $ this ->optimizeScalarType ($ rightType );
13371367 }
13381368
13391369 $ leftNumberType = $ leftType ->toNumber ();
@@ -1346,6 +1376,33 @@ public function getShiftRightType(Expr $left, Expr $right, callable $getTypeCall
13461376 return $ this ->resolveCommonMath (new Expr \BinaryOp \ShiftRight ($ left , $ right ), $ leftType , $ rightType );
13471377 }
13481378
1379+ private function optimizeScalarType (Type $ type ): Type
1380+ {
1381+ $ types = [];
1382+ if ($ type ->isInteger ()->yes ()) {
1383+ $ types [] = new IntegerType ();
1384+ }
1385+ if ($ type ->isString ()->yes ()) {
1386+ $ types [] = new StringType ();
1387+ }
1388+ if ($ type ->isFloat ()->yes ()) {
1389+ $ types [] = new FloatType ();
1390+ }
1391+ if ($ type ->isNull ()->yes ()) {
1392+ $ types [] = new NullType ();
1393+ }
1394+
1395+ if (count ($ types ) === 0 ) {
1396+ return new ErrorType ();
1397+ }
1398+
1399+ if (count ($ types ) === 1 ) {
1400+ return $ types [0 ];
1401+ }
1402+
1403+ return new UnionType ($ types );
1404+ }
1405+
13491406 /**
13501407 * @return TypeResult<BooleanType>
13511408 */
0 commit comments