Skip to content

Commit

Permalink
Limit the depth when resolving closure type for performance reasons
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jul 6, 2024
1 parent 7c61b03 commit 2c08dfa
Showing 1 changed file with 54 additions and 39 deletions.
93 changes: 54 additions & 39 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ class MutatingScope implements Scope

private ?self $scopeWithPromotedNativeTypes = null;

private static int $resolveClosureTypeDepth = 0;

/**
* @param array<string, ExpressionTypeHolder> $expressionTypes
* @param array<string, ConditionalExpressionHolder[]> $conditionalExpressions
Expand Down Expand Up @@ -1322,56 +1324,69 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu
$closureExecutionEnds = [];
$closureImpurePoints = [];
$invalidateExpressions = [];
$closureStatementResult = $this->nodeScopeResolver->processStmtNodes($node, $node->stmts, $closureScope, static function (Node $node, Scope $scope) use ($closureScope, &$closureReturnStatements, &$closureYieldStatements, &$closureExecutionEnds, &$closureImpurePoints, &$invalidateExpressions): void {
if ($scope->getAnonymousFunctionReflection() !== $closureScope->getAnonymousFunctionReflection()) {
return;
}
if (self::$resolveClosureTypeDepth >= 2) {
return new ClosureType(
$parameters,
$this->getFunctionType($node->returnType, false, false),
$isVariadic,
);
}

if ($node instanceof InvalidateExprNode) {
$invalidateExpressions[] = $node;
return;
}
self::$resolveClosureTypeDepth++;
try {
$closureStatementResult = $this->nodeScopeResolver->processStmtNodes($node, $node->stmts, $closureScope, static function (Node $node, Scope $scope) use ($closureScope, &$closureReturnStatements, &$closureYieldStatements, &$closureExecutionEnds, &$closureImpurePoints, &$invalidateExpressions): void {
if ($scope->getAnonymousFunctionReflection() !== $closureScope->getAnonymousFunctionReflection()) {
return;
}

if ($node instanceof PropertyAssignNode) {
$closureImpurePoints[] = new ImpurePoint(
$scope,
$node,
'propertyAssign',
'property assignment',
true,
);
return;
}
if ($node instanceof InvalidateExprNode) {
$invalidateExpressions[] = $node;
return;
}

if ($node instanceof PropertyAssignNode) {
$closureImpurePoints[] = new ImpurePoint(
$scope,
$node,
'propertyAssign',
'property assignment',
true,
);
return;
}

if ($node instanceof ExecutionEndNode) {
if ($node->getStatementResult()->isAlwaysTerminating()) {
foreach ($node->getStatementResult()->getExitPoints() as $exitPoint) {
if ($exitPoint->getStatement() instanceof Node\Stmt\Return_) {
continue;
if ($node instanceof ExecutionEndNode) {
if ($node->getStatementResult()->isAlwaysTerminating()) {
foreach ($node->getStatementResult()->getExitPoints() as $exitPoint) {
if ($exitPoint->getStatement() instanceof Node\Stmt\Return_) {
continue;
}

$closureExecutionEnds[] = $node;
break;
}

$closureExecutionEnds[] = $node;
break;
if (count($node->getStatementResult()->getExitPoints()) === 0) {
$closureExecutionEnds[] = $node;
}
}

if (count($node->getStatementResult()->getExitPoints()) === 0) {
$closureExecutionEnds[] = $node;
}
return;
}

return;
}

if ($node instanceof Node\Stmt\Return_) {
$closureReturnStatements[] = [$node, $scope];
}
if ($node instanceof Node\Stmt\Return_) {
$closureReturnStatements[] = [$node, $scope];
}

if (!$node instanceof Expr\Yield_ && !$node instanceof Expr\YieldFrom) {
return;
}
if (!$node instanceof Expr\Yield_ && !$node instanceof Expr\YieldFrom) {
return;
}

$closureYieldStatements[] = [$node, $scope];
}, StatementContext::createTopLevel());
$closureYieldStatements[] = [$node, $scope];
}, StatementContext::createTopLevel());
} finally {
self::$resolveClosureTypeDepth--;
}

$throwPoints = $closureStatementResult->getThrowPoints();
$impurePoints = array_merge($closureImpurePoints, $closureStatementResult->getImpurePoints());
Expand Down

0 comments on commit 2c08dfa

Please sign in to comment.