@@ -1643,15 +1643,8 @@ private function findTypeExpressionsFromBinaryOperation(Scope $scope, Node\Expr\
16431643$ leftType = $ scope ->getType ($ binaryOperation ->left );
16441644$ rightType = $ scope ->getType ($ binaryOperation ->right );
16451645
1646- $ rightExpr = $ binaryOperation ->right ;
1647- if ($ rightExpr instanceof AlwaysRememberedExpr) {
1648- $ rightExpr = $ rightExpr ->getExpr ();
1649- }
1650-
1651- $ leftExpr = $ binaryOperation ->left ;
1652- if ($ leftExpr instanceof AlwaysRememberedExpr) {
1653- $ leftExpr = $ leftExpr ->getExpr ();
1654- }
1646+ $ rightExpr = $ this ->extractExpression ($ binaryOperation ->right );
1647+ $ leftExpr = $ this ->extractExpression ($ binaryOperation ->left );
16551648
16561649if (
16571650$ leftType instanceof ConstantScalarType
@@ -1670,6 +1663,39 @@ private function findTypeExpressionsFromBinaryOperation(Scope $scope, Node\Expr\
16701663return null ;
16711664}
16721665
1666+ /**
1667+ * @return array{Expr, Type, Type}|null
1668+ */
1669+ private function findEnumTypeExpressionsFromBinaryOperation (Scope $ scope , Node \Expr \BinaryOp $ binaryOperation ): ?array
1670+ {
1671+ $ leftType = $ scope ->getType ($ binaryOperation ->left );
1672+ $ rightType = $ scope ->getType ($ binaryOperation ->right );
1673+
1674+ $ rightExpr = $ this ->extractExpression ($ binaryOperation ->right );
1675+ $ leftExpr = $ this ->extractExpression ($ binaryOperation ->left );
1676+
1677+ if (
1678+ $ leftType ->getEnumCases () === [$ leftType ]
1679+ && !$ rightExpr instanceof ConstFetch
1680+ && !$ rightExpr instanceof ClassConstFetch
1681+ ) {
1682+ return [$ binaryOperation ->right , $ leftType , $ rightType ];
1683+ } elseif (
1684+ $ rightType ->getEnumCases () === [$ rightType ]
1685+ && !$ leftExpr instanceof ConstFetch
1686+ && !$ leftExpr instanceof ClassConstFetch
1687+ ) {
1688+ return [$ binaryOperation ->left , $ rightType , $ leftType ];
1689+ }
1690+
1691+ return null ;
1692+ }
1693+
1694+ private function extractExpression (Expr $ expr ): Expr
1695+ {
1696+ return $ expr instanceof AlwaysRememberedExpr ? $ expr ->getExpr () : $ expr ;
1697+ }
1698+
16731699/** @api */
16741700public function create (
16751701Expr $ expr ,
@@ -2061,6 +2087,27 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif
20612087) {
20622088return $ this ->specifyTypesInCondition ($ scope , new Expr \BinaryOp \Identical ($ expr ->left , $ expr ->right ), $ context )->setRootExpr ($ expr );
20632089}
2090+
2091+ if (!$ context ->null () && TypeCombinator::containsNull ($ otherType )) {
2092+ if ($ constantType ->toBoolean ()->isTrue ()->yes ()) {
2093+ $ otherType = TypeCombinator::remove ($ otherType , new NullType ());
2094+ }
2095+
2096+ if (!$ otherType ->isSuperTypeOf ($ constantType )->no ()) {
2097+ return $ this ->create ($ exprNode , TypeCombinator::intersect ($ constantType , $ otherType ), $ context , $ scope )->setRootExpr ($ expr );
2098+ }
2099+ }
2100+ }
2101+
2102+ $ expressions = $ this ->findEnumTypeExpressionsFromBinaryOperation ($ scope , $ expr );
2103+ if ($ expressions !== null ) {
2104+ $ exprNode = $ expressions [0 ];
2105+ $ enumCaseObjectType = $ expressions [1 ];
2106+ $ otherType = $ expressions [2 ];
2107+
2108+ if (!$ context ->null ()) {
2109+ return $ this ->create ($ exprNode , TypeCombinator::intersect ($ enumCaseObjectType , $ otherType ), $ context , $ scope )->setRootExpr ($ expr );
2110+ }
20642111}
20652112
20662113$ leftType = $ scope ->getType ($ expr ->left );
0 commit comments