131131use PHPStan \Reflection \ParameterReflection ;
132132use PHPStan \Reflection \ParametersAcceptor ;
133133use PHPStan \Reflection \ParametersAcceptorSelector ;
134+ use PHPStan \Reflection \PassedByReference ;
135+ use PHPStan \Reflection \Php \DummyParameter ;
134136use PHPStan \Reflection \Php \PhpFunctionFromParserNodeReflection ;
135137use PHPStan \Reflection \Php \PhpMethodFromParserNodeReflection ;
136138use PHPStan \Reflection \Php \PhpMethodReflection ;
@@ -2704,6 +2706,7 @@ public function processClosureNode(
27042706 callable $ nodeCallback ,
27052707 ExpressionContext $ context ,
27062708 ?Type $ passedToType ,
2709+ ?Type $ nativePassedToType = null ,
27072710 ): ProcessClosureResult
27082711 {
27092712 foreach ($ expr ->params as $ param ) {
@@ -2713,12 +2716,8 @@ public function processClosureNode(
27132716 $ byRefUses = [];
27142717
27152718 $ closureCallArgs = $ expr ->getAttribute (ClosureArgVisitor::ATTRIBUTE_NAME );
2716- $ callableParameters = $ this ->createCallableParameters (
2717- $ scope ,
2718- $ expr ,
2719- $ closureCallArgs ,
2720- $ passedToType ,
2721- );
2719+ $ callableParameters = $ this ->createCallableParameters ($ scope , $ expr , $ closureCallArgs , $ passedToType );
2720+ $ nativeCallableParameters = $ this ->createNativeCallableParameters ($ scope , $ expr , $ closureCallArgs , $ nativePassedToType );
27222721
27232722 $ useScope = $ scope ;
27242723 foreach ($ expr ->uses as $ use ) {
@@ -2769,7 +2768,7 @@ public function processClosureNode(
27692768 $ this ->callNodeCallback ($ nodeCallback , $ expr ->returnType , $ scope , $ storage );
27702769 }
27712770
2772- $ closureScope = $ scope ->enterAnonymousFunction ($ expr , $ callableParameters );
2771+ $ closureScope = $ scope ->enterAnonymousFunction ($ expr , $ callableParameters, $ nativeCallableParameters );
27732772 $ closureScope = $ closureScope ->processClosureScope ($ scope , null , $ byRefUses );
27742773 $ closureType = $ closureScope ->getAnonymousFunctionReflection ();
27752774 if (!$ closureType instanceof ClosureType) {
@@ -2851,7 +2850,7 @@ public function processClosureNode(
28512850 break ;
28522851 }
28532852
2854- $ closureScope = $ scope ->enterAnonymousFunction ($ expr , $ callableParameters );
2853+ $ closureScope = $ scope ->enterAnonymousFunction ($ expr , $ callableParameters, $ nativeCallableParameters );
28552854 $ closureScope = $ closureScope ->processClosureScope ($ intermediaryClosureScope , $ prevScope , $ byRefUses );
28562855
28572856 if ($ closureScope ->equals ($ prevScope )) {
@@ -2916,6 +2915,7 @@ public function processArrowFunctionNode(
29162915 ExpressionResultStorage $ storage ,
29172916 callable $ nodeCallback ,
29182917 ?Type $ passedToType ,
2918+ ?Type $ nativePassedToType = null ,
29192919 ): ExpressionResult
29202920 {
29212921 foreach ($ expr ->params as $ param ) {
@@ -2926,12 +2926,9 @@ public function processArrowFunctionNode(
29262926 }
29272927
29282928 $ arrowFunctionCallArgs = $ expr ->getAttribute (ArrowFunctionArgVisitor::ATTRIBUTE_NAME );
2929- $ arrowFunctionScope = $ scope ->enterArrowFunction ($ expr , $ this ->createCallableParameters (
2930- $ scope ,
2931- $ expr ,
2932- $ arrowFunctionCallArgs ,
2933- $ passedToType ,
2934- ));
2929+ $ callableParameters = $ this ->createCallableParameters ($ scope , $ expr , $ arrowFunctionCallArgs , $ passedToType );
2930+ $ nativeCallableParameters = $ this ->createNativeCallableParameters ($ scope , $ expr , $ arrowFunctionCallArgs , $ nativePassedToType );
2931+ $ arrowFunctionScope = $ scope ->enterArrowFunction ($ expr , $ callableParameters , $ nativeCallableParameters );
29352932 $ arrowFunctionType = $ arrowFunctionScope ->getAnonymousFunctionReflection ();
29362933 if ($ arrowFunctionType === null ) {
29372934 throw new ShouldNotHappenException ();
@@ -2943,14 +2940,33 @@ public function processArrowFunctionNode(
29432940 }
29442941
29452942 /**
2946- * @param Node\Arg[] $args
2943+ * @param Node\Arg[]|null $args
29472944 * @return ParameterReflection[]|null
29482945 */
29492946 public function createCallableParameters (Scope $ scope , Expr $ closureExpr , ?array $ args , ?Type $ passedToType ): ?array
2947+ {
2948+ return $ this ->doCreateCallableParameters ($ scope , $ closureExpr , $ args , $ passedToType , static fn (Scope $ s , Expr $ e ) => $ s ->getType ($ e ));
2949+ }
2950+
2951+ /**
2952+ * @param Node\Arg[]|null $args
2953+ * @return ParameterReflection[]|null
2954+ */
2955+ public function createNativeCallableParameters (Scope $ scope , Expr $ closureExpr , ?array $ args , ?Type $ nativePassedToType ): ?array
2956+ {
2957+ return $ this ->doCreateCallableParameters ($ scope , $ closureExpr , $ args , $ nativePassedToType , static fn (Scope $ s , Expr $ e ) => $ s ->getNativeType ($ e ));
2958+ }
2959+
2960+ /**
2961+ * @param Node\Arg[]|null $args
2962+ * @param Closure(Scope, Expr): Type $typeGetter
2963+ * @return ParameterReflection[]|null
2964+ */
2965+ private function doCreateCallableParameters (Scope $ scope , Expr $ closureExpr , ?array $ args , ?Type $ passedToType , Closure $ typeGetter ): ?array
29502966 {
29512967 $ callableParameters = null ;
29522968 if ($ args !== null ) {
2953- $ closureType = $ scope -> getType ( $ closureExpr );
2969+ $ closureType = $ typeGetter ( $ scope , $ closureExpr );
29542970
29552971 if ($ closureType ->isCallable ()->no ()) {
29562972 return null ;
@@ -2967,12 +2983,13 @@ public function createCallableParameters(Scope $scope, Expr $closureExpr, ?array
29672983
29682984 if ($ callableParameter ->isVariadic ()) {
29692985 $ argTypes = [];
2970- for ($ j = $ index ; $ j < count ($ args ); $ j ++) {
2971- $ argTypes [] = $ scope ->getType ($ args [$ j ]->value );
2986+ $ argNumber = count ($ args );
2987+ for ($ j = $ index ; $ j < $ argNumber ; $ j ++) {
2988+ $ argTypes [] = $ typeGetter ($ scope , $ args [$ j ]->value );
29722989 }
29732990 $ type = TypeCombinator::union (...$ argTypes );
29742991 } else {
2975- $ type = $ scope -> getType ( $ args [$ index ]->value );
2992+ $ type = $ typeGetter ( $ scope , $ args [$ index ]->value );
29762993 }
29772994 $ callableParameters [$ index ] = new NativeParameterReflection (
29782995 $ callableParameter ->getName (),
@@ -3391,7 +3408,7 @@ public function processArgs(
33913408 }
33923409
33933410 $ this ->callNodeCallbackWithExpression ($ nodeCallback , $ arg ->value , $ scopeToPass , $ storage , $ context );
3394- $ closureResult = $ this ->processClosureNode ($ stmt , $ arg ->value , $ scopeToPass , $ storage , $ nodeCallback , $ context , $ parameterType ?? null );
3411+ $ closureResult = $ this ->processClosureNode ($ stmt , $ arg ->value , $ scopeToPass , $ storage , $ nodeCallback , $ context , $ parameterType ?? null , $ parameterNativeType );
33953412 if ($ this ->callCallbackImmediately ($ parameter , $ parameterType , $ calleeReflection )) {
33963413 $ throwPoints = array_merge ($ throwPoints , array_map (static fn (InternalThrowPoint $ throwPoint ) => $ throwPoint ->isExplicit () ? InternalThrowPoint::createExplicit ($ scope , $ throwPoint ->getType (), $ arg ->value , $ throwPoint ->canContainAnyThrowable ()) : InternalThrowPoint::createImplicit ($ scope , $ arg ->value ), $ closureResult ->getThrowPoints ()));
33973414 $ impurePoints = array_merge ($ impurePoints , $ closureResult ->getImpurePoints ());
@@ -3450,7 +3467,7 @@ public function processArgs(
34503467 }
34513468
34523469 $ this ->callNodeCallbackWithExpression ($ nodeCallback , $ arg ->value , $ scopeToPass , $ storage , $ context );
3453- $ arrowFunctionResult = $ this ->processArrowFunctionNode ($ stmt , $ arg ->value , $ scopeToPass , $ storage , $ nodeCallback , $ parameterType ?? null );
3470+ $ arrowFunctionResult = $ this ->processArrowFunctionNode ($ stmt , $ arg ->value , $ scopeToPass , $ storage , $ nodeCallback , $ parameterType ?? null , $ parameterNativeType );
34543471 if ($ this ->callCallbackImmediately ($ parameter , $ parameterType , $ calleeReflection )) {
34553472 $ throwPoints = array_merge ($ throwPoints , array_map (static fn (InternalThrowPoint $ throwPoint ) => $ throwPoint ->isExplicit () ? InternalThrowPoint::createExplicit ($ scope , $ throwPoint ->getType (), $ arg ->value , $ throwPoint ->canContainAnyThrowable ()) : InternalThrowPoint::createImplicit ($ scope , $ arg ->value ), $ arrowFunctionResult ->getThrowPoints ()));
34563473 $ impurePoints = array_merge ($ impurePoints , $ arrowFunctionResult ->getImpurePoints ());
0 commit comments