@@ -2021,7 +2021,7 @@ public function enterAnonymousFunctionWithoutReflection(
20212021 $ isNullable = $ this ->isParameterValueNullable ($ parameter );
20222022 $ parameterType = $ this ->getFunctionType ($ parameter ->type , $ isNullable , $ parameter ->variadic );
20232023 if ($ callableParameters !== null ) {
2024- $ parameterType = self ::intersectButNotNever ($ parameterType , $ this ->getCallableParameterType ($ callableParameters , $ i ));
2024+ $ parameterType = self ::intersectButNotNever ($ parameterType , $ this ->getCallableParameterType ($ parameter , $ callableParameters , $ i ));
20252025 }
20262026 $ holder = ExpressionTypeHolder::createYes ($ parameter ->var , $ parameterType );
20272027 $ expressionTypes [$ paramExprString ] = $ holder ;
@@ -2221,7 +2221,7 @@ public function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFun
22212221 $ isNullable = $ this ->isParameterValueNullable ($ parameter );
22222222 $ parameterType = $ this ->getFunctionType ($ parameter ->type , $ isNullable , $ parameter ->variadic );
22232223 if ($ callableParameters !== null ) {
2224- $ parameterType = self ::intersectButNotNever ($ parameterType , $ this ->getCallableParameterType ($ callableParameters , $ i ));
2224+ $ parameterType = self ::intersectButNotNever ($ parameterType , $ this ->getCallableParameterType ($ parameter , $ callableParameters , $ i ));
22252225 }
22262226
22272227 if (!$ parameter ->var instanceof Variable || !is_string ($ parameter ->var ->name )) {
@@ -2290,8 +2290,12 @@ public function getFunctionType($type, bool $isNullable, bool $isVariadic): Type
22902290 /**
22912291 * @param ParameterReflection[] $callableParameters
22922292 */
2293- private function getCallableParameterType (array $ callableParameters , int $ index ): Type
2293+ private function getCallableParameterType (Node \ Param $ parameter , array $ callableParameters , int $ index ): Type
22942294 {
2295+ if ($ parameter ->variadic ) {
2296+ return $ this ->buildVariadicArrayTypeFromCallableParameters ($ callableParameters , $ index );
2297+ }
2298+
22952299 if (isset ($ callableParameters [$ index ])) {
22962300 return $ callableParameters [$ index ]->getType ();
22972301 }
@@ -2308,6 +2312,40 @@ private function getCallableParameterType(array $callableParameters, int $index)
23082312 return new MixedType ();
23092313 }
23102314
2315+ /**
2316+ * @param array<ParameterReflection> $callableParameters
2317+ */
2318+ private function buildVariadicArrayTypeFromCallableParameters (array $ callableParameters , int $ startIndex ): Type
2319+ {
2320+ $ elementTypes = [];
2321+ $ callableParametersCount = count ($ callableParameters );
2322+ for ($ j = $ startIndex ; $ j < $ callableParametersCount ; $ j ++) {
2323+ $ elementTypes [] = $ callableParameters [$ j ]->getType ();
2324+ if ($ callableParameters [$ j ]->isVariadic ()) {
2325+ break ;
2326+ }
2327+ }
2328+
2329+ if ($ elementTypes === [] && $ callableParametersCount > 0 ) {
2330+ $ lastParameter = array_last ($ callableParameters );
2331+ if ($ lastParameter ->isVariadic ()) {
2332+ $ elementTypes [] = $ lastParameter ->getType ();
2333+ }
2334+ }
2335+
2336+ if ($ elementTypes === []) {
2337+ return new MixedType ();
2338+ }
2339+
2340+ $ elementType = TypeCombinator::union (...$ elementTypes );
2341+
2342+ if (!$ this ->getPhpVersion ()->supportsNamedArguments ()->no ()) {
2343+ return new ArrayType (new UnionType ([new IntegerType (), new StringType ()]), $ elementType );
2344+ }
2345+
2346+ return new IntersectionType ([new ArrayType (IntegerRangeType::createAllGreaterThanOrEqualTo (0 ), $ elementType ), new AccessoryArrayListType ()]);
2347+ }
2348+
23112349 public static function intersectButNotNever (Type $ nativeType , Type $ inferredType ): Type
23122350 {
23132351 if ($ nativeType ->isSuperTypeOf ($ inferredType )->no ()) {
0 commit comments