Skip to content

Commit 65fc460

Browse files
committed
Request the current ExprAnalysisResultStorage in generators
1 parent 9b0c268 commit 65fc460

File tree

6 files changed

+69
-17
lines changed

6 files changed

+69
-17
lines changed

build/PHPStan/Build/GeneratorYieldSendTypeExtension.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PHPStan\Analyser\Generator\ExprAnalysisRequest;
88
use PHPStan\Analyser\Generator\ExprAnalysisResult;
99
use PHPStan\Analyser\Generator\ExprAnalysisResultStorage;
10+
use PHPStan\Analyser\Generator\GetExprAnalysisResultStorageRequest;
1011
use PHPStan\Analyser\Generator\NodeCallbackRequest;
1112
use PHPStan\Analyser\Generator\PersistStorageRequest;
1213
use PHPStan\Analyser\Generator\RestoreStorageRequest;
@@ -15,6 +16,7 @@
1516
use PHPStan\Analyser\Generator\StmtAnalysisRequest;
1617
use PHPStan\Analyser\Generator\StmtAnalysisResult;
1718
use PHPStan\Analyser\Generator\StmtsAnalysisRequest;
19+
use PHPStan\Analyser\Generator\StoreExprResultRequest;
1820
use PHPStan\Analyser\Generator\TypeExprRequest;
1921
use PHPStan\Analyser\Generator\TypeExprResult;
2022
use PHPStan\Analyser\Scope;
@@ -66,6 +68,12 @@ public function getType(Expr $expr, Scope $scope): ?Type
6668
if ((new ObjectType(PersistStorageRequest::class))->isSuperTypeOf($valueType)->yes()) {
6769
return new ObjectType(ExprAnalysisResultStorage::class);
6870
}
71+
if ((new ObjectType(GetExprAnalysisResultStorageRequest::class))->isSuperTypeOf($valueType)->yes()) {
72+
return new ObjectType(ExprAnalysisResultStorage::class);
73+
}
74+
if ((new ObjectType(StoreExprResultRequest::class))->isSuperTypeOf($valueType)->yes()) {
75+
return new NullType();
76+
}
6977
if ((new ObjectType(RestoreStorageRequest::class))->isSuperTypeOf($valueType)->yes()) {
7078
return new NullType();
7179
}

