Skip to content

Commit 2c08dfa

Browse files
committed
Limit the depth when resolving closure type for performance reasons
1 parent 7c61b03 commit 2c08dfa

File tree

1 file changed

+54
-39
lines changed

1 file changed

+54
-39
lines changed

src/Analyser/MutatingScope.php

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ class MutatingScope implements Scope
180180

181181
private ?self $scopeWithPromotedNativeTypes = null;
182182

183+
private static int $resolveClosureTypeDepth = 0;
184+
183185
/**
184186
* @param array<string, ExpressionTypeHolder> $expressionTypes
185187
* @param array<string, ConditionalExpressionHolder[]> $conditionalExpressions
@@ -1322,56 +1324,69 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu
13221324
$closureExecutionEnds = [];
13231325
$closureImpurePoints = [];
13241326
$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+
}
13291334

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+
}
13341341

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+
}
13451357

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;
13511367
}
13521368

1353-
$closureExecutionEnds[] = $node;
1354-
break;
1369+
if (count($node->getStatementResult()->getExitPoints()) === 0) {
1370+
$closureExecutionEnds[] = $node;
1371+
}
13551372
}
13561373

1357-
if (count($node->getStatementResult()->getExitPoints()) === 0) {
1358-
$closureExecutionEnds[] = $node;
1359-
}
1374+
return;
13601375
}
13611376

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+
}
13681380

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+
}
13721384

1373-
$closureYieldStatements[] = [$node, $scope];
1374-
}, StatementContext::createTopLevel());
1385+
$closureYieldStatements[] = [$node, $scope];
1386+
}, StatementContext::createTopLevel());
1387+
} finally {
1388+
self::$resolveClosureTypeDepth--;
1389+
}
13751390

13761391
$throwPoints = $closureStatementResult->getThrowPoints();
13771392
$impurePoints = array_merge($closureImpurePoints, $closureStatementResult->getImpurePoints());

0 commit comments

Comments
 (0)