Skip to content

Commit d7b13c2

Browse files
committed
TypeExprRequest
1 parent 96c70c5 commit d7b13c2

File tree

10 files changed

+99
-30
lines changed

10 files changed

+99
-30
lines changed

build/PHPStan/Build/GeneratorYieldSendTypeExtension.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use PHPStan\Analyser\Generator\StmtAnalysisRequest;
1111
use PHPStan\Analyser\Generator\StmtAnalysisResult;
1212
use PHPStan\Analyser\Generator\StmtsAnalysisRequest;
13+
use PHPStan\Analyser\Generator\TypeExprRequest;
14+
use PHPStan\Analyser\Generator\TypeExprResult;
1315
use PHPStan\Analyser\Scope;
1416
use PHPStan\Type\ExpressionTypeResolverExtension;
1517
use PHPStan\Type\NullType;
@@ -55,6 +57,9 @@ public function getType(Expr $expr, Scope $scope): ?Type
5557
if ((new ObjectType(AlternativeNodeCallbackRequest::class))->isSuperTypeOf($valueType)->yes()) {
5658
return new NullType();
5759
}
60+
if ((new ObjectType(TypeExprRequest::class))->isSuperTypeOf($valueType)->yes()) {
61+
return new ObjectType(TypeExprResult::class);
62+
}
5863

5964
return null;
6065
}

src/Analyser/Generator/ExprHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function supports(Expr $expr): bool;
2222

2323
/**
2424
* @param T $expr
25-
* @return Generator<int, ExprAnalysisRequest|NodeCallbackRequest, ExprAnalysisResult, ExprAnalysisResult>
25+
* @return Generator<int, ExprAnalysisRequest|AlternativeNodeCallbackRequest|NodeCallbackRequest|TypeExprRequest, ExprAnalysisResult|TypeExprResult, ExprAnalysisResult>
2626
*/
2727
public function analyseExpr(Stmt $stmt, Expr $expr, GeneratorScope $scope, ExprAnalysisResultStorage $storage, ExpressionContext $context): Generator;
2828

src/Analyser/Generator/ExprHandler/AssignHandler.php

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
use PHPStan\Analyser\Generator\GeneratorScope;
3030
use PHPStan\Analyser\Generator\InternalThrowPoint;
3131
use PHPStan\Analyser\Generator\NodeCallbackRequest;
32+
use PHPStan\Analyser\Generator\TypeExprRequest;
33+
use PHPStan\Analyser\Generator\TypeExprResult;
3234
use PHPStan\Analyser\ImpurePoint;
3335
use PHPStan\Analyser\Scope;
3436
use PHPStan\Analyser\SpecifiedTypes;
@@ -218,7 +220,7 @@ private function getAssignedVariables(Expr $expr): array
218220

