Skip to content

Commit 44b744c

Browse files
committed
Fix duplicate Assign result storing
1 parent b1a09a5 commit 44b744c

File tree

2 files changed

+38
-10
lines changed

2 files changed

+38
-10
lines changed

src/Analyser/ExpressionResultStorage.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
use PhpParser\Node\Expr;
66
use PHPStan\Analyser\Fiber\ExpressionAnalysisRequest;
7+
use PHPStan\ShouldNotHappenException;
78
use SplObjectStorage;
9+
use function sprintf;
810

911
final class ExpressionResultStorage
1012
{
@@ -29,6 +31,9 @@ public function duplicate(): self
2931

3032
public function storeResult(Expr $expr, ExpressionResult $result): void
3133
{
34+
if (isset($this->results[$expr])) {
35+
throw new ShouldNotHappenException(sprintf('already stored %s on line %d', get_class($expr), $expr->getStartLine()));
36+
}
3237
$this->results[$expr] = $result;
3338
}
3439

src/Analyser/NodeScopeResolver.php

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2557,6 +2557,14 @@ public function processExprNode(
25572557
ExpressionContext $context,
25582558
): ExpressionResult
25592559
{
2560+
$existingExprResult = $storage->findResult($expr);
2561+
if ($existingExprResult !== null) {
2562+
if ($nodeCallback instanceof ShallowNodeCallback) {
2563+
return $existingExprResult;
2564+
}
2565+
throw new ShouldNotHappenException(sprintf('Expr %s on line %d has already been analysed', get_class($expr), $expr->getStartLine()));
2566+
}
2567+
25602568
if ($expr instanceof Expr\CallLike && $expr->isFirstClassCallable()) {
25612569
if ($expr instanceof FuncCall) {
25622570
$newExpr = new FunctionCallableNode($expr->name, $expr);
@@ -2575,14 +2583,6 @@ public function processExprNode(
25752583
return $newExprResult;
25762584
}
25772585

2578-
$existingExprResult = $storage->findResult($expr);
2579-
if ($existingExprResult !== null) {
2580-
if ($nodeCallback instanceof ShallowNodeCallback) {
2581-
return $existingExprResult;
2582-
}
2583-
throw new ShouldNotHappenException(sprintf('Expr %s on line %d has already been analysed', get_class($expr), $expr->getStartLine()));
2584-
}
2585-
25862586
$originalScope = $scope;
25872587
$this->callNodeCallbackWithExpression($nodeCallback, $expr, $scope, $storage, $context);
25882588

@@ -2658,7 +2658,6 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
26582658
true,
26592659
);
26602660
$scope = $result->getScope();
2661-
$this->storeResult($storage, $expr, $result);
26622661
$hasYield = $result->hasYield();
26632662
$throwPoints = $result->getThrowPoints();
26642663
$impurePoints = $result->getImpurePoints();
@@ -2671,6 +2670,17 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
26712670
$scope = $this->processStmtVarAnnotation($scope, $storage, $stmt, null, $nodeCallback);
26722671
}
26732672
}
2673+
2674+
return new ExpressionResult(
2675+
$scope,
2676+
$originalScope,
2677+
$hasYield,
2678+
$isAlwaysTerminating,
2679+
$throwPoints,
2680+
$impurePoints,
2681+
static fn (): MutatingScope => $scope->filterByTruthyValue($expr),
2682+
static fn (): MutatingScope => $scope->filterByFalseyValue($expr),
2683+
);
26742684
} elseif ($expr instanceof Expr\AssignOp) {
26752685
$result = $this->processAssignVar(
26762686
$scope,
@@ -2708,7 +2718,9 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
27082718
$expr instanceof Expr\AssignOp\Coalesce,
27092719
);
27102720
$scope = $result->getScope();
2711-
$this->storeResult($storage, $expr, $result);
2721+
if (!$expr instanceof Expr\AssignOp\Coalesce) {
2722+
$this->storeResult($storage, $expr, $result);
2723+
}
27122724
$hasYield = $result->hasYield();
27132725
$throwPoints = $result->getThrowPoints();
27142726
$impurePoints = $result->getImpurePoints();
@@ -2719,6 +2731,17 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
27192731
) {
27202732
$throwPoints[] = InternalThrowPoint::createExplicit($scope, new ObjectType(DivisionByZeroError::class), $expr, false);
27212733
}
2734+
2735+
return new ExpressionResult(
2736+
$scope,
2737+
$originalScope,
2738+
$hasYield,
2739+
$isAlwaysTerminating,
2740+
$throwPoints,
2741+
$impurePoints,
2742+
static fn (): MutatingScope => $scope->filterByTruthyValue($expr),
2743+
static fn (): MutatingScope => $scope->filterByFalseyValue($expr),
2744+
);
27222745
} elseif ($expr instanceof FuncCall) {
27232746
$parametersAcceptor = null;
27242747
$functionReflection = null;

0 commit comments

Comments
 (0)