Skip to content

Commit 6528880

Browse files
committed
Separate PendingFibersStorage and ExprAnalysisResultStorage
1 parent 214927b commit 6528880

File tree

4 files changed

+98
-73
lines changed

4 files changed

+98
-73
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\Generator;
4+
5+
use PhpParser\Node\Expr;
6+
use SplObjectStorage;
7+
8+
final class ExprAnalysisResultStorage
9+
{
10+
11+
/** @var SplObjectStorage<Expr, ExprAnalysisResult> */
12+
private SplObjectStorage $expressionAnalysisResults;
13+
14+
public function __construct()
15+
{
16+
$this->expressionAnalysisResults = new SplObjectStorage();
17+
}
18+
19+
public function storeExprAnalysisResult(Expr $expr, ExprAnalysisResult $result): void
20+
{
21+
$this->expressionAnalysisResults[$expr] = $result;
22+
}
23+
24+
public function lookupExprAnalysisResult(Expr $expr): ?ExprAnalysisResult
25+
{
26+
return $this->expressionAnalysisResults[$expr] ?? null;
27+
}
28+
29+
}

src/Analyser/Generator/GeneratorNodeScopeResolver.php

Lines changed: 56 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,11 @@ public function processNodes(
8686
callable $nodeCallback,
8787
): void
8888
{
89-
$storage = new NodeScopeResolverRunStorage();
89+
$pendingFibersStorage = new PendingFibersStorage();
90+
$exprAnalysisResultStorage = new ExprAnalysisResultStorage();
9091
$this->processStmtNodes(
91-
$storage,
92+
$pendingFibersStorage,
93+
$exprAnalysisResultStorage,
9294
$stmts,
9395
$scope,
9496
$nodeCallback,
@@ -100,7 +102,8 @@ public function processNodes(
100102
* @param callable(Node, Scope): void $nodeCallback
101103
*/
102104
private function processStmtNodes(
103-
NodeScopeResolverRunStorage $storage,
105+
PendingFibersStorage $fibersStorage,
106+
ExprAnalysisResultStorage $exprAnalysisResultStorage,
104107
array $stmts,
105108
GeneratorScope $scope,
106109
callable $nodeCallback,
@@ -113,14 +116,15 @@ private function processStmtNodes(
113116

114117
// Trampoline loop
115118
while (true) {
116-
$this->processPendingFibers($storage);
119+
$this->processPendingFibers($fibersStorage, $exprAnalysisResultStorage);
117120

118121
if ($gen->valid()) {
119122
$yielded = $gen->current();
120123

121124
if ($yielded instanceof NodeCallbackRequest) {
122125
$this->invokeNodeCallback(
123-
$storage,
126+
$fibersStorage,
127+
$exprAnalysisResultStorage,
124128
$yielded->node,
125129
$yielded->scope,
126130
$nodeCallback,
@@ -130,7 +134,7 @@ private function processStmtNodes(
130134
continue;
131135
} elseif ($yielded instanceof ExprAnalysisRequest) {
132136
$stack[] = $gen;
133-
$gen = $this->analyzeExpr($storage, $yielded->expr, $yielded->scope);
137+
$gen = $this->analyzeExpr($exprAnalysisResultStorage, $yielded->expr, $yielded->scope);
134138
$gen->current();
135139
continue;
136140
} elseif ($yielded instanceof StmtAnalysisRequest) {
@@ -145,31 +149,32 @@ private function processStmtNodes(
145149

146150
$result = $gen->getReturn();
147151
if (count($stack) === 0) {
148-
foreach ($storage->pendingFibers as $pending) {
152+
foreach ($fibersStorage->pendingFibers as $pending) {
149153
$request = $pending['request'];
150-
$exprAnalysisResult = $this->lookupExprAnalysisResult($storage, $request->expr);
154+
$exprAnalysisResult = $exprAnalysisResultStorage->lookupExprAnalysisResult($request->expr);
151155

152156
if ($exprAnalysisResult !== null) {
153157
throw new ShouldNotHappenException('Pending fibers with an empty stack should be about synthetic nodes');
154158
}
155159

156160
$this->processStmtNodes(
157-
$storage,
161+
$fibersStorage,
162+
$exprAnalysisResultStorage,
158163
[new Stmt\Expression($request->expr)],
159164
$request->scope,
160165
static function () {
161166
},
162167
);
163168
}
164169

165-
if (count($storage->pendingFibers) === 0) {
170+
if (count($fibersStorage->pendingFibers) === 0) {
166171
if (!$result instanceof StmtAnalysisResult) {
167172
throw new ShouldNotHappenException('Top node should be Stmt');
168173
}
169174
return $result;
170175
}
171176

172-
throw new ShouldNotHappenException(sprintf('Cannot finish analysis, pending fibers about: %s', implode(', ', array_map(static fn (array $fiber) => get_class($fiber['request']->expr), $storage->pendingFibers))));
177+
throw new ShouldNotHappenException(sprintf('Cannot finish analysis, pending fibers about: %s', implode(', ', array_map(static fn (array $fiber) => get_class($fiber['request']->expr), $fibersStorage->pendingFibers))));
173178
}
174179

175180
$gen = array_pop($stack);
@@ -258,7 +263,7 @@ private function analyzeStmt(Stmt $stmt, GeneratorScope $scope): Generator
258263
/**
259264
* @return Generator<int, ExprAnalysisRequest|NodeCallbackRequest, ExprAnalysisResult, ExprAnalysisResult>
260265
*/
261-
private function analyzeExpr(NodeScopeResolverRunStorage $storage, Expr $expr, GeneratorScope $scope): Generator
266+
private function analyzeExpr(ExprAnalysisResultStorage $storage, Expr $expr, GeneratorScope $scope): Generator
262267
{
263268
yield new NodeCallbackRequest($expr, $scope);
264269

@@ -269,70 +274,70 @@ private function analyzeExpr(NodeScopeResolverRunStorage $storage, Expr $expr, G
269274
) {
270275
$variableName = $expr->var->name;
271276
$exprResult = yield new ExprAnalysisRequest($expr->expr, $scope);
272-
$this->storeExprAnalysisResult($storage, $expr->expr, $exprResult);
277+
$storage->storeExprAnalysisResult($expr->expr, $exprResult);
273278

274279
$varResult = yield new ExprAnalysisRequest($expr->var, $scope);
275-
$this->storeExprAnalysisResult($storage, $expr->var, $varResult);
280+
$storage->storeExprAnalysisResult($expr->var, $varResult);
276281

277282
$assignResult = new ExprAnalysisResult($exprResult->type, $varResult->scope->assignVariable($variableName, $exprResult->type));
278-
$this->storeExprAnalysisResult($storage, $expr, $assignResult);
283+
$storage->storeExprAnalysisResult($expr, $assignResult);
279284
return $assignResult;
280285
}
281286

282287
if ($expr instanceof Expr\New_ && $expr->class instanceof Node\Name) {
283288
$result = new ExprAnalysisResult(new ObjectType($expr->class->toString()), $scope);
284-
$this->storeExprAnalysisResult($storage, $expr, $result);
289+
$storage->storeExprAnalysisResult($expr, $result);
285290
return $result;
286291
}
287292

288293
if ($expr instanceof Expr\Variable && is_string($expr->name)) {
289294
$exprTypeFromScope = $scope->expressionTypes['$' . $expr->name] ?? null;
290295
if ($exprTypeFromScope !== null) {
291296
$result = new ExprAnalysisResult($exprTypeFromScope, $scope);
292-
$this->storeExprAnalysisResult($storage, $expr, $result);
297+
$storage->storeExprAnalysisResult($expr, $result);
293298
return $result;
294299
}
295-
return $this->lookupExprAnalysisResult($storage, $expr) ?? new ExprAnalysisResult(new ErrorType(), $scope);
300+
return $storage->lookupExprAnalysisResult($expr) ?? new ExprAnalysisResult(new ErrorType(), $scope);
296301
}
297302

298303
if ($expr instanceof Node\Scalar\Int_) {
299304
$result = new ExprAnalysisResult(new ConstantIntegerType($expr->value), $scope);
300-
$this->storeExprAnalysisResult($storage, $expr, $result);
305+
$storage->storeExprAnalysisResult($expr, $result);
301306
return $result;
302307
}
303308

304309
if ($expr instanceof Node\Scalar\String_) {
305310
$result = new ExprAnalysisResult(new ConstantStringType($expr->value), $scope);
306-
$this->storeExprAnalysisResult($storage, $expr, $result);
311+
$storage->storeExprAnalysisResult($expr, $result);
307312
return $result;
308313
}
309314

310315
if ($expr instanceof Node\Expr\Cast\Int_) {
311316
$exprResult = yield new ExprAnalysisRequest($expr->expr, $scope);
312-
$this->storeExprAnalysisResult($storage, $expr->expr, $exprResult);
317+
$storage->storeExprAnalysisResult($expr->expr, $exprResult);
313318
$result = new ExprAnalysisResult($exprResult->type->toInteger(), $scope);
314-
$this->storeExprAnalysisResult($storage, $expr, $result);
319+
$storage->storeExprAnalysisResult($expr, $result);
315320
return $result;
316321
}
317322

318323
if ($expr instanceof MethodCall && $expr->name instanceof Node\Identifier) {
319324
$varResult = yield new ExprAnalysisRequest($expr->var, $scope);
320325

321-
$this->storeExprAnalysisResult($storage, $expr->var, $varResult);
326+
$storage->storeExprAnalysisResult($expr->var, $varResult);
322327
$currentScope = $varResult->scope;
323328
$argTypes = [];
324329

325330
foreach ($expr->getArgs() as $arg) {
326331
$argResult = yield new ExprAnalysisRequest($arg->value, $currentScope);
327-
$this->storeExprAnalysisResult($storage, $arg->value, $argResult);
332+
$storage->storeExprAnalysisResult($arg->value, $argResult);
328333
$argTypes[] = $argResult->type;
329334
$currentScope = $argResult->scope;
330335
}
331336

332337
if ($varResult->type->hasMethod($expr->name->toString())->yes()) {
333338
$method = $varResult->type->getMethod($expr->name->toString(), $scope);
334339
$result = new ExprAnalysisResult($method->getOnlyVariant()->getReturnType(), $scope);
335-
$this->storeExprAnalysisResult($storage, $expr, $result);
340+
$storage->storeExprAnalysisResult($expr, $result);
336341
return $result;
337342
}
338343
}
@@ -341,22 +346,22 @@ private function analyzeExpr(NodeScopeResolverRunStorage $storage, Expr $expr, G
341346
yield from $this->analyzeStmts($expr->stmts, $scope); // @phpstan-ignore generator.valueType, generator.sendType
342347

343348
$result = new ExprAnalysisResult(new ClosureType(), $scope);
344-
$this->storeExprAnalysisResult($storage, $expr, $result);
349+
$storage->storeExprAnalysisResult($expr, $result);
345350
return $result;
346351
}
347352

348353
if ($expr instanceof Expr\FuncCall) {
349354
if ($expr->name instanceof Expr) {
350355
$nameResult = yield new ExprAnalysisRequest($expr->name, $scope);
351-
$this->storeExprAnalysisResult($storage, $expr->name, $nameResult);
356+
$storage->storeExprAnalysisResult($expr->name, $nameResult);
352357
$scope = $nameResult->scope;
353358
}
354359

355360
$argTypes = [];
356361

357362
foreach ($expr->getArgs() as $arg) {
358363
$argResult = yield new ExprAnalysisRequest($arg->value, $scope);
359-
$this->storeExprAnalysisResult($storage, $arg->value, $argResult);
364+
$storage->storeExprAnalysisResult($arg->value, $argResult);
360365
$argTypes[] = $argResult->type;
361366
$scope = $argResult->scope;
362367
}
@@ -365,7 +370,7 @@ private function analyzeExpr(NodeScopeResolverRunStorage $storage, Expr $expr, G
365370
if ($this->reflectionProvider->hasFunction($expr->name, $scope)) {
366371
$function = $this->reflectionProvider->getFunction($expr->name, $scope);
367372
$result = new ExprAnalysisResult($function->getOnlyVariant()->getReturnType(), $scope);
368-
$this->storeExprAnalysisResult($storage, $expr, $result);
373+
$storage->storeExprAnalysisResult($expr, $result);
369374
return $result;
370375
}
371376
}
@@ -378,7 +383,7 @@ private function analyzeExpr(NodeScopeResolverRunStorage $storage, Expr $expr, G
378383
&& $expr->name->toLowerString() === 'class'
379384
) {
380385
$result = new ExprAnalysisResult(new ConstantStringType($expr->class->toString()), $scope);
381-
$this->storeExprAnalysisResult($storage, $expr, $result);
386+
$storage->storeExprAnalysisResult($expr, $result);
382387
return $result;
383388
}
384389

@@ -388,23 +393,34 @@ private function analyzeExpr(NodeScopeResolverRunStorage $storage, Expr $expr, G
388393
/**
389394
* @param callable(Node, Scope): void $nodeCallback
390395
*/
391-
private function invokeNodeCallback(NodeScopeResolverRunStorage $storage, Node $node, Scope $scope, callable $nodeCallback): void
396+
private function invokeNodeCallback(
397+
PendingFibersStorage $fibersStorage,
398+
ExprAnalysisResultStorage $exprAnalysisResultStorage,
399+
Node $node,
400+
Scope $scope,
401+
callable $nodeCallback,
402+
): void
392403
{
393404
$fiber = new Fiber(static function () use ($node, $scope, $nodeCallback) {
394405
$nodeCallback($node, $scope);
395406
});
396407
$request = $fiber->start();
397-
$this->runFiber($storage, $fiber, $request);
408+
$this->runFiber($fibersStorage, $exprAnalysisResultStorage, $fiber, $request);
398409
}
399410

400411
/**
401412
* @param Fiber<mixed, ExprAnalysisResult, null, ExprAnalysisRequest> $fiber
402413
*/
403-
private function runFiber(NodeScopeResolverRunStorage $storage, Fiber $fiber, ?ExprAnalysisRequest $request): void
414+
private function runFiber(
415+
PendingFibersStorage $fibersStorage,
416+
ExprAnalysisResultStorage $exprAnalysisResultStorage,
417+
Fiber $fiber,
418+
?ExprAnalysisRequest $request,
419+
): void
404420
{
405421
while (!$fiber->isTerminated()) {
406422
if ($request instanceof ExprAnalysisRequest) {
407-
$result = $this->lookupExprAnalysisResult($storage, $request->expr);
423+
$result = $exprAnalysisResultStorage->lookupExprAnalysisResult($request->expr);
408424

409425
if ($result !== null) {
410426
// Result ready - continue the loop to resume
@@ -413,7 +429,7 @@ private function runFiber(NodeScopeResolverRunStorage $storage, Fiber $fiber, ?E
413429
}
414430

415431
// Park the fiber - can't make progress yet
416-
$storage->pendingFibers[] = [
432+
$fibersStorage->pendingFibers[] = [
417433
'fiber' => $fiber,
418434
'request' => $request,
419435
];
@@ -432,32 +448,22 @@ private function runFiber(NodeScopeResolverRunStorage $storage, Fiber $fiber, ?E
432448
}
433449
}
434450

435-
private function processPendingFibers(NodeScopeResolverRunStorage $storage): void
451+
private function processPendingFibers(PendingFibersStorage $fibersStorage, ExprAnalysisResultStorage $exprAnalysisResultStorage): void
436452
{
437-
foreach ($storage->pendingFibers as $key => $pending) {
453+
foreach ($fibersStorage->pendingFibers as $key => $pending) {
438454
$request = $pending['request'];
439-
$exprAnalysisResult = $this->lookupExprAnalysisResult($storage, $request->expr);
455+
$exprAnalysisResult = $exprAnalysisResultStorage->lookupExprAnalysisResult($request->expr);
440456

441457
if ($exprAnalysisResult === null) {
442458
continue;
443459
}
444460

445-
unset($storage->pendingFibers[$key]);
461+
unset($fibersStorage->pendingFibers[$key]);
446462

447463
$fiber = $pending['fiber'];
448464
$request = $fiber->resume($exprAnalysisResult);
449-
$this->runFiber($storage, $fiber, $request);
465+
$this->runFiber($fibersStorage, $exprAnalysisResultStorage, $fiber, $request);
450466
}
451467
}
452468

453-
private function storeExprAnalysisResult(NodeScopeResolverRunStorage $storage, Expr $expr, ExprAnalysisResult $result): void
454-
{
455-
$storage->expressionAnalysisResults[$expr] = $result;
456-
}
457-
458-
private function lookupExprAnalysisResult(NodeScopeResolverRunStorage $storage, Expr $expr): ?ExprAnalysisResult
459-
{
460-
return $storage->expressionAnalysisResults[$expr] ?? null;
461-
}
462-
463469
}

src/Analyser/Generator/NodeScopeResolverRunStorage.php

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\Generator;
4+
5+
use Fiber;
6+
7+
final class PendingFibersStorage
8+
{
9+
10+
/** @var array<array{fiber: Fiber<mixed, ExprAnalysisResult, null, ExprAnalysisRequest>, request: ExprAnalysisRequest}> */
11+
public array $pendingFibers = [];
12+
13+
}

0 commit comments

Comments
 (0)