219221
/**
220222
* @param array<int, string> $variableNames
221-
* @return Generator<int, ExprAnalysisRequest, ExprAnalysisResult, GeneratorScope>
223+
* @return Generator<int, ExprAnalysisRequest|TypeExprRequest, ExprAnalysisResult|TypeExprResult, GeneratorScope>
222224
*/
223225
private function processVarAnnotation(GeneratorScope $scope, array $variableNames, Node\Stmt $node, bool &$changed = false): Generator
224226
{
@@ -269,7 +271,7 @@ private function processVarAnnotation(GeneratorScope $scope, array $variableName
269271
}
270272

271273
/**
272-
* @return Generator<int, ExprAnalysisRequest|NodeCallbackRequest, ExprAnalysisResult, GeneratorScope>
274+
* @return Generator<int, ExprAnalysisRequest|NodeCallbackRequest|TypeExprRequest, ExprAnalysisResult|TypeExprResult, GeneratorScope>
273275
*/
274276
private function processStmtVarAnnotation(GeneratorScope $scope, Node\Stmt $stmt, ?Expr $defaultExpr): Generator
275277
{
@@ -328,6 +330,7 @@ private function processStmtVarAnnotation(GeneratorScope $scope, Node\Stmt $stmt
328330
yield new NodeCallbackRequest(new VarTagChangedExpressionTypeNode($varTag, $variableNode), $scope);
329331
}
330332

333+
// todo NoopExprAnalysisRequest
331334
$variableNodeResult = yield new ExprAnalysisRequest($stmt, $variableNode, $scope, ExpressionContext::createDeep(), static function () {
332335
});
333336

@@ -357,8 +360,8 @@ private function processStmtVarAnnotation(GeneratorScope $scope, Node\Stmt $stmt
357360
}
358361

359362
/**
360-
* @param Closure(GeneratorScope $scope): Generator<int, ExprAnalysisRequest|NodeCallbackRequest, ExprAnalysisResult, ExprAnalysisResult> $processExprCallback
361-
* @return Generator<int, ExprAnalysisRequest|NodeCallbackRequest, ExprAnalysisResult, ExprAnalysisResult>
363+
* @param Closure(GeneratorScope $scope): Generator<int, ExprAnalysisRequest|NodeCallbackRequest|TypeExprRequest, ExprAnalysisResult|TypeExprResult, ExprAnalysisResult> $processExprCallback
364+
* @return Generator<int, ExprAnalysisRequest|NodeCallbackRequest|TypeExprRequest, ExprAnalysisResult|TypeExprResult, ExprAnalysisResult>
362365
*/
363366
private function processAssignVar(
364367
GeneratorScope $scope,
@@ -627,6 +630,7 @@ private function processAssignVar(
627630
}
628631

629632
if (!$varType->isArray()->yes() && !(new ObjectType(ArrayAccess::class))->isSuperTypeOf($varType)->no()) {
633+
// todo NoopExprAnalysisRequest
630634
$throwPoints = array_merge($throwPoints, (yield new ExprAnalysisRequest(
631635
$stmt,
632636
new MethodCall($var, 'offsetSet'),
@@ -744,6 +748,7 @@ static function (): void {
744748
$scope = $assignExprGen->getReturn();
745749
// simulate dynamic property assign by __set to get throw points
746750
if (!$propertyHolderType->hasMethod('__set')->no()) {
751+
// todo NoopExprAnalysisRequest
747752
$throwPoints = array_merge($throwPoints, (yield new ExprAnalysisRequest(
748753
$stmt,
749754
new MethodCall($var->var, '__set'),
@@ -971,8 +976,7 @@ static function (GeneratorScope $scope): Generator {
971976
$offsetNativeTypes = [];
972977
foreach (array_reverse($dimFetchStack) as $dimFetch) {
973978
$dimExpr = $dimFetch->getDim();
974-
$dimExprResult = yield new ExprAnalysisRequest($stmt, $dimExpr, $scope, $context->enterDeep(), static function (): void {
975-
});
979+
$dimExprResult = yield new TypeExprRequest($dimExpr);
976980
$offsetTypes[] = [$dimExprResult->type, $dimFetch];
977981
$offsetNativeTypes[] = [$dimExprResult->nativeType, $dimFetch];
978982
}
@@ -1178,7 +1182,7 @@ private function unwrapAssign(Expr $expr): Expr
11781182
/**
11791183
* @param list<ArrayDimFetch> $dimFetchStack
11801184
*/
1181-
private function isImplicitArrayCreation(array $dimFetchStack, Scope $scope): TrinaryLogic
1185+
private function isImplicitArrayCreation(array $dimFetchStack, GeneratorScope $scope): TrinaryLogic
11821186
{
11831187
if (count($dimFetchStack) === 0) {
11841188
return TrinaryLogic::createNo();
@@ -1202,7 +1206,7 @@ private function isImplicitArrayCreation(array $dimFetchStack, Scope $scope): Tr
12021206
*
12031207
* @return array{Type, list<array{Expr, Type}>}
12041208
*/
1205-
private function produceArrayDimFetchAssignValueToWrite(array $dimFetchStack, array $offsetTypes, Type $offsetValueType, Type $valueToWrite, Scope $scope, ExprAnalysisResultStorage $storage, bool $native): array
1209+
private function produceArrayDimFetchAssignValueToWrite(array $dimFetchStack, array $offsetTypes, Type $offsetValueType, Type $valueToWrite, GeneratorScope $scope, ExprAnalysisResultStorage $storage, bool $native): array
12061210
{
12071211
$originalValueToWrite = $valueToWrite;
12081212

src/Analyser/Generator/GeneratorNodeScopeResolver.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,16 @@ static function (Node $node, Scope $scope) use ($alternativeNodeCallback, $nodeC
211211
);
212212
$gen->generator->current();
213213
continue;
214+
} elseif ($yielded instanceof TypeExprRequest) {
215+
$stack[] = $gen;
216+
$gen = new IdentifiedGeneratorInStack(
217+
$this->analyseExprForType($exprAnalysisResultStorage, $yielded->expr),
218+
$yielded->expr,
219+
$yielded->originFile,
220+
$yielded->originLine,
221+
);
222+
$gen->generator->current();
223+
continue;
214224
} elseif ($yielded instanceof StmtAnalysisRequest) {
215225
$stack[] = $gen;
216226
$gen = new IdentifiedGeneratorInStack(
@@ -246,6 +256,7 @@ static function (Node $node, Scope $scope) use ($alternativeNodeCallback, $nodeC
246256
throw new ShouldNotHappenException('Pending fibers with an empty stack should be about synthetic nodes');
247257
}
248258

259+
// todo NoopExprAnalysisRequest
249260
$this->processStmtNodes(
250261
$fibersStorage,
251262
$exprAnalysisResultStorage,
@@ -337,7 +348,7 @@ private function analyseStmt(Stmt $stmt, GeneratorScope $scope, StatementContext
337348

338349
/**
339350
* @param (callable(Node, Scope, callable(Node, Scope): void): void)|null $alternativeNodeCallback
340-
* @return Generator<int, ExprAnalysisRequest|NodeCallbackRequest|AlternativeNodeCallbackRequest, ExprAnalysisResult, ExprAnalysisResult>
351+
* @return Generator<int, TypeExprRequest|ExprAnalysisRequest|NodeCallbackRequest|AlternativeNodeCallbackRequest, ExprAnalysisResult, TypeExprResult|ExprAnalysisResult>
341352
*/
342353
private function analyseExpr(ExprAnalysisResultStorage $storage, Stmt $stmt, Expr $expr, GeneratorScope $scope, ExpressionContext $context, ?callable $alternativeNodeCallback): Generator
343354
{
@@ -371,6 +382,20 @@ private function analyseExpr(ExprAnalysisResultStorage $storage, Stmt $stmt, Exp
371382
throw new ShouldNotHappenException('Unhandled expr: ' . get_class($expr));
372383
}
373384

385+
/**
386+
* @return Generator<int, TypeExprRequest, TypeExprResult, TypeExprResult>
387+
*/
388+
private function analyseExprForType(ExprAnalysisResultStorage $storage, Expr $expr): Generator
389+
{
390+
$result = $storage->findExprAnalysisResult($expr);
391+
if ($result !== null) {
392+
yield from [];
393+
return new TypeExprResult($result->type, $result->nativeType);
394+
}
395+
396+
throw new ShouldNotHappenException('Not yet implemented - park expr request for type until later when it has been analysed');
397+
}
398+
374399
/**
375400
* @param callable(Node, Scope): void $nodeCallback
376401
*/

src/Analyser/Generator/GeneratorScope.php

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ private function getNodeKey(Expr $node): string
228228
}
229229

230230
/**
231-
* @return Generator<int, ExprAnalysisRequest, ExprAnalysisResult, GeneratorScope>
231+
* @return Generator<int, ExprAnalysisRequest|TypeExprRequest, ExprAnalysisResult|TypeExprResult, GeneratorScope>
232232
*/
233233
public function assignVariable(string $variableName, Type $type, Type $nativeType, TrinaryLogic $certainty): Generator
234234
{
@@ -297,7 +297,7 @@ public function assignVariable(string $variableName, Type $type, Type $nativeTyp
297297
}
298298

299299
/**
300-
* @return Generator<int, ExprAnalysisRequest, ExprAnalysisResult, GeneratorScope>
300+
* @return Generator<int, ExprAnalysisRequest|TypeExprRequest, ExprAnalysisResult|TypeExprResult, GeneratorScope>
301301
*/
302302
public function assignExpression(Expr $expr, Type $type, Type $nativeType): Generator
303303
{
@@ -317,7 +317,7 @@ public function assignExpression(Expr $expr, Type $type, Type $nativeType): Gene
317317
}
318318

319319
/**
320-
* @return Generator<int, ExprAnalysisRequest, ExprAnalysisResult, GeneratorScope>
320+
* @return Generator<int, ExprAnalysisRequest|TypeExprRequest, ExprAnalysisResult|TypeExprResult, GeneratorScope>
321321
*/
322322
private function specifyExpressionType(Expr $expr, Type $type, Type $nativeType, TrinaryLogic $certainty): Generator
323323
{
@@ -348,23 +348,9 @@ private function specifyExpressionType(Expr $expr, Type $type, Type $nativeType,
348348
&& !$expr->dim instanceof Expr\PostDec
349349
&& !$expr->dim instanceof Expr\PostInc
350350
) {
351-
$dimType = (yield new ExprAnalysisRequest(
352-
new Node\Stmt\Expression($expr->dim),
353-
$expr->dim,
354-
$this,
355-
ExpressionContext::createTopLevel(),
356-
static function () {
357-
},
358-
))->type->toArrayKey();
351+
$dimType = (yield new TypeExprRequest($expr->dim))->type->toArrayKey();
359352
if ($dimType->isInteger()->yes() || $dimType->isString()->yes()) {
360-
$exprVarResult = yield new ExprAnalysisRequest(
361-
new Node\Stmt\Expression($expr->var),
362-
$expr->var,
363-
$this,
364-
ExpressionContext::createTopLevel(),
365-
static function () {
366-
},
367-
);
353+
$exprVarResult = yield new TypeExprRequest($expr->var);
368354
$exprVarType = $exprVarResult->type;
369355
if (!$exprVarType instanceof MixedType && !$exprVarType->isArray()->no()) {
370356
$types = [

src/Analyser/Generator/IdentifiedGeneratorInStack.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ final class IdentifiedGeneratorInStack
1212
* @param (
1313
* Generator<int, StmtAnalysisRequest, StmtAnalysisResult, StmtAnalysisResult>| // analyseStmts
1414
* Generator<int, ExprAnalysisRequest|StmtAnalysisRequest|StmtsAnalysisRequest|NodeCallbackRequest|AlternativeNodeCallbackRequest, ExprAnalysisResult|StmtAnalysisResult, StmtAnalysisResult>| // analyseStmt
15-
* Generator<int, ExprAnalysisRequest|NodeCallbackRequest|AlternativeNodeCallbackRequest, ExprAnalysisResult, ExprAnalysisResult> // analyseExpr
15+
* Generator<int, TypeExprRequest|ExprAnalysisRequest|NodeCallbackRequest|AlternativeNodeCallbackRequest, ExprAnalysisResult, TypeExprResult|ExprAnalysisResult>| // analyseExpr
16+
* Generator<int, TypeExprRequest, TypeExprResult, TypeExprResult> // analyseExprForType
1617
* ) $generator
1718
* @param Node|Node[] $node
1819
*/
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\Generator;
4+
5+
use PhpParser\Node\Expr;
6+
use function debug_backtrace;
7+
use const DEBUG_BACKTRACE_IGNORE_ARGS;
8+
9+
final class TypeExprRequest
10+
{
11+
12+
public ?string $originFile = null;
13+
14+
public ?int $originLine = null;
15+
16+
public function __construct(
17+
public readonly Expr $expr,
18+
)
19+
{
20+
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
21+
$this->originFile = $trace[0]['file'] ?? null;
22+
$this->originLine = $trace[0]['line'] ?? null;
23+
}
24+
25+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\Generator;
4+
5+
use PHPStan\Type\Type;
6+
7+
final class TypeExprResult
8+
{
9+
10+
public function __construct(
11+
public readonly Type $type,
12+
public readonly Type $nativeType,
13+
)
14+
{
15+
}
16+
17+
}

tests/PHPStan/Analyser/Generator/data/gnsr.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ function (): void {
2727
assertType('array{}', $a);
2828

2929
};
30+
31+
function (): void {
32+
$a['bla'] = 1;
33+
//assertType('array{bla: 1}', $a);
34+
};

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class FooTestYield
1414
public function doFoo(): Generator
1515
{
1616
assertType(ExprAnalysisResult::class, yield new ExprAnalysisRequest());
17+
assertType(TypeExprResult::class, yield new TypeExprRequest());
1718
assertType(StmtAnalysisResult::class, yield new StmtAnalysisRequest());
1819
assertType(StmtAnalysisResult::class, yield new StmtsAnalysisRequest());
1920
assertType('null', yield new NodeCallbackRequest());

0 commit comments

Comments
 (0)