6565use PHPStan \Type \Type ;
6666use PHPStan \Type \TypeCombinator ;
6767use PHPStan \Type \TypehintHelper ;
68+ use PHPStan \Type \TypeResult ;
6869use PHPStan \Type \TypeTraverser ;
6970use PHPStan \Type \TypeUtils ;
7071use PHPStan \Type \TypeWithClassName ;
@@ -298,7 +299,7 @@ public function getType(Expr $expr, InitializerExprContext $context): Type
298299 return $ this ->resolveIdenticalType (
299300 $ this ->getType ($ expr ->left , $ context ),
300301 $ this ->getType ($ expr ->right , $ context ),
301- );
302+ )-> type ;
302303 }
303304
304305 if ($ expr instanceof BinaryOp \NotIdentical) {
@@ -309,7 +310,7 @@ public function getType(Expr $expr, InitializerExprContext $context): Type
309310 return $ this ->resolveEqualType (
310311 $ this ->getType ($ expr ->left , $ context ),
311312 $ this ->getType ($ expr ->right , $ context ),
312- );
313+ )-> type ;
313314 }
314315
315316 if ($ expr instanceof BinaryOp \NotEqual) {
@@ -1349,34 +1350,42 @@ public function getShiftRightType(Expr $left, Expr $right, callable $getTypeCall
13491350 return $ this ->resolveCommonMath (new Expr \BinaryOp \ShiftRight ($ left , $ right ), $ leftType , $ rightType );
13501351 }
13511352
1352- public function resolveIdenticalType (Type $ leftType , Type $ rightType ): BooleanType
1353+ /**
1354+ * @return TypeResult<BooleanType>
1355+ */
1356+ public function resolveIdenticalType (Type $ leftType , Type $ rightType ): TypeResult
13531357 {
13541358 if ($ leftType instanceof NeverType || $ rightType instanceof NeverType) {
1355- return new ConstantBooleanType (false );
1359+ return new TypeResult ( new ConstantBooleanType (false ), [] );
13561360 }
13571361
13581362 if ($ leftType instanceof ConstantScalarType && $ rightType instanceof ConstantScalarType) {
1359- return new ConstantBooleanType ($ leftType ->getValue () === $ rightType ->getValue ());
1363+ return new TypeResult ( new ConstantBooleanType ($ leftType ->getValue () === $ rightType ->getValue ()), [] );
13601364 }
13611365
13621366 $ leftTypeFiniteTypes = $ leftType ->getFiniteTypes ();
13631367 $ rightTypeFiniteType = $ rightType ->getFiniteTypes ();
13641368 if (count ($ leftTypeFiniteTypes ) === 1 && count ($ rightTypeFiniteType ) === 1 ) {
1365- return new ConstantBooleanType ($ leftTypeFiniteTypes [0 ]->equals ($ rightTypeFiniteType [0 ]));
1369+ return new TypeResult ( new ConstantBooleanType ($ leftTypeFiniteTypes [0 ]->equals ($ rightTypeFiniteType [0 ])), [] );
13661370 }
13671371
1368- if ($ leftType ->isSuperTypeOf ($ rightType )->no () && $ rightType ->isSuperTypeOf ($ leftType )->no ()) {
1369- return new ConstantBooleanType (false );
1372+ $ leftIsSuperTypeOfRight = $ leftType ->isSuperTypeOfWithReason ($ rightType );
1373+ $ rightIsSuperTypeOfLeft = $ rightType ->isSuperTypeOfWithReason ($ leftType );
1374+ if ($ leftIsSuperTypeOfRight ->no () && $ rightIsSuperTypeOfLeft ->no ()) {
1375+ return new TypeResult (new ConstantBooleanType (false ), array_merge ($ leftIsSuperTypeOfRight ->reasons , $ rightIsSuperTypeOfLeft ->reasons ));
13701376 }
13711377
13721378 if ($ leftType instanceof ConstantArrayType && $ rightType instanceof ConstantArrayType) {
1373- return $ this ->resolveConstantArrayTypeComparison ($ leftType , $ rightType , fn ($ leftValueType , $ rightValueType ): BooleanType => $ this ->resolveIdenticalType ($ leftValueType , $ rightValueType ));
1379+ return $ this ->resolveConstantArrayTypeComparison ($ leftType , $ rightType , fn ($ leftValueType , $ rightValueType ): TypeResult => $ this ->resolveIdenticalType ($ leftValueType , $ rightValueType ));
13741380 }
13751381
1376- return new BooleanType ();
1382+ return new TypeResult ( new BooleanType (), [] );
13771383 }
13781384
1379- public function resolveEqualType (Type $ leftType , Type $ rightType ): BooleanType
1385+ /**
1386+ * @return TypeResult<BooleanType>
1387+ */
1388+ public function resolveEqualType (Type $ leftType , Type $ rightType ): TypeResult
13801389 {
13811390 if (
13821391 ($ leftType ->isEnum ()->yes () && $ rightType ->isTrue ()->no ())
@@ -1386,16 +1395,17 @@ public function resolveEqualType(Type $leftType, Type $rightType): BooleanType
13861395 }
13871396
13881397 if ($ leftType instanceof ConstantArrayType && $ rightType instanceof ConstantArrayType) {
1389- return $ this ->resolveConstantArrayTypeComparison ($ leftType , $ rightType , fn ($ leftValueType , $ rightValueType ): BooleanType => $ this ->resolveEqualType ($ leftValueType , $ rightValueType ));
1398+ return $ this ->resolveConstantArrayTypeComparison ($ leftType , $ rightType , fn ($ leftValueType , $ rightValueType ): TypeResult => $ this ->resolveEqualType ($ leftValueType , $ rightValueType ));
13901399 }
13911400
1392- return $ leftType ->looseCompare ($ rightType , $ this ->phpVersion );
1401+ return new TypeResult ( $ leftType ->looseCompare ($ rightType , $ this ->phpVersion ), [] );
13931402 }
13941403
13951404 /**
1396- * @param callable(Type, Type): BooleanType $valueComparisonCallback
1405+ * @param callable(Type, Type): TypeResult<BooleanType> $valueComparisonCallback
1406+ * @return TypeResult<BooleanType>
13971407 */
1398- private function resolveConstantArrayTypeComparison (ConstantArrayType $ leftType , ConstantArrayType $ rightType , callable $ valueComparisonCallback ): BooleanType
1408+ private function resolveConstantArrayTypeComparison (ConstantArrayType $ leftType , ConstantArrayType $ rightType , callable $ valueComparisonCallback ): TypeResult
13991409 {
14001410 $ leftKeyTypes = $ leftType ->getKeyTypes ();
14011411 $ rightKeyTypes = $ rightType ->getKeyTypes ();
@@ -1412,7 +1422,7 @@ private function resolveConstantArrayTypeComparison(ConstantArrayType $leftType,
14121422
14131423 if (count ($ rightKeyTypes ) === 0 ) {
14141424 if (!$ leftOptional ) {
1415- return new ConstantBooleanType (false );
1425+ return new TypeResult ( new ConstantBooleanType (false ), [] );
14161426 }
14171427 continue ;
14181428 }
@@ -1425,13 +1435,13 @@ private function resolveConstantArrayTypeComparison(ConstantArrayType $leftType,
14251435 $ found = true ;
14261436 break ;
14271437 } elseif (!$ rightType ->isOptionalKey ($ j )) {
1428- return new ConstantBooleanType (false );
1438+ return new TypeResult ( new ConstantBooleanType (false ), [] );
14291439 }
14301440 }
14311441
14321442 if (!$ found ) {
14331443 if (!$ leftOptional ) {
1434- return new ConstantBooleanType (false );
1444+ return new TypeResult ( new ConstantBooleanType (false ), [] );
14351445 }
14361446 continue ;
14371447 }
@@ -1448,21 +1458,22 @@ private function resolveConstantArrayTypeComparison(ConstantArrayType $leftType,
14481458 }
14491459 }
14501460
1451- $ leftIdenticalToRight = $ valueComparisonCallback ($ leftValueTypes [$ i ], $ rightValueTypes [$ j ]);
1461+ $ leftIdenticalToRightResult = $ valueComparisonCallback ($ leftValueTypes [$ i ], $ rightValueTypes [$ j ]);
1462+ $ leftIdenticalToRight = $ leftIdenticalToRightResult ->type ;
14521463 if ($ leftIdenticalToRight ->isFalse ()->yes ()) {
1453- return new ConstantBooleanType ( false ) ;
1464+ return $ leftIdenticalToRightResult ;
14541465 }
14551466 $ resultType = TypeCombinator::union ($ resultType , $ leftIdenticalToRight );
14561467 }
14571468
14581469 foreach (array_keys ($ rightKeyTypes ) as $ j ) {
14591470 if (!$ rightType ->isOptionalKey ($ j )) {
1460- return new ConstantBooleanType (false );
1471+ return new TypeResult ( new ConstantBooleanType (false ), [] );
14611472 }
14621473 $ resultType = new BooleanType ();
14631474 }
14641475
1465- return $ resultType ->toBoolean ();
1476+ return new TypeResult ( $ resultType ->toBoolean (), [] );
14661477 }
14671478
14681479 private function callOperatorTypeSpecifyingExtensions (Expr \BinaryOp $ expr , Type $ leftType , Type $ rightType ): ?Type
0 commit comments