Skip to content

Commit 40c2377

Browse files
committed
ExpressionTypeResolverExtension for yield in PHPStan\Analyser\Generator namespace
1 parent e870ac1 commit 40c2377

File tree

5 files changed

+90
-0
lines changed

5 files changed

+90
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Build;
4+
5+
use PhpParser\Node\Expr;
6+
use PHPStan\Analyser\Generator\ExprAnalysisRequest;
7+
use PHPStan\Analyser\Generator\ExprAnalysisResult;
8+
use PHPStan\Analyser\Generator\NodeCallbackRequest;
9+
use PHPStan\Analyser\Generator\StmtAnalysisRequest;
10+
use PHPStan\Analyser\Generator\StmtAnalysisResult;
11+
use PHPStan\Analyser\Generator\StmtsAnalysisRequest;
12+
use PHPStan\Analyser\Scope;
13+
use PHPStan\Type\ExpressionTypeResolverExtension;
14+
use PHPStan\Type\NullType;
15+
use PHPStan\Type\ObjectType;
16+
use PHPStan\Type\Type;
17+
use function str_starts_with;
18+
19+
final class GeneratorYieldSendTypeExtension implements ExpressionTypeResolverExtension
20+
{
21+
22+
public function getType(Expr $expr, Scope $scope): ?Type
23+
{
24+
if (!$expr instanceof Expr\Yield_) {
25+
return null;
26+
}
27+
28+
if ($expr->value === null) {
29+
return null;
30+
}
31+
32+
$namespace = $scope->getNamespace();
33+
if ($namespace === null) {
34+
return null;
35+
}
36+
37+
if (!str_starts_with($namespace . '\\', 'PHPStan\\Analyser\\Generator\\')) {
38+
return null;
39+
}
40+
41+
$valueType = $scope->getType($expr->value);
42+
if ((new ObjectType(ExprAnalysisRequest::class))->isSuperTypeOf($valueType)->yes()) {
43+
return new ObjectType(ExprAnalysisResult::class);
44+
}
45+
if ((new ObjectType(StmtAnalysisRequest::class))->isSuperTypeOf($valueType)->yes()) {
46+
return new ObjectType(StmtAnalysisResult::class);
47+
}
48+
if ((new ObjectType(StmtsAnalysisRequest::class))->isSuperTypeOf($valueType)->yes()) {
49+
return new ObjectType(StmtAnalysisResult::class);
50+
}
51+
if ((new ObjectType(NodeCallbackRequest::class))->isSuperTypeOf($valueType)->yes()) {
52+
return new NullType();
53+
}
54+
55+
return null;
56+
}
57+
58+
}

build/phpstan.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,7 @@ services:
147147
class: PHPStan\Build\ContainerDynamicReturnTypeExtension
148148
tags:
149149
- phpstan.broker.dynamicMethodReturnTypeExtension
150+
-
151+
class: PHPStan\Build\GeneratorYieldSendTypeExtension
152+
tags:
153+
- phpstan.broker.expressionTypeResolverExtension

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ public static function getAdditionalConfigFiles(): array
302302
return [
303303
__DIR__ . '/../../../conf/bleedingEdge.neon',
304304
__DIR__ . '/typeAliases.neon',
305+
__DIR__ . '/gnsr-extensions.neon',
305306
];
306307
}
307308

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
services:
2+
-
3+
class: PHPStan\Build\GeneratorYieldSendTypeExtension
4+
tags:
5+
- phpstan.broker.expressionTypeResolverExtension
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace PHPStan\Analyser\Generator;
4+
5+
use Generator;
6+
use function PHPStan\Testing\assertType;
7+
8+
class FooTestYield
9+
{
10+
11+
/**
12+
* @return Generator<int, ExprAnalysisRequest|StmtAnalysisRequest|StmtsAnalysisRequest|NodeCallbackRequest, ExprAnalysisResult|StmtAnalysisResult, StmtAnalysisResult>
13+
*/
14+
public function doFoo(): Generator
15+
{
16+
assertType(ExprAnalysisResult::class, yield new ExprAnalysisRequest());
17+
assertType(StmtAnalysisResult::class, yield new StmtAnalysisRequest());
18+
assertType(StmtAnalysisResult::class, yield new StmtsAnalysisRequest());
19+
assertType('null', yield new NodeCallbackRequest());
20+
}
21+
22+
}

0 commit comments

Comments
 (0)