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 ;
@@ -2965,7 +2981,7 @@ public function createCallableParameters(Scope $scope, Expr $closureExpr, ?array
29652981 continue ;
29662982 }
29672983
2968- $ type = $ scope -> getType ( $ args [$ index ]->value );
2984+ $ type = $ typeGetter ( $ scope , $ args [$ index ]->value );
29692985 $ callableParameters [$ index ] = new NativeParameterReflection (
29702986 $ callableParameter ->getName (),
29712987 $ callableParameter ->isOptional (),
@@ -3383,7 +3399,7 @@ public function processArgs(
33833399 }
33843400
33853401 $ this ->callNodeCallbackWithExpression ($ nodeCallback , $ arg ->value , $ scopeToPass , $ storage , $ context );
3386- $ closureResult = $ this ->processClosureNode ($ stmt , $ arg ->value , $ scopeToPass , $ storage , $ nodeCallback , $ context , $ parameterType ?? null );
3402+ $ closureResult = $ this ->processClosureNode ($ stmt , $ arg ->value , $ scopeToPass , $ storage , $ nodeCallback , $ context , $ parameterType ?? null , $ parameterNativeType );
33873403 if ($ this ->callCallbackImmediately ($ parameter , $ parameterType , $ calleeReflection )) {
33883404 $ 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 ()));
33893405 $ impurePoints = array_merge ($ impurePoints , $ closureResult ->getImpurePoints ());
@@ -3442,7 +3458,7 @@ public function processArgs(
34423458 }
34433459
34443460 $ this ->callNodeCallbackWithExpression ($ nodeCallback , $ arg ->value , $ scopeToPass , $ storage , $ context );
3445- $ arrowFunctionResult = $ this ->processArrowFunctionNode ($ stmt , $ arg ->value , $ scopeToPass , $ storage , $ nodeCallback , $ parameterType ?? null );
3461+ $ arrowFunctionResult = $ this ->processArrowFunctionNode ($ stmt , $ arg ->value , $ scopeToPass , $ storage , $ nodeCallback , $ parameterType ?? null , $ parameterNativeType );
34463462 if ($ this ->callCallbackImmediately ($ parameter , $ parameterType , $ calleeReflection )) {
34473463 $ 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 ()));
34483464 $ impurePoints = array_merge ($ impurePoints , $ arrowFunctionResult ->getImpurePoints ());
0 commit comments