@@ -180,6 +180,8 @@ class MutatingScope implements Scope
180
180
181
181
private ?self $ scopeWithPromotedNativeTypes = null ;
182
182
183
+ private static int $ resolveClosureTypeDepth = 0 ;
184
+
183
185
/**
184
186
* @param array<string, ExpressionTypeHolder> $expressionTypes
185
187
* @param array<string, ConditionalExpressionHolder[]> $conditionalExpressions
@@ -1322,56 +1324,69 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu
1322
1324
$ closureExecutionEnds = [];
1323
1325
$ closureImpurePoints = [];
1324
1326
$ invalidateExpressions = [];
1325
- $ closureStatementResult = $ this ->nodeScopeResolver ->processStmtNodes ($ node , $ node ->stmts , $ closureScope , static function (Node $ node , Scope $ scope ) use ($ closureScope , &$ closureReturnStatements , &$ closureYieldStatements , &$ closureExecutionEnds , &$ closureImpurePoints , &$ invalidateExpressions ): void {
1326
- if ($ scope ->getAnonymousFunctionReflection () !== $ closureScope ->getAnonymousFunctionReflection ()) {
1327
- return ;
1328
- }
1327
+ if (self ::$ resolveClosureTypeDepth >= 2 ) {
1328
+ return new ClosureType (
1329
+ $ parameters ,
1330
+ $ this ->getFunctionType ($ node ->returnType , false , false ),
1331
+ $ isVariadic ,
1332
+ );
1333
+ }
1329
1334
1330
- if ($ node instanceof InvalidateExprNode) {
1331
- $ invalidateExpressions [] = $ node ;
1332
- return ;
1333
- }
1335
+ self ::$ resolveClosureTypeDepth ++;
1336
+ try {
1337
+ $ closureStatementResult = $ this ->nodeScopeResolver ->processStmtNodes ($ node , $ node ->stmts , $ closureScope , static function (Node $ node , Scope $ scope ) use ($ closureScope , &$ closureReturnStatements , &$ closureYieldStatements , &$ closureExecutionEnds , &$ closureImpurePoints , &$ invalidateExpressions ): void {
1338
+ if ($ scope ->getAnonymousFunctionReflection () !== $ closureScope ->getAnonymousFunctionReflection ()) {
1339
+ return ;
1340
+ }
1334
1341
1335
- if ($ node instanceof PropertyAssignNode) {
1336
- $ closureImpurePoints [] = new ImpurePoint (
1337
- $ scope ,
1338
- $ node ,
1339
- 'propertyAssign ' ,
1340
- 'property assignment ' ,
1341
- true ,
1342
- );
1343
- return ;
1344
- }
1342
+ if ($ node instanceof InvalidateExprNode) {
1343
+ $ invalidateExpressions [] = $ node ;
1344
+ return ;
1345
+ }
1346
+
1347
+ if ($ node instanceof PropertyAssignNode) {
1348
+ $ closureImpurePoints [] = new ImpurePoint (
1349
+ $ scope ,
1350
+ $ node ,
1351
+ 'propertyAssign ' ,
1352
+ 'property assignment ' ,
1353
+ true ,
1354
+ );
1355
+ return ;
1356
+ }
1345
1357
1346
- if ($ node instanceof ExecutionEndNode) {
1347
- if ($ node ->getStatementResult ()->isAlwaysTerminating ()) {
1348
- foreach ($ node ->getStatementResult ()->getExitPoints () as $ exitPoint ) {
1349
- if ($ exitPoint ->getStatement () instanceof Node \Stmt \Return_) {
1350
- continue ;
1358
+ if ($ node instanceof ExecutionEndNode) {
1359
+ if ($ node ->getStatementResult ()->isAlwaysTerminating ()) {
1360
+ foreach ($ node ->getStatementResult ()->getExitPoints () as $ exitPoint ) {
1361
+ if ($ exitPoint ->getStatement () instanceof Node \Stmt \Return_) {
1362
+ continue ;
1363
+ }
1364
+
1365
+ $ closureExecutionEnds [] = $ node ;
1366
+ break ;
1351
1367
}
1352
1368
1353
- $ closureExecutionEnds [] = $ node ;
1354
- break ;
1369
+ if (count ($ node ->getStatementResult ()->getExitPoints ()) === 0 ) {
1370
+ $ closureExecutionEnds [] = $ node ;
1371
+ }
1355
1372
}
1356
1373
1357
- if (count ($ node ->getStatementResult ()->getExitPoints ()) === 0 ) {
1358
- $ closureExecutionEnds [] = $ node ;
1359
- }
1374
+ return ;
1360
1375
}
1361
1376
1362
- return ;
1363
- }
1364
-
1365
- if ($ node instanceof Node \Stmt \Return_) {
1366
- $ closureReturnStatements [] = [$ node , $ scope ];
1367
- }
1377
+ if ($ node instanceof Node \Stmt \Return_) {
1378
+ $ closureReturnStatements [] = [$ node , $ scope ];
1379
+ }
1368
1380
1369
- if (!$ node instanceof Expr \Yield_ && !$ node instanceof Expr \YieldFrom) {
1370
- return ;
1371
- }
1381
+ if (!$ node instanceof Expr \Yield_ && !$ node instanceof Expr \YieldFrom) {
1382
+ return ;
1383
+ }
1372
1384
1373
- $ closureYieldStatements [] = [$ node , $ scope ];
1374
- }, StatementContext::createTopLevel ());
1385
+ $ closureYieldStatements [] = [$ node , $ scope ];
1386
+ }, StatementContext::createTopLevel ());
1387
+ } finally {
1388
+ self ::$ resolveClosureTypeDepth --;
1389
+ }
1375
1390
1376
1391
$ throwPoints = $ closureStatementResult ->getThrowPoints ();
1377
1392
$ impurePoints = array_merge ($ closureImpurePoints , $ closureStatementResult ->getImpurePoints ());
0 commit comments