src/Analyser/Generator/GeneratorNodeScopeResolver.php

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
* a hypothetical method call) are analyzed on-demand when requested, with the Fiber
7676
* suspending until analysis completes
7777
*
78-
* @phpstan-type GeneratorTValueType = ExprAnalysisRequest|StmtAnalysisRequest|StmtsAnalysisRequest|NodeCallbackRequest|AttrGroupsAnalysisRequest|TypeExprRequest|PersistStorageRequest|RestoreStorageRequest|RunInFiberRequest<mixed>
78+
* @phpstan-type GeneratorTValueType = ExprAnalysisRequest|StmtAnalysisRequest|StmtsAnalysisRequest|NodeCallbackRequest|AttrGroupsAnalysisRequest|TypeExprRequest|PersistStorageRequest|RestoreStorageRequest|RunInFiberRequest<mixed>|GetExprAnalysisResultStorageRequest|StoreExprResultRequest
7979
* @phpstan-type GeneratorTSendType = ExprAnalysisResult|StmtAnalysisResult|TypeExprResult|ExprAnalysisResultStorage|RunInFiberResult<mixed>|null
8080
*/
8181
#[AutowiredService]
@@ -178,7 +178,7 @@ private function runTrampoline(
178178
): void
179179
{
180180
while (true) {
181-
$pendingFibersGen = $this->processPendingFibers($fibersStorage, $exprAnalysisResultStorage);
181+
$pendingFibersGen = $this->processPendingFibers($exprAnalysisResultStorage, $fibersStorage);
182182
if ($pendingFibersGen->valid()) {
183183
$stack[] = $gen;
184184
$gen = new IdentifiedGeneratorInStack($pendingFibersGen, new Stmt\Expression(new Node\Scalar\String_('pendingFibers')), null, null);
@@ -193,7 +193,6 @@ private function runTrampoline(
193193
$gen = new IdentifiedGeneratorInStack(
194194
$this->invokeNodeCallback(
195195
$fibersStorage,
196-
$exprAnalysisResultStorage,
197196
$yielded->node,
198197
$yielded->scope,
199198
$alternativeNodeCallback !== null
@@ -211,7 +210,7 @@ private function runTrampoline(
211210
} elseif ($yielded instanceof ExprAnalysisRequest) {
212211
$stack[] = $gen;
213212
$gen = new IdentifiedGeneratorInStack(
214-
$this->analyseExpr($fibersStorage, $exprAnalysisResultStorage, $yielded->stmt, $yielded->expr, $yielded->scope, $yielded->context, $yielded->alternativeNodeCallback, $stack, $yielded->originFile, $yielded->originLine),
213+
$this->analyseExpr($fibersStorage, $yielded->stmt, $yielded->expr, $yielded->scope, $yielded->context, $yielded->alternativeNodeCallback, $stack, $yielded->originFile, $yielded->originLine),
215214
$yielded->expr,
216215
$yielded->originFile,
217216
$yielded->originLine,
@@ -275,6 +274,19 @@ private function runTrampoline(
275274
);
276275
$gen->generator->current();
277276
continue;
277+
} elseif ($yielded instanceof GetExprAnalysisResultStorageRequest) {
278+
$gen->generator->send($exprAnalysisResultStorage);
279+
continue;
280+
} elseif ($yielded instanceof StoreExprResultRequest) {
281+
$exprAnalysisResultStorage->storeExprAnalysisResult(
282+
$yielded->expr,
283+
$yielded->result,
284+
$yielded->stack,
285+
$yielded->file,
286+
$yielded->line,
287+
);
288+
$gen->generator->next();
289+
continue;
278290
} else { // phpcs:ignore
279291
throw new NeverException($yielded);
280292
}
@@ -292,7 +304,7 @@ private function runTrampoline(
292304

293305
$stack[] = $gen;
294306
$gen = new IdentifiedGeneratorInStack(
295-
$this->analyseExpr(null, $exprAnalysisResultStorage, $request->stmt, $request->expr, $request->scope, $request->context, $request->alternativeNodeCallback, $stack, $request->originFile, $request->originLine),
307+
$this->analyseExpr(null, $request->stmt, $request->expr, $request->scope, $request->context, $request->alternativeNodeCallback, $stack, $request->originFile, $request->originLine),
296308
$request->expr,
297309
$request->originFile,
298310
$request->originLine,
@@ -450,8 +462,9 @@ private function runInFiber(callable $callback): Generator
450462
* @param list<IdentifiedGeneratorInStack> $stack
451463
* @return Generator<int, GeneratorTValueType, GeneratorTSendType, ExprAnalysisResult>
452464
*/
453-
private function analyseExpr(?PendingFibersStorage $fibersStorage, ExprAnalysisResultStorage $storage, Stmt $stmt, Expr $expr, GeneratorScope $scope, ExpressionContext $context, ?callable $alternativeNodeCallback, array $stack, ?string $file, ?int $line): Generator
465+
private function analyseExpr(?PendingFibersStorage $fibersStorage, Stmt $stmt, Expr $expr, GeneratorScope $scope, ExpressionContext $context, ?callable $alternativeNodeCallback, array $stack, ?string $file, ?int $line): Generator
454466
{
467+
$storage = yield new GetExprAnalysisResultStorageRequest();
455468
$foundExprAnalysisResult = $storage->findExprAnalysisResult($expr);
456469
if ($foundExprAnalysisResult !== null) {
457470
if ($alternativeNodeCallback instanceof NoopNodeCallback) {
@@ -488,7 +501,7 @@ private function analyseExpr(?PendingFibersStorage $fibersStorage, ExprAnalysisR
488501
throw new ShouldNotHappenException();
489502
}
490503

491-
$exprGen = $this->analyseExpr($fibersStorage, $storage, $stmt, $newExpr, $scope, $context, $alternativeNodeCallback, $stack, $file, $line);
504+
$exprGen = $this->analyseExpr($fibersStorage, $stmt, $newExpr, $scope, $context, $alternativeNodeCallback, $stack, $file, $line);
492505
yield from $exprGen;
493506

494507
return $exprGen->getReturn();
@@ -508,10 +521,10 @@ private function analyseExpr(?PendingFibersStorage $fibersStorage, ExprAnalysisR
508521
yield from $gen;
509522

510523
$exprAnalysisResult = $gen->getReturn();
511-
$storage->storeExprAnalysisResult($expr, $exprAnalysisResult, $stack, $file, $line);
524+
yield new StoreExprResultRequest($expr, $exprAnalysisResult, $stack, $file, $line);
512525

513526
if ($fibersStorage !== null) {
514-
yield from $this->processPendingFibersForRequestedExpr($fibersStorage, $storage, $expr, $exprAnalysisResult);
527+
yield from $this->processPendingFibersForRequestedExpr($fibersStorage, $expr, $exprAnalysisResult);
515528
}
516529

517530
return $exprAnalysisResult;
@@ -540,7 +553,6 @@ private function analyseExprForType(ExprAnalysisResultStorage $storage, Expr $ex
540553
*/
541554
private function invokeNodeCallback(
542555
PendingFibersStorage $fibersStorage,
543-
ExprAnalysisResultStorage $exprAnalysisResultStorage,
544556
Node $node,
545557
Scope $scope,
546558
callable $nodeCallback,
@@ -550,7 +562,7 @@ private function invokeNodeCallback(
550562
$nodeCallback($node, $scope);
551563
});
552564
$request = $fiber->start();
553-
yield from $this->runFiberForNodeCallback($fibersStorage, $exprAnalysisResultStorage, $fiber, $request);
565+
yield from $this->runFiberForNodeCallback($fibersStorage, $fiber, $request);
554566

555567
return null;
556568
}
@@ -561,13 +573,13 @@ private function invokeNodeCallback(
561573
*/
562574
private function runFiberForNodeCallback(
563575
PendingFibersStorage $fibersStorage,
564-
ExprAnalysisResultStorage $exprAnalysisResultStorage,
565576
Fiber $fiber,
566577
ExprAnalysisRequest|NodeCallbackRequest|null $request,
567578
): Generator
568579
{
569580
while (!$fiber->isTerminated()) {
570581
if ($request instanceof ExprAnalysisRequest) {
582+
$exprAnalysisResultStorage = yield new GetExprAnalysisResultStorageRequest();
571583
$result = $exprAnalysisResultStorage->findExprAnalysisResult($request->expr);
572584

573585
if ($result !== null) {
@@ -603,7 +615,7 @@ private function runFiberForNodeCallback(
603615
/**
604616
* @return Generator<int, GeneratorTValueType, GeneratorTSendType, void>
605617
*/
606-
private function processPendingFibers(PendingFibersStorage $fibersStorage, ExprAnalysisResultStorage $exprAnalysisResultStorage): Generator
618+
private function processPendingFibers(ExprAnalysisResultStorage $exprAnalysisResultStorage, PendingFibersStorage $fibersStorage): Generator
607619
{
608620
$restartLoop = true;
609621

@@ -623,7 +635,7 @@ private function processPendingFibers(PendingFibersStorage $fibersStorage, ExprA
623635

624636
$fiber = $pending['fiber'];
625637
$request = $fiber->resume($exprAnalysisResult);
626-
yield from $this->runFiberForNodeCallback($fibersStorage, $exprAnalysisResultStorage, $fiber, $request);
638+
yield from $this->runFiberForNodeCallback($fibersStorage, $fiber, $request);
627639

628640
// Break and restart the loop since the array may have been modified
629641
break;
@@ -634,7 +646,7 @@ private function processPendingFibers(PendingFibersStorage $fibersStorage, ExprA
634646
/**
635647
* @return Generator<int, GeneratorTValueType, GeneratorTSendType, void>
636648
*/
637-
private function processPendingFibersForRequestedExpr(PendingFibersStorage $fibersStorage, ExprAnalysisResultStorage $exprAnalysisResultStorage, Expr $expr, ExprAnalysisResult $result): Generator
649+
private function processPendingFibersForRequestedExpr(PendingFibersStorage $fibersStorage, Expr $expr, ExprAnalysisResult $result): Generator
638650
{
639651
$restartLoop = true;
640652

@@ -652,7 +664,7 @@ private function processPendingFibersForRequestedExpr(PendingFibersStorage $fibe
652664

653665
$fiber = $pending['fiber'];
654666
$request = $fiber->resume($result);
655-
yield from $this->runFiberForNodeCallback($fibersStorage, $exprAnalysisResultStorage, $fiber, $request);
667+
yield from $this->runFiberForNodeCallback($fibersStorage, $fiber, $request);
656668

657669
// Break and restart the loop since the array may have been modified
658670
break;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\Generator;
4+
5+
final class GetExprAnalysisResultStorageRequest
6+
{
7+
8+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\Generator;
4+
5+
use PhpParser\Node\Expr;
6+
7+
final class StoreExprResultRequest
8+
{
9+
10+
/**
11+
* @param list<IdentifiedGeneratorInStack> $stack
12+
*/
13+
public function __construct(
14+
public readonly Expr $expr,
15+
public readonly ExprAnalysisResult $result,
16+
public readonly array $stack,
17+
public readonly ?string $file,
18+
public readonly ?int $line,
19+
)
20+
{
21+
}
22+
23+
}

tests/PHPStan/Analyser/Generator/GeneratorNodeScopeResolverRuleTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ static function (Node $node, Scope $scope) {
160160
[
161161
['exit through', 666],
162162
['Called on GeneratorNodeScopeResolverRule\\Foo, arg: 1', 21],
163-
['exit through', 666],
164163
['Virtual node invoked: \'foo\', 3', 23],
165164
['Called on GeneratorNodeScopeResolverRule\\Foo, arg: \'foo\'', 23],
166165
],

tests/PHPStan/Analyser/nsrt/gnsr-yield-in-generator-ns.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public function doFoo(): Generator
2121
assertType('null', yield new AttrGroupsAnalysisRequest());
2222
assertType(ExprAnalysisResultStorage::class, yield new PersistStorageRequest());
2323
assertType('null', yield new RestoreStorageRequest());
24+
assertType('null', yield new StoreExprResultRequest());
25+
assertType(ExprAnalysisResultStorage::class, yield new GetExprAnalysisResultStorageRequest());
2426
assertType(RunInFiberResult::class . '<1>', yield new RunInFiberRequest(fn () => 1));
2527

2628
$a = 's';

0 commit comments

Comments
 (0)