diff --git a/src/Analyser/ExpressionResultStorage.php b/src/Analyser/ExpressionResultStorage.php index 72375b1a88..ae13c74228 100644 --- a/src/Analyser/ExpressionResultStorage.php +++ b/src/Analyser/ExpressionResultStorage.php @@ -4,44 +4,38 @@ use Fiber; use PhpParser\Node\Expr; -use PHPStan\Analyser\Fiber\ExpressionAnalysisRequest; -use PHPStan\ShouldNotHappenException; +use PHPStan\Analyser\Fiber\BeforeScopeForExprRequest; use SplObjectStorage; -use function get_class; -use function sprintf; final class ExpressionResultStorage { - /** @var SplObjectStorage */ - private SplObjectStorage $results; + /** @var SplObjectStorage */ + private SplObjectStorage $scopes; - /** @var array, request: ExpressionAnalysisRequest}> */ + /** @var array, request: BeforeScopeForExprRequest}> */ public array $pendingFibers = []; public function __construct() { - $this->results = new SplObjectStorage(); + $this->scopes = new SplObjectStorage(); } public function duplicate(): self { $new = new self(); - $new->results->addAll($this->results); + $new->scopes->addAll($this->scopes); return $new; } - public function storeResult(Expr $expr, ExpressionResult $result): void + public function storeBeforeScope(Expr $expr, Scope $scope): void { - if (isset($this->results[$expr])) { - throw new ShouldNotHappenException(sprintf('already stored %s on line %d', get_class($expr), $expr->getStartLine())); - } - $this->results[$expr] = $result; + $this->scopes[$expr] = $scope; } - public function findResult(Expr $expr): ?ExpressionResult + public function findBeforeScope(Expr $expr): ?Scope { - return $this->results[$expr] ?? null; + return $this->scopes[$expr] ?? null; } } diff --git a/src/Analyser/Fiber/ExpressionAnalysisRequest.php b/src/Analyser/Fiber/BeforeScopeForExprRequest.php similarity index 86% rename from src/Analyser/Fiber/ExpressionAnalysisRequest.php rename to src/Analyser/Fiber/BeforeScopeForExprRequest.php index 0c015a00c6..0fc6ecd35c 100644 --- a/src/Analyser/Fiber/ExpressionAnalysisRequest.php +++ b/src/Analyser/Fiber/BeforeScopeForExprRequest.php @@ -5,7 +5,7 @@ use PhpParser\Node\Expr; use PHPStan\Analyser\MutatingScope; -final class ExpressionAnalysisRequest +final class BeforeScopeForExprRequest { public function __construct(public readonly Expr $expr, public readonly MutatingScope $scope) diff --git a/src/Analyser/Fiber/FiberNodeScopeResolver.php b/src/Analyser/Fiber/FiberNodeScopeResolver.php index 7aeaf8bada..bbbb2a750e 100644 --- a/src/Analyser/Fiber/FiberNodeScopeResolver.php +++ b/src/Analyser/Fiber/FiberNodeScopeResolver.php @@ -6,7 +6,6 @@ use PhpParser\Node; use PhpParser\Node\Expr; use PHPStan\Analyser\ExpressionContext; -use PHPStan\Analyser\ExpressionResult; use PHPStan\Analyser\ExpressionResultStorage; use PHPStan\Analyser\MutatingScope; use PHPStan\Analyser\NodeScopeResolver; @@ -40,19 +39,19 @@ protected function callNodeCallback( } /** - * @param Fiber $fiber + * @param Fiber $fiber */ private function runFiberForNodeCallback( ExpressionResultStorage $storage, Fiber $fiber, - ?ExpressionAnalysisRequest $request, + ?BeforeScopeForExprRequest $request, ): void { while (!$fiber->isTerminated()) { - if ($request instanceof ExpressionAnalysisRequest) { - $result = $storage->findResult($request->expr); - if ($result !== null) { - $request = $fiber->resume($result); + if ($request instanceof BeforeScopeForExprRequest) { + $beforeScope = $storage->findBeforeScope($request->expr); + if ($beforeScope !== null) { + $request = $fiber->resume($beforeScope); continue; } @@ -79,9 +78,9 @@ protected function processPendingFibers(ExpressionResultStorage $storage): void { foreach ($storage->pendingFibers as $pending) { $request = $pending['request']; - $result = $storage->findResult($request->expr); + $beforeScope = $storage->findBeforeScope($request->expr); - if ($result !== null) { + if ($beforeScope !== null) { throw new ShouldNotHappenException('Pending fibers at the end should be about synthetic nodes'); } @@ -93,8 +92,8 @@ protected function processPendingFibers(ExpressionResultStorage $storage): void new NoopNodeCallback(), ExpressionContext::createTopLevel(), ); - if ($storage->findResult($request->expr) === null) { - throw new ShouldNotHappenException(sprintf('processExprNode should have stored the result of %s on line %s', get_class($request->expr), $request->expr->getStartLine())); + if ($storage->findBeforeScope($request->expr) === null) { + throw new ShouldNotHappenException(sprintf('processExprNode should have stored the beforeScope of %s on line %s', get_class($request->expr), $request->expr->getStartLine())); } $this->processPendingFibers($storage); @@ -103,7 +102,7 @@ protected function processPendingFibers(ExpressionResultStorage $storage): void } } - protected function processPendingFibersForRequestedExpr(ExpressionResultStorage $storage, Expr $expr, ExpressionResult $result): void + protected function processPendingFibersForRequestedExpr(ExpressionResultStorage $storage, Expr $expr, Scope $result): void { $restartLoop = true; diff --git a/src/Analyser/Fiber/FiberScope.php b/src/Analyser/Fiber/FiberScope.php index 4bde06904a..ad4d007c91 100644 --- a/src/Analyser/Fiber/FiberScope.php +++ b/src/Analyser/Fiber/FiberScope.php @@ -4,8 +4,8 @@ use Fiber; use PhpParser\Node\Expr; -use PHPStan\Analyser\ExpressionResult; use PHPStan\Analyser\MutatingScope; +use PHPStan\Analyser\Scope; use PHPStan\Type\Type; final class FiberScope extends MutatingScope @@ -41,12 +41,12 @@ public function toMutatingScope(): MutatingScope /** @api */ public function getType(Expr $node): Type { - /** @var ExpressionResult $exprResult */ - $exprResult = Fiber::suspend( - new ExpressionAnalysisRequest($node, $this), + /** @var Scope $beforeScope */ + $beforeScope = Fiber::suspend( + new BeforeScopeForExprRequest($node, $this), ); - return $exprResult->getBeforeScope()->toMutatingScope()->getType($node); + return $beforeScope->toMutatingScope()->getType($node); } public function getScopeType(Expr $expr): Type @@ -62,22 +62,22 @@ public function getScopeNativeType(Expr $expr): Type /** @api */ public function getNativeType(Expr $expr): Type { - /** @var ExpressionResult $exprResult */ - $exprResult = Fiber::suspend( - new ExpressionAnalysisRequest($expr, $this), + /** @var Scope $beforeScope */ + $beforeScope = Fiber::suspend( + new BeforeScopeForExprRequest($expr, $this), ); - return $exprResult->getBeforeScope()->toMutatingScope()->getNativeType($expr); + return $beforeScope->toMutatingScope()->getNativeType($expr); } public function getKeepVoidType(Expr $node): Type { - /** @var ExpressionResult $exprResult */ - $exprResult = Fiber::suspend( - new ExpressionAnalysisRequest($node, $this), + /** @var Scope $beforeScope */ + $beforeScope = Fiber::suspend( + new BeforeScopeForExprRequest($node, $this), ); - return $exprResult->getBeforeScope()->toMutatingScope()->getKeepVoidType($node); + return $beforeScope->toMutatingScope()->getKeepVoidType($node); } } diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index c1a2325785..5adce94423 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -342,17 +342,17 @@ public function processNodes( $this->processPendingFibers($expressionResultStorage); } - private function storeResult(ExpressionResultStorage $storage, Expr $expr, ExpressionResult $result): void + private function storeBeforeScope(ExpressionResultStorage $storage, Expr $expr, ExpressionResult $result): void { - $storage->storeResult($expr, $result); - $this->processPendingFibersForRequestedExpr($storage, $expr, $result); + $storage->storeBeforeScope($expr, $result->getBeforeScope()); + $this->processPendingFibersForRequestedExpr($storage, $expr, $result->getBeforeScope()); } protected function processPendingFibers(ExpressionResultStorage $storage): void { } - protected function processPendingFibersForRequestedExpr(ExpressionResultStorage $storage, Expr $expr, ExpressionResult $result): void + protected function processPendingFibersForRequestedExpr(ExpressionResultStorage $storage, Expr $expr, Scope $result): void { } @@ -2545,12 +2545,11 @@ public function processExprNode( ExpressionContext $context, ): ExpressionResult { - $existingExprResult = $storage->findResult($expr); - if ($existingExprResult !== null) { - if ($nodeCallback instanceof ShallowNodeCallback) { - return $existingExprResult; + $existingBeforeScope = $storage->findBeforeScope($expr); + if ($existingBeforeScope !== null) { + if (!$nodeCallback instanceof ShallowNodeCallback) { + throw new ShouldNotHappenException(sprintf('Expr %s on line %d has already been analysed', get_class($expr), $expr->getStartLine())); } - throw new ShouldNotHappenException(sprintf('Expr %s on line %d has already been analysed', get_class($expr), $expr->getStartLine())); } if ($expr instanceof Expr\CallLike && $expr->isFirstClassCallable()) { @@ -2567,7 +2566,7 @@ public function processExprNode( } $newExprResult = $this->processExprNode($stmt, $newExpr, $scope, $storage, $nodeCallback, $context); - $this->storeResult($storage, $expr, $newExprResult); + $this->storeBeforeScope($storage, $expr, $newExprResult); return $newExprResult; } @@ -2639,7 +2638,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto } $result = new ExpressionResult($scope, $beforeScope, $hasYield, $isAlwaysTerminating, $throwPoints, $impurePoints); - $this->storeResult($storage, $expr, $result); + $this->storeBeforeScope($storage, $expr, $result); return $result; }, @@ -2696,7 +2695,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto $result->getThrowPoints(), $result->getImpurePoints(), ); - $this->storeResult($storage, $expr, $result); + $this->storeBeforeScope($storage, $expr, $result); return $result; } @@ -2707,7 +2706,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto ); $scope = $result->getScope(); if (!$expr instanceof Expr\AssignOp\Coalesce) { - $this->storeResult($storage, $expr, $result); + $this->storeBeforeScope($storage, $expr, $result); } $hasYield = $result->hasYield(); $throwPoints = $result->getThrowPoints(); @@ -3236,7 +3235,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto static fn (): MutatingScope => $scope->filterByTruthyValue($expr), static fn (): MutatingScope => $scope->filterByFalseyValue($expr), ); - $this->storeResult($storage, $expr, $result); + $this->storeBeforeScope($storage, $expr, $result); return $result; } elseif ($expr instanceof StaticCall) { @@ -3456,7 +3455,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto static fn (): MutatingScope => $scope->filterByTruthyValue($expr), static fn (): MutatingScope => $scope->filterByFalseyValue($expr), ); - $this->storeResult($storage, $expr, $result); + $this->storeBeforeScope($storage, $expr, $result); return $result; } elseif ($expr instanceof StaticPropertyFetch) { @@ -3501,7 +3500,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto [], [], ); - $this->storeResult($storage, $expr, $result); + $this->storeBeforeScope($storage, $expr, $result); return $result; } elseif ($expr instanceof Expr\ArrowFunction) { @@ -3514,7 +3513,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto [], [], ); - $this->storeResult($storage, $expr, $exprResult); + $this->storeBeforeScope($storage, $expr, $exprResult); return $exprResult; } elseif ($expr instanceof ErrorSuppress) { $result = $this->processExprNode($stmt, $expr->expr, $scope, $storage, $nodeCallback, $context); @@ -3623,7 +3622,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto static fn (): MutatingScope => $rightResult->getScope()->filterByTruthyValue($expr), static fn (): MutatingScope => $leftMergedWithRightScope->filterByFalseyValue($expr), ); - $this->storeResult($storage, $expr, $result); + $this->storeBeforeScope($storage, $expr, $result); return $result; } elseif ($expr instanceof BooleanOr || $expr instanceof BinaryOp\LogicalOr) { $leftResult = $this->processExprNode($stmt, $expr->left, $scope, $storage, $nodeCallback, $context->enterDeep()); @@ -3647,7 +3646,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto static fn (): MutatingScope => $leftMergedWithRightScope->filterByTruthyValue($expr), static fn (): MutatingScope => $rightResult->getScope()->filterByFalseyValue($expr), ); - $this->storeResult($storage, $expr, $result); + $this->storeBeforeScope($storage, $expr, $result); return $result; } elseif ($expr instanceof Coalesce) { $nonNullabilityResult = $this->ensureNonNullability($scope, $expr->left); @@ -4121,7 +4120,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto static fn (): MutatingScope => $finalScope->filterByTruthyValue($expr), static fn (): MutatingScope => $finalScope->filterByFalseyValue($expr), ); - $this->storeResult($storage, $expr, $result); + $this->storeBeforeScope($storage, $expr, $result); return $result; } elseif ($expr instanceof Expr\Yield_) { @@ -4477,7 +4476,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto static fn (): MutatingScope => $scope->filterByTruthyValue($expr), static fn (): MutatingScope => $scope->filterByFalseyValue($expr), ); - $this->storeResult($storage, $expr, $result); + $this->storeBeforeScope($storage, $expr, $result); return $result; } @@ -5668,7 +5667,7 @@ private function processArgs( $isAlwaysTerminating = $isAlwaysTerminating || $closureResult->isAlwaysTerminating(); } - $this->storeResult($storage, $arg->value, new ExpressionResult($closureResult->getScope(), $scopeToPass, false, $isAlwaysTerminating, $throwPoints, $impurePoints)); + $this->storeBeforeScope($storage, $arg->value, new ExpressionResult($closureResult->getScope(), $scopeToPass, false, $isAlwaysTerminating, $throwPoints, $impurePoints)); $uses = []; foreach ($arg->value->uses as $use) { @@ -5724,7 +5723,7 @@ private function processArgs( $impurePoints = array_merge($impurePoints, $arrowFunctionResult->getImpurePoints()); $isAlwaysTerminating = $isAlwaysTerminating || $arrowFunctionResult->isAlwaysTerminating(); } - $this->storeResult($storage, $arg->value, new ExpressionResult($arrowFunctionResult->getScope(), $scopeToPass, false, $isAlwaysTerminating, $throwPoints, $impurePoints)); + $this->storeBeforeScope($storage, $arg->value, new ExpressionResult($arrowFunctionResult->getScope(), $scopeToPass, false, $isAlwaysTerminating, $throwPoints, $impurePoints)); } else { $exprType = $scope->getType($arg->value); $exprResult = $this->processExprNode($stmt, $arg->value, $scopeToPass, $storage, $nodeCallback, $context->enterDeep());