39
39
use PHPStan \Type \ArrayType ;
40
40
use PHPStan \Type \BooleanType ;
41
41
use PHPStan \Type \ConditionalTypeForParameter ;
42
+ use PHPStan \Type \Constant \ConstantArrayType ;
42
43
use PHPStan \Type \Constant \ConstantArrayTypeBuilder ;
43
44
use PHPStan \Type \Constant \ConstantBooleanType ;
44
45
use PHPStan \Type \Constant \ConstantIntegerType ;
@@ -1049,7 +1050,7 @@ private function turnListIntoConstantArray(FuncCall $countFuncCall, Type $type,
1049
1050
$ offsetType = new ConstantIntegerType ($ i );
1050
1051
$ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), true );
1051
1052
}
1052
- } else {
1053
+ } elseif ( $ type -> isConstantArray ()-> yes ()) {
1053
1054
for ($ i = $ sizeType ->getMin ();; $ i ++) {
1054
1055
$ offsetType = new ConstantIntegerType ($ i );
1055
1056
$ hasOffset = $ type ->hasOffsetValueType ($ offsetType );
@@ -1060,7 +1061,11 @@ private function turnListIntoConstantArray(FuncCall $countFuncCall, Type $type,
1060
1061
}
1061
1062
1062
1063
}
1063
- return $ valueTypesBuilder ->getArray ();
1064
+
1065
+ $ arrayType = $ valueTypesBuilder ->getArray ();
1066
+ if ($ arrayType ->isIterableAtLeastOnce ()->yes ()) {
1067
+ return $ arrayType ;
1068
+ }
1064
1069
}
1065
1070
1066
1071
return null ;
@@ -1102,54 +1107,6 @@ private function specifyTypesForConstantBinaryExpression(
1102
1107
));
1103
1108
}
1104
1109
1105
- if (
1106
- !$ context ->null ()
1107
- && $ exprNode instanceof FuncCall
1108
- && count ($ exprNode ->getArgs ()) >= 1
1109
- && $ exprNode ->name instanceof Name
1110
- && in_array (strtolower ((string ) $ exprNode ->name ), ['count ' , 'sizeof ' ], true )
1111
- && $ constantType instanceof ConstantIntegerType
1112
- ) {
1113
- if ($ constantType ->getValue () < 0 ) {
1114
- return $ this ->create ($ exprNode ->getArgs ()[0 ]->value , new NeverType (), $ context , false , $ scope , $ rootExpr );
1115
- }
1116
-
1117
- $ argType = $ scope ->getType ($ exprNode ->getArgs ()[0 ]->value );
1118
-
1119
- if ($ argType instanceof UnionType) {
1120
- $ narrowed = $ this ->narrowUnionByArraySize ($ exprNode , $ argType , $ constantType , $ context , $ scope , $ rootExpr );
1121
- if ($ narrowed !== null ) {
1122
- return $ narrowed ;
1123
- }
1124
- }
1125
-
1126
- if ($ context ->truthy () || $ constantType ->getValue () === 0 ) {
1127
- $ newContext = $ context ;
1128
- if ($ constantType ->getValue () === 0 ) {
1129
- $ newContext = $ newContext ->negate ();
1130
- }
1131
-
1132
- if ($ argType ->isArray ()->yes ()) {
1133
- if (
1134
- $ context ->truthy ()
1135
- && $ argType ->isConstantArray ()->yes ()
1136
- && $ constantType ->isSuperTypeOf ($ argType ->getArraySize ())->no ()
1137
- ) {
1138
- return $ this ->create ($ exprNode ->getArgs ()[0 ]->value , new NeverType (), $ context , false , $ scope , $ rootExpr );
1139
- }
1140
-
1141
- $ funcTypes = $ this ->create ($ exprNode , $ constantType , $ context , false , $ scope , $ rootExpr );
1142
- $ constArray = $ this ->turnListIntoConstantArray ($ exprNode , $ argType , $ constantType , $ scope );
1143
- if ($ context ->truthy () && $ constArray !== null ) {
1144
- $ valueTypes = $ this ->create ($ exprNode ->getArgs ()[0 ]->value , $ constArray , $ context , false , $ scope , $ rootExpr );
1145
- } else {
1146
- $ valueTypes = $ this ->create ($ exprNode ->getArgs ()[0 ]->value , new NonEmptyArrayType (), $ newContext , false , $ scope , $ rootExpr );
1147
- }
1148
- return $ funcTypes ->unionWith ($ valueTypes );
1149
- }
1150
- }
1151
- }
1152
-
1153
1110
if (
1154
1111
!$ context ->null ()
1155
1112
&& $ exprNode instanceof FuncCall
@@ -2137,6 +2094,70 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
2137
2094
}
2138
2095
$ rightType = $ scope ->getType ($ rightExpr );
2139
2096
2097
+ if (
2098
+ !$ context ->null ()
2099
+ && $ unwrappedLeftExpr instanceof FuncCall
2100
+ && count ($ unwrappedLeftExpr ->getArgs ()) >= 1
2101
+ && $ unwrappedLeftExpr ->name instanceof Name
2102
+ && in_array (strtolower ((string ) $ unwrappedLeftExpr ->name ), ['count ' , 'sizeof ' ], true )
2103
+ && $ rightType ->isInteger ()->yes ()
2104
+ ) {
2105
+ if (IntegerRangeType::fromInterval (null , -1 )->isSuperTypeOf ($ rightType )->yes ()) {
2106
+ return $ this ->create ($ unwrappedLeftExpr ->getArgs ()[0 ]->value , new NeverType (), $ context , false , $ scope , $ rootExpr );
2107
+ }
2108
+
2109
+ $ argType = $ scope ->getType ($ unwrappedLeftExpr ->getArgs ()[0 ]->value );
2110
+ $ isZero = (new ConstantIntegerType (0 ))->isSuperTypeOf ($ rightType );
2111
+ if ($ isZero ->yes ()) {
2112
+ $ funcTypes = $ this ->create ($ unwrappedLeftExpr , $ rightType , $ context , false , $ scope , $ rootExpr );
2113
+
2114
+ if ($ context ->truthy () && !$ argType ->isArray ()->yes ()) {
2115
+ $ newArgType = new UnionType ([
2116
+ new ObjectType (Countable::class),
2117
+ new ConstantArrayType ([], []),
2118
+ ]);
2119
+ } else {
2120
+ $ newArgType = new ConstantArrayType ([], []);
2121
+ }
2122
+
2123
+ return $ funcTypes ->unionWith (
2124
+ $ this ->create ($ unwrappedLeftExpr ->getArgs ()[0 ]->value , $ newArgType , $ context , false , $ scope , $ rootExpr ),
2125
+ );
2126
+ }
2127
+
2128
+ if ($ argType instanceof UnionType) {
2129
+ $ narrowed = $ this ->narrowUnionByArraySize ($ unwrappedLeftExpr , $ argType , $ rightType , $ context , $ scope , $ rootExpr );
2130
+ if ($ narrowed !== null ) {
2131
+ return $ narrowed ;
2132
+ }
2133
+ }
2134
+
2135
+ if ($ context ->truthy ()) {
2136
+ if ($ argType ->isArray ()->yes ()) {
2137
+ if (
2138
+ $ argType ->isConstantArray ()->yes ()
2139
+ && $ rightType ->isSuperTypeOf ($ argType ->getArraySize ())->no ()
2140
+ ) {
2141
+ return $ this ->create ($ unwrappedLeftExpr ->getArgs ()[0 ]->value , new NeverType (), $ context , false , $ scope , $ rootExpr );
2142
+ }
2143
+
2144
+ $ funcTypes = $ this ->create ($ unwrappedLeftExpr , $ rightType , $ context , false , $ scope , $ rootExpr );
2145
+ $ constArray = $ this ->turnListIntoConstantArray ($ unwrappedLeftExpr , $ argType , $ rightType , $ scope );
2146
+ if ($ constArray !== null ) {
2147
+ return $ funcTypes ->unionWith (
2148
+ $ this ->create ($ unwrappedLeftExpr ->getArgs ()[0 ]->value , $ constArray , $ context , false , $ scope , $ rootExpr ),
2149
+ );
2150
+ } elseif (IntegerRangeType::fromInterval (1 , null )->isSuperTypeOf ($ rightType )->yes ()) {
2151
+ return $ funcTypes ->unionWith (
2152
+ $ this ->create ($ unwrappedLeftExpr ->getArgs ()[0 ]->value , new NonEmptyArrayType (), $ context , false , $ scope , $ rootExpr ),
2153
+ );
2154
+ }
2155
+
2156
+ return $ funcTypes ;
2157
+ }
2158
+ }
2159
+ }
2160
+
2140
2161
if (
2141
2162
$ context ->true ()
2142
2163
&& $ unwrappedLeftExpr instanceof FuncCall
0 commit comments