@@ -272,7 +272,6 @@ public function specifyTypesInCondition(
272
272
) {
273
273
$ argType = $ scope ->getType ($ expr ->right ->getArgs ()[0 ]->value );
274
274
275
- $ sizeType = null ;
276
275
if ($ leftType instanceof ConstantIntegerType) {
277
276
if ($ orEqual ) {
278
277
$ sizeType = IntegerRangeType::createAllGreaterThanOrEqualTo ($ leftType ->getValue ());
@@ -281,6 +280,8 @@ public function specifyTypesInCondition(
281
280
}
282
281
} elseif ($ leftType instanceof IntegerRangeType) {
283
282
$ sizeType = $ leftType ->shift ($ offset );
283
+ } else {
284
+ $ sizeType = $ leftType ;
284
285
}
285
286
286
287
$ specifiedTypes = $ this ->specifyTypesForCountFuncCall ($ expr ->right , $ argType , $ sizeType , $ context , $ scope , $ expr );
@@ -1044,103 +1045,91 @@ public function specifyTypesInCondition(
1044
1045
return (new SpecifiedTypes ([], []))->setRootExpr ($ expr );
1045
1046
}
1046
1047
1047
- private function specifyTypesForCountFuncCall (FuncCall $ countFuncCall , Type $ type , ?Type $ sizeType , TypeSpecifierContext $ context , Scope $ scope , ?Expr $ rootExpr ): ?SpecifiedTypes
1048
+ private function specifyTypesForCountFuncCall (
1049
+ FuncCall $ countFuncCall ,
1050
+ Type $ type ,
1051
+ Type $ sizeType ,
1052
+ TypeSpecifierContext $ context ,
1053
+ Scope $ scope ,
1054
+ Expr $ rootExpr ,
1055
+ ): ?SpecifiedTypes
1048
1056
{
1049
- if ($ sizeType === null ) {
1050
- return null ;
1057
+ if (count ($ countFuncCall ->getArgs ()) === 1 ) {
1058
+ $ isNormalCount = TrinaryLogic::createYes ();
1059
+ } else {
1060
+ $ mode = $ scope ->getType ($ countFuncCall ->getArgs ()[1 ]->value );
1061
+ $ isNormalCount = (new ConstantIntegerType (COUNT_NORMAL ))->isSuperTypeOf ($ mode )->result ->or ($ type ->getIterableValueType ()->isArray ()->negate ());
1051
1062
}
1052
1063
1053
- if (
1054
- $ this ->isFuncCallWithNormalCount ($ countFuncCall , $ scope )->yes ()
1055
- && $ type ->isConstantArray ()->yes ()
1056
- ) {
1057
- $ resultType = TypeTraverser::map ($ type , function (Type $ type , callable $ traverse ) use ($ sizeType , $ context ) {
1058
- if ($ type instanceof UnionType) {
1059
- return $ traverse ($ type );
1060
- }
1061
-
1062
- $ arraySize = $ type ->getArraySize ();
1063
- $ isSize = $ sizeType ->isSuperTypeOf ($ arraySize );
1064
- if ($ context ->truthy () && $ isSize ->no ()) {
1065
- return new NeverType ();
1066
- }
1067
- if ($ context ->falsey () && !$ isSize ->yes ()) {
1068
- return new NeverType ();
1069
- }
1070
-
1071
- return $ this ->turnListIntoConstantArray ($ type , $ sizeType ) ?? $ type ;
1072
- });
1073
-
1074
- return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , $ resultType , $ context , $ scope )->setRootExpr ($ rootExpr );
1064
+ if (!$ isNormalCount ->yes () || (!$ type ->isConstantArray ()->yes () && !$ type ->isList ()->yes ())) {
1065
+ return null ;
1075
1066
}
1076
1067
1077
- return null ;
1078
- }
1068
+ $ resultType = TypeTraverser::map ($ type , static function (Type $ type , callable $ traverse ) use ($ sizeType , $ context ) {
1069
+ if ($ type instanceof UnionType) {
1070
+ return $ traverse ($ type );
1071
+ }
1079
1072
1080
- private function turnListIntoConstantArray (Type $ type , Type $ sizeType ): ?Type
1081
- {
1082
- if (
1083
- $ type ->isList ()->yes ()
1084
- && $ sizeType instanceof ConstantIntegerType
1085
- && $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
1086
- ) {
1087
- // turn optional offsets non-optional
1088
- $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1089
- for ($ i = 0 ; $ i < $ sizeType ->getValue (); $ i ++) {
1090
- $ offsetType = new ConstantIntegerType ($ i );
1091
- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1073
+ $ isSizeSuperTypeOfArraySize = $ sizeType ->isSuperTypeOf ($ type ->getArraySize ());
1074
+ if ($ context ->truthy () && $ isSizeSuperTypeOfArraySize ->no ()) {
1075
+ return new NeverType ();
1076
+ }
1077
+ if ($ context ->falsey () && !$ isSizeSuperTypeOfArraySize ->yes ()) {
1078
+ return new NeverType ();
1092
1079
}
1093
- return $ valueTypesBuilder ->getArray ();
1094
- }
1095
1080
1096
- if (
1097
- $ type ->isList ()->yes ()
1098
- && $ sizeType instanceof IntegerRangeType
1099
- && $ sizeType ->getMin () !== null
1100
- ) {
1101
- // turn optional offsets non-optional
1102
- $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1103
- for ($ i = 0 ; $ i < $ sizeType ->getMin (); $ i ++) {
1104
- $ offsetType = new ConstantIntegerType ($ i );
1105
- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1106
- }
1107
- if ($ sizeType ->getMax () !== null ) {
1108
- for ($ i = $ sizeType ->getMin (); $ i < $ sizeType ->getMax (); $ i ++) {
1109
- $ offsetType = new ConstantIntegerType ($ i );
1110
- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), true );
1111
- }
1112
- } elseif ($ type ->isConstantArray ()->yes ()) {
1113
- for ($ i = $ sizeType ->getMin ();; $ i ++) {
1114
- $ offsetType = new ConstantIntegerType ($ i );
1115
- $ hasOffset = $ type ->hasOffsetValueType ($ offsetType );
1116
- if ($ hasOffset ->no ()) {
1117
- break ;
1081
+ if ($ type ->isList ()->yes ()) {
1082
+ if (
1083
+ $ sizeType instanceof ConstantIntegerType
1084
+ && $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
1085
+ ) {
1086
+ // turn optional offsets non-optional
1087
+ $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1088
+ for ($ i = 0 ; $ i < $ sizeType ->getValue (); $ i ++) {
1089
+ $ offsetType = new ConstantIntegerType ($ i );
1090
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1118
1091
}
1119
- $ valueTypesBuilder ->setOffsetValueType ( $ offsetType , $ type -> getOffsetValueType ( $ offsetType ), ! $ hasOffset -> yes () );
1092
+ return $ valueTypesBuilder ->getArray ( );
1120
1093
}
1121
- } else {
1122
- return null ;
1123
- }
1124
1094
1125
- $ arrayType = $ valueTypesBuilder ->getArray ();
1126
- if ($ arrayType ->isIterableAtLeastOnce ()->yes ()) {
1127
- return $ arrayType ;
1128
- }
1129
- }
1095
+ if (
1096
+ $ sizeType instanceof IntegerRangeType
1097
+ && $ sizeType ->getMin () !== null
1098
+ ) {
1099
+ // turn optional offsets non-optional
1100
+ $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1101
+ for ($ i = 0 ; $ i < $ sizeType ->getMin (); $ i ++) {
1102
+ $ offsetType = new ConstantIntegerType ($ i );
1103
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1104
+ }
1105
+ if ($ sizeType ->getMax () !== null ) {
1106
+ for ($ i = $ sizeType ->getMin (); $ i < $ sizeType ->getMax (); $ i ++) {
1107
+ $ offsetType = new ConstantIntegerType ($ i );
1108
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), true );
1109
+ }
1110
+ } elseif ($ type ->isConstantArray ()->yes ()) {
1111
+ for ($ i = $ sizeType ->getMin ();; $ i ++) {
1112
+ $ offsetType = new ConstantIntegerType ($ i );
1113
+ $ hasOffset = $ type ->hasOffsetValueType ($ offsetType );
1114
+ if ($ hasOffset ->no ()) {
1115
+ break ;
1116
+ }
1117
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
1118
+ }
1119
+ } else {
1120
+ return TypeCombinator::intersect ($ type , new NonEmptyArrayType ());
1121
+ }
1130
1122
1131
- return null ;
1132
- }
1123
+ return $ valueTypesBuilder -> getArray () ;
1124
+ }
1133
1125
1134
- private function isFuncCallWithNormalCount (FuncCall $ countFuncCall , Scope $ scope ): TrinaryLogic
1135
- {
1136
- $ argType = $ scope ->getType ($ countFuncCall ->getArgs ()[0 ]->value );
1126
+ return $ type ;
1127
+ }
1137
1128
1138
- if (count ($ countFuncCall ->getArgs ()) === 1 ) {
1139
- return TrinaryLogic::createYes ();
1140
- }
1141
- $ mode = $ scope ->getType ($ countFuncCall ->getArgs ()[1 ]->value );
1129
+ return TypeCombinator::intersect ($ type , new NonEmptyArrayType ());
1130
+ });
1142
1131
1143
- return ( new ConstantIntegerType ( COUNT_NORMAL ))-> isSuperTypeOf ( $ mode )-> result -> or ( $ argType -> getIterableValueType ()-> isArray ( )->negate () );
1132
+ return $ this -> create ( $ countFuncCall -> getArgs ()[ 0 ]-> value , $ resultType , $ context , $ scope )->setRootExpr ( $ rootExpr );
1144
1133
}
1145
1134
1146
1135
private function specifyTypesForConstantBinaryExpression (
@@ -2177,30 +2166,15 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
2177
2166
return $ specifiedTypes ;
2178
2167
}
2179
2168
2180
- if ($ context ->truthy ()) {
2181
- if ($ argType ->isArray ()->yes ()) {
2182
- if (
2183
- $ argType ->isConstantArray ()->yes ()
2184
- && $ rightType ->isSuperTypeOf ($ argType ->getArraySize ())->no ()
2185
- ) {
2186
- return $ this ->create ($ unwrappedLeftExpr ->getArgs ()[0 ]->value , new NeverType (), $ context , $ scope )->setRootExpr ($ expr );
2187
- }
2188
-
2189
- $ funcTypes = $ this ->create ($ unwrappedLeftExpr , $ rightType , $ context , $ scope )->setRootExpr ($ expr );
2190
- $ isNormalCount = $ this ->isFuncCallWithNormalCount ($ unwrappedLeftExpr , $ scope );
2191
- $ constArray = $ isNormalCount ->yes () ? $ this ->turnListIntoConstantArray ($ argType , $ rightType ) : null ;
2192
- if ($ constArray !== null ) {
2193
- return $ funcTypes ->unionWith (
2194
- $ this ->create ($ unwrappedLeftExpr ->getArgs ()[0 ]->value , $ constArray , $ context , $ scope )->setRootExpr ($ expr ),
2195
- );
2196
- } elseif (IntegerRangeType::fromInterval (1 , null )->isSuperTypeOf ($ rightType )->yes ()) {
2197
- return $ funcTypes ->unionWith (
2198
- $ this ->create ($ unwrappedLeftExpr ->getArgs ()[0 ]->value , new NonEmptyArrayType (), $ context , $ scope )->setRootExpr ($ expr ),
2199
- );
2200
- }
2201
-
2202
- return $ funcTypes ;
2169
+ if ($ context ->truthy () && $ argType ->isArray ()->yes ()) {
2170
+ $ funcTypes = $ this ->create ($ unwrappedLeftExpr , $ rightType , $ context , $ scope )->setRootExpr ($ expr );
2171
+ if (IntegerRangeType::fromInterval (1 , null )->isSuperTypeOf ($ rightType )->yes ()) {
2172
+ return $ funcTypes ->unionWith (
2173
+ $ this ->create ($ unwrappedLeftExpr ->getArgs ()[0 ]->value , new NonEmptyArrayType (), $ context , $ scope )->setRootExpr ($ expr ),
2174
+ );
2203
2175
}
2176
+
2177
+ return $ funcTypes ;
2204
2178
}
2205
2179
}
2206
2180
0 commit comments