@@ -1056,13 +1056,19 @@ private function turnListIntoConstantArray(FuncCall $countFuncCall, Type $type,
10561056
10571057private function specifyTypesForConstantBinaryExpression (
10581058Expr $ exprNode ,
1059- ConstantScalarType $ constantType ,
1059+ Type $ constantType ,
10601060TypeSpecifierContext $ context ,
10611061Scope $ scope ,
10621062?Expr $ rootExpr ,
10631063): ?SpecifiedTypes
10641064{
1065- if (!$ context ->null () && $ constantType ->getValue () === false ) {
1065+ $ scalarValues = $ constantType ->getConstantScalarValues ();
1066+ if (count ($ scalarValues ) !== 1 ) {
1067+ return null ;
1068+ }
1069+ $ constValue = $ scalarValues [0 ];
1070+
1071+ if (!$ context ->null () && $ constValue === false ) {
10661072$ types = $ this ->create ($ exprNode , $ constantType , $ context , false , $ scope , $ rootExpr );
10671073if ($ exprNode instanceof Expr \NullsafeMethodCall || $ exprNode instanceof Expr \NullsafePropertyFetch) {
10681074return $ types ;
@@ -1076,7 +1082,7 @@ private function specifyTypesForConstantBinaryExpression(
10761082));
10771083}
10781084
1079- if (!$ context ->null () && $ constantType -> getValue () === true ) {
1085+ if (!$ context ->null () && $ constValue === true ) {
10801086$ types = $ this ->create ($ exprNode , $ constantType , $ context , false , $ scope , $ rootExpr );
10811087if ($ exprNode instanceof Expr \NullsafeMethodCall || $ exprNode instanceof Expr \NullsafePropertyFetch) {
10821088return $ types ;
@@ -1090,10 +1096,6 @@ private function specifyTypesForConstantBinaryExpression(
10901096));
10911097}
10921098
1093- if ($ constantType ->getValue () === null ) {
1094- return $ this ->create ($ exprNode , $ constantType , $ context , false , $ scope , $ rootExpr );
1095- }
1096-
10971099if (
10981100!$ context ->null ()
10991101&& $ exprNode instanceof FuncCall
@@ -1102,6 +1104,10 @@ private function specifyTypesForConstantBinaryExpression(
11021104&& in_array (strtolower ((string ) $ exprNode ->name ), ['count ' , 'sizeof ' ], true )
11031105&& $ constantType instanceof ConstantIntegerType
11041106) {
1107+ if ($ constantType ->getValue () < 0 ) {
1108+ return $ this ->create ($ exprNode ->getArgs ()[0 ]->value , new NeverType (), $ context , false , $ scope , $ rootExpr );
1109+ }
1110+
11051111$ argType = $ scope ->getType ($ exprNode ->getArgs ()[0 ]->value );
11061112
11071113if ($ argType instanceof UnionType) {
@@ -1146,6 +1152,10 @@ private function specifyTypesForConstantBinaryExpression(
11461152&& in_array (strtolower ((string ) $ exprNode ->name ), ['strlen ' , 'mb_strlen ' ], true )
11471153&& $ constantType instanceof ConstantIntegerType
11481154) {
1155+ if ($ constantType ->getValue () < 0 ) {
1156+ return $ this ->create ($ exprNode ->getArgs ()[0 ]->value , new NeverType (), $ context , false , $ scope , $ rootExpr );
1157+ }
1158+
11491159if ($ context ->truthy () || $ constantType ->getValue () === 0 ) {
11501160$ newContext = $ context ;
11511161if ($ constantType ->getValue () === 0 ) {
@@ -1172,12 +1182,18 @@ private function specifyTypesForConstantBinaryExpression(
11721182
11731183private function specifyTypesForConstantStringBinaryExpression (
11741184Expr $ exprNode ,
1175- ConstantStringType $ constantType ,
1185+ Type $ constantType ,
11761186TypeSpecifierContext $ context ,
11771187Scope $ scope ,
11781188?Expr $ rootExpr ,
11791189): ?SpecifiedTypes
11801190{
1191+ $ scalarValues = $ constantType ->getConstantScalarValues ();
1192+ if (count ($ scalarValues ) !== 1 || !is_string ($ scalarValues [0 ])) {
1193+ return null ;
1194+ }
1195+ $ constantStringValue = $ scalarValues [0 ];
1196+
11811197if (
11821198$ context ->truthy ()
11831199&& $ exprNode instanceof FuncCall
@@ -1188,12 +1204,12 @@ private function specifyTypesForConstantStringBinaryExpression(
11881204'ucwords ' , 'mb_convert_case ' , 'mb_convert_kana ' ,
11891205], true )
11901206&& isset ($ exprNode ->getArgs ()[0 ])
1191- && $ constantType -> getValue () !== ''
1207+ && $ constantStringValue !== ''
11921208) {
11931209$ argType = $ scope ->getType ($ exprNode ->getArgs ()[0 ]->value );
11941210
11951211if ($ argType ->isString ()->yes ()) {
1196- if ($ constantType -> getValue () !== '0 ' ) {
1212+ if ($ constantStringValue !== '0 ' ) {
11971213return $ this ->create (
11981214$ exprNode ->getArgs ()[0 ]->value ,
11991215TypeCombinator::intersect ($ argType , new AccessoryNonFalsyStringType ()),
@@ -1220,28 +1236,28 @@ private function specifyTypesForConstantStringBinaryExpression(
12201236&& isset ($ exprNode ->getArgs ()[0 ])
12211237) {
12221238$ type = null ;
1223- if ($ constantType -> getValue () === 'string ' ) {
1239+ if ($ constantStringValue === 'string ' ) {
12241240$ type = new StringType ();
12251241}
1226- if ($ constantType -> getValue () === 'array ' ) {
1242+ if ($ constantStringValue === 'array ' ) {
12271243$ type = new ArrayType (new MixedType (), new MixedType ());
12281244}
1229- if ($ constantType -> getValue () === 'boolean ' ) {
1245+ if ($ constantStringValue === 'boolean ' ) {
12301246$ type = new BooleanType ();
12311247}
1232- if (in_array ($ constantType -> getValue () , ['resource ' , 'resource (closed) ' ], true )) {
1248+ if (in_array ($ constantStringValue , ['resource ' , 'resource (closed) ' ], true )) {
12331249$ type = new ResourceType ();
12341250}
1235- if ($ constantType -> getValue () === 'integer ' ) {
1251+ if ($ constantStringValue === 'integer ' ) {
12361252$ type = new IntegerType ();
12371253}
1238- if ($ constantType -> getValue () === 'double ' ) {
1254+ if ($ constantStringValue === 'double ' ) {
12391255$ type = new FloatType ();
12401256}
1241- if ($ constantType -> getValue () === 'NULL ' ) {
1257+ if ($ constantStringValue === 'NULL ' ) {
12421258$ type = new NullType ();
12431259}
1244- if ($ constantType -> getValue () === 'object ' ) {
1260+ if ($ constantStringValue === 'object ' ) {
12451261$ type = new ObjectWithoutClassType ();
12461262}
12471263
@@ -1260,7 +1276,7 @@ private function specifyTypesForConstantStringBinaryExpression(
12601276&& isset ($ exprNode ->getArgs ()[0 ])
12611277) {
12621278$ argType = $ scope ->getType ($ exprNode ->getArgs ()[0 ]->value );
1263- $ objectType = new ObjectType ($ constantType -> getValue () );
1279+ $ objectType = new ObjectType ($ constantStringValue );
12641280$ classStringType = new GenericClassStringType ($ objectType );
12651281
12661282if ($ argType ->isString ()->yes ()) {
@@ -2149,10 +2165,14 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
21492165}
21502166}
21512167
2152- if (count ( $ rightType ->getConstantStrings ()) > 0 ) {
2168+ if ($ rightType ->isInteger ()-> yes () || $ rightType -> isString ()-> yes () ) {
21532169$ types = null ;
2154- foreach ($ rightType ->getConstantStrings () as $ constantString ) {
2155- $ specifiedType = $ this ->specifyTypesForConstantStringBinaryExpression ($ unwrappedLeftExpr , $ constantString , $ context , $ scope , $ rootExpr );
2170+ foreach ($ rightType ->getFiniteTypes () as $ finiteType ) {
2171+ if ($ finiteType ->isString ()->yes ()) {
2172+ $ specifiedType = $ this ->specifyTypesForConstantStringBinaryExpression ($ unwrappedLeftExpr , $ finiteType , $ context , $ scope , $ rootExpr );
2173+ } else {
2174+ $ specifiedType = $ this ->specifyTypesForConstantBinaryExpression ($ unwrappedLeftExpr , $ finiteType , $ context , $ scope , $ rootExpr );
2175+ }
21562176if ($ specifiedType === null ) {
21572177continue ;
21582178}
0 commit comments