@@ -56,6 +56,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
56
56
$ keyType = $ arrayArgType ->getIterableKeyType ();
57
57
$ itemType = $ arrayArgType ->getIterableValueType ();
58
58
59
+ if ($ itemType instanceof NeverType || $ keyType instanceof NeverType) {
60
+ return new ConstantArrayType ([], []);
61
+ }
62
+
59
63
if ($ arrayArgType instanceof MixedType) {
60
64
return new BenevolentUnionType ([
61
65
new ArrayType (new MixedType (), new MixedType ()),
@@ -73,52 +77,48 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
73
77
if ($ callbackArg instanceof Closure && count ($ callbackArg ->stmts ) === 1 && count ($ callbackArg ->params ) > 0 ) {
74
78
$ statement = $ callbackArg ->stmts [0 ];
75
79
if ($ statement instanceof Return_ && $ statement ->expr !== null ) {
76
- [ $ itemType , $ keyType ] = $ this ->filterByTruthyValue ($ scope , $ callbackArg ->params [0 ]->var , $ itemType , null , $ keyType , $ statement ->expr );
80
+ return $ this ->filterByTruthyValue ($ scope , $ callbackArg ->params [0 ]->var , $ arrayArgType , null , $ statement ->expr );
77
81
}
78
82
} elseif ($ callbackArg instanceof ArrowFunction && count ($ callbackArg ->params ) > 0 ) {
79
- [ $ itemType , $ keyType ] = $ this ->filterByTruthyValue ($ scope , $ callbackArg ->params [0 ]->var , $ itemType , null , $ keyType , $ callbackArg ->expr );
83
+ return $ this ->filterByTruthyValue ($ scope , $ callbackArg ->params [0 ]->var , $ arrayArgType , null , $ callbackArg ->expr );
80
84
} elseif ($ callbackArg instanceof String_) {
81
85
$ itemVar = new Variable ('item ' );
82
86
$ expr = new FuncCall (new Name ($ callbackArg ->value ), [new Arg ($ itemVar )]);
83
- [ $ itemType , $ keyType ] = $ this ->filterByTruthyValue ($ scope , $ itemVar , $ itemType , null , $ keyType , $ expr );
87
+ return $ this ->filterByTruthyValue ($ scope , $ itemVar , $ arrayArgType , null , $ expr );
84
88
}
85
89
}
86
90
87
91
if ($ flagArg instanceof ConstFetch && $ flagArg ->name ->parts [0 ] === 'ARRAY_FILTER_USE_KEY ' ) {
88
92
if ($ callbackArg instanceof Closure && count ($ callbackArg ->stmts ) === 1 && count ($ callbackArg ->params ) > 0 ) {
89
93
$ statement = $ callbackArg ->stmts [0 ];
90
94
if ($ statement instanceof Return_ && $ statement ->expr !== null ) {
91
- [ $ itemType , $ keyType ] = $ this ->filterByTruthyValue ($ scope , null , $ itemType , $ callbackArg ->params [0 ]->var , $ keyType , $ statement ->expr );
95
+ return $ this ->filterByTruthyValue ($ scope , null , $ arrayArgType , $ callbackArg ->params [0 ]->var , $ statement ->expr );
92
96
}
93
97
} elseif ($ callbackArg instanceof ArrowFunction && count ($ callbackArg ->params ) > 0 ) {
94
- [ $ itemType , $ keyType ] = $ this ->filterByTruthyValue ($ scope , null , $ itemType , $ callbackArg ->params [0 ]->var , $ keyType , $ callbackArg ->expr );
98
+ return $ this ->filterByTruthyValue ($ scope , null , $ arrayArgType , $ callbackArg ->params [0 ]->var , $ callbackArg ->expr );
95
99
} elseif ($ callbackArg instanceof String_) {
96
100
$ keyVar = new Variable ('key ' );
97
101
$ expr = new FuncCall (new Name ($ callbackArg ->value ), [new Arg ($ keyVar )]);
98
- [ $ itemType , $ keyType ] = $ this ->filterByTruthyValue ($ scope , null , $ itemType , $ keyVar, $ keyType , $ expr );
102
+ return $ this ->filterByTruthyValue ($ scope , null , $ arrayArgType , $ keyVar , $ expr );
99
103
}
100
104
}
101
105
102
106
if ($ flagArg instanceof ConstFetch && $ flagArg ->name ->parts [0 ] === 'ARRAY_FILTER_USE_BOTH ' ) {
103
107
if ($ callbackArg instanceof Closure && count ($ callbackArg ->stmts ) === 1 && count ($ callbackArg ->params ) > 0 ) {
104
108
$ statement = $ callbackArg ->stmts [0 ];
105
109
if ($ statement instanceof Return_ && $ statement ->expr !== null ) {
106
- [ $ itemType , $ keyType ] = $ this ->filterByTruthyValue ($ scope , $ callbackArg ->params [0 ]->var , $ itemType , $ callbackArg ->params [1 ]->var ?? null , $ keyType , $ statement ->expr );
110
+ return $ this ->filterByTruthyValue ($ scope , $ callbackArg ->params [0 ]->var , $ arrayArgType , $ callbackArg ->params [1 ]->var ?? null , $ statement ->expr );
107
111
}
108
112
} elseif ($ callbackArg instanceof ArrowFunction && count ($ callbackArg ->params ) > 0 ) {
109
- [ $ itemType , $ keyType ] = $ this ->filterByTruthyValue ($ scope , $ callbackArg ->params [0 ]->var , $ itemType , $ callbackArg ->params [1 ]->var ?? null , $ keyType , $ callbackArg ->expr );
113
+ return $ this ->filterByTruthyValue ($ scope , $ callbackArg ->params [0 ]->var , $ arrayArgType , $ callbackArg ->params [1 ]->var ?? null , $ callbackArg ->expr );
110
114
} elseif ($ callbackArg instanceof String_) {
111
115
$ itemVar = new Variable ('item ' );
112
116
$ keyVar = new Variable ('key ' );
113
117
$ expr = new FuncCall (new Name ($ callbackArg ->value ), [new Arg ($ itemVar ), new Arg ($ keyVar )]);
114
- [ $ itemType , $ keyType ] = $ this ->filterByTruthyValue ($ scope , $ itemVar , $ itemType , $ keyVar, $ keyType , $ expr );
118
+ return $ this ->filterByTruthyValue ($ scope , $ itemVar , $ arrayArgType , $ keyVar , $ expr );
115
119
}
116
120
}
117
121
118
- if ($ itemType instanceof NeverType || $ keyType instanceof NeverType) {
119
- return new ConstantArrayType ([], []);
120
- }
121
-
122
122
return new ArrayType ($ keyType , $ itemType );
123
123
}
124
124
@@ -157,15 +157,51 @@ public function removeFalsey(Type $type): Type
157
157
return new ArrayType ($ keyType , $ valueType );
158
158
}
159
159
160
- /**
161
- * @return array{Type, Type}
162
- */
163
- private function filterByTruthyValue (Scope $ scope , Error |Variable |null $ itemVar , Type $ itemType , Error |Variable |null $ keyVar , Type $ keyType , Expr $ expr ): array
160
+ private function filterByTruthyValue (Scope $ scope , Error |Variable |null $ itemVar , Type $ arrayType , Error |Variable |null $ keyVar , Expr $ expr ): Type
164
161
{
165
162
if (!$ scope instanceof MutatingScope) {
166
163
throw new ShouldNotHappenException ();
167
164
}
168
165
166
+ $ constantArrays = TypeUtils::getOldConstantArrays ($ arrayType );
167
+ if (count ($ constantArrays ) > 0 ) {
168
+ $ results = [];
169
+ foreach ($ constantArrays as $ constantArray ) {
170
+ $ builder = ConstantArrayTypeBuilder::createEmpty ();
171
+ foreach ($ constantArray ->getKeyTypes () as $ i => $ keyType ) {
172
+ $ itemType = $ constantArray ->getValueTypes ()[$ i ];
173
+ [$ newKeyType , $ newItemType ] = $ this ->processKeyAndItemType ($ scope , $ keyType , $ itemType , $ itemVar , $ keyVar , $ expr );
174
+ if ($ newKeyType instanceof NeverType || $ newItemType instanceof NeverType) {
175
+ continue ;
176
+ }
177
+ if ($ itemType ->equals ($ newItemType ) && $ keyType ->equals ($ newKeyType )) {
178
+ $ builder ->setOffsetValueType ($ keyType , $ itemType );
179
+ continue ;
180
+ }
181
+
182
+ $ builder ->setOffsetValueType ($ newKeyType , $ newItemType , true );
183
+ }
184
+
185
+ $ results [] = $ builder ->getArray ();
186
+ }
187
+
188
+ return TypeCombinator::union (...$ results );
189
+ }
190
+
191
+ [$ newKeyType , $ newItemType ] = $ this ->processKeyAndItemType ($ scope , $ arrayType ->getIterableKeyType (), $ arrayType ->getIterableValueType (), $ itemVar , $ keyVar , $ expr );
192
+
193
+ if ($ newItemType instanceof NeverType || $ newKeyType instanceof NeverType) {
194
+ return new ConstantArrayType ([], []);
195
+ }
196
+
197
+ return new ArrayType ($ newKeyType , $ newItemType );
198
+ }
199
+
200
+ /**
201
+ * @return array{Type, Type}
202
+ */
203
+ private function processKeyAndItemType (MutatingScope $ scope , Type $ keyType , Type $ itemType , Error |Variable |null $ itemVar , Error |Variable |null $ keyVar , Expr $ expr ): array
204
+ {
169
205
$ itemVarName = null ;
170
206
if ($ itemVar !== null ) {
171
207
if (!$ itemVar instanceof Variable || !is_string ($ itemVar ->name )) {
@@ -187,8 +223,8 @@ private function filterByTruthyValue(Scope $scope, Error|Variable|null $itemVar,
187
223
$ scope = $ scope ->filterByTruthyValue ($ expr );
188
224
189
225
return [
190
- $ itemVarName !== null ? $ scope ->getVariableType ($ itemVarName ) : $ itemType ,
191
226
$ keyVarName !== null ? $ scope ->getVariableType ($ keyVarName ) : $ keyType ,
227
+ $ itemVarName !== null ? $ scope ->getVariableType ($ itemVarName ) : $ itemType ,
192
228
];
193
229
}
194
230
0 commit comments