Skip to content

Commit d615188

Browse files
committed
GeneratorTypeSpecifier
1 parent 36cf9a1 commit d615188

File tree

4 files changed

+82
-11
lines changed

4 files changed

+82
-11
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\Generator;
4+
5+
use Fiber;
6+
use PhpParser\Node\Expr;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\Analyser\SpecifiedTypes;
9+
use PHPStan\Analyser\TypeSpecifier;
10+
use PHPStan\Analyser\TypeSpecifierContext;
11+
use PHPStan\ShouldNotHappenException;
12+
use PHPStan\Type\Type;
13+
14+
final class GeneratorTypeSpecifier implements TypeSpecifier
15+
{
16+
17+
public function __construct(
18+
private SpecifiedTypesHelper $specifiedTypesHelper,
19+
)
20+
{
21+
}
22+
23+
public function specifyTypesInCondition(Scope $scope, Expr $expr, TypeSpecifierContext $context): SpecifiedTypes
24+
{
25+
if (!$scope instanceof GeneratorScope) {
26+
throw new ShouldNotHappenException();
27+
}
28+
29+
/** @var ExprAnalysisResult $result */
30+
$result = Fiber::suspend(ExprAnalysisRequest::createNoopRequest($expr, $scope));
31+
if ($context->null()) {
32+
return $result->specifiedNullTypes;
33+
}
34+
if ($context->truthy()) {
35+
return $result->specifiedTruthyTypes;
36+
}
37+
if ($context->falsey()) {
38+
return $result->specifiedFalseyTypes;
39+
}
40+
41+
throw new ShouldNotHappenException('Unknown TypeSpecifierContext');
42+
}
43+
44+
public function create(Expr $expr, Type $type, TypeSpecifierContext $context, Scope $scope): SpecifiedTypes
45+
{
46+
return $this->specifiedTypesHelper->create($expr, $type, $context);
47+
}
48+
49+
}

src/Analyser/Generator/SpecifiedTypesHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public function createDefaultSpecifiedFalseyTypes(Expr $expr): SpecifiedTypes
3434
return $this->create($expr, $type, TypeSpecifierContext::createFalse())->setRootExpr($expr);
3535
}
3636

37-
private function create(
37+
public function create(
3838
Expr $expr,
3939
Type $type,
4040
TypeSpecifierContext $context,

src/Analyser/TypeSpecifierFactory.php

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace PHPStan\Analyser;
44

5+
use PHPStan\Analyser\Generator\GeneratorTypeSpecifier;
6+
use PHPStan\Analyser\Generator\SpecifiedTypesHelper;
57
use PHPStan\Broker\BrokerFactory;
68
use PHPStan\DependencyInjection\AutowiredService;
79
use PHPStan\DependencyInjection\Container;
@@ -18,7 +20,7 @@ final class TypeSpecifierFactory
1820
public const METHOD_TYPE_SPECIFYING_EXTENSION_TAG = 'phpstan.typeSpecifier.methodTypeSpecifyingExtension';
1921
public const STATIC_METHOD_TYPE_SPECIFYING_EXTENSION_TAG = 'phpstan.typeSpecifier.staticMethodTypeSpecifyingExtension';
2022

21-
public function __construct(private Container $container)
23+
public function __construct(private Container $container, private bool $gnsr = false)
2224
{
2325
}
2426

@@ -27,15 +29,22 @@ public function create(): TypeSpecifier
2729
$functionTypeSpecifying = $this->container->getServicesByTag(self::FUNCTION_TYPE_SPECIFYING_EXTENSION_TAG);
2830
$methodTypeSpecifying = $this->container->getServicesByTag(self::METHOD_TYPE_SPECIFYING_EXTENSION_TAG);
2931
$staticMethodTypeSpecifying = $this->container->getServicesByTag(self::STATIC_METHOD_TYPE_SPECIFYING_EXTENSION_TAG);
30-
$typeSpecifier = new LegacyTypeSpecifier(
31-
$this->container->getByType(ExprPrinter::class),
32-
$this->container->getByType(ReflectionProvider::class),
33-
$this->container->getByType(PhpVersion::class),
34-
$functionTypeSpecifying,
35-
$methodTypeSpecifying,
36-
$staticMethodTypeSpecifying,
37-
$this->container->getParameter('rememberPossiblyImpureFunctionValues'),
38-
);
32+
33+
if ($this->gnsr) {
34+
$typeSpecifier = new GeneratorTypeSpecifier(
35+
$this->container->getByType(SpecifiedTypesHelper::class),
36+
);
37+
} else {
38+
$typeSpecifier = new LegacyTypeSpecifier(
39+
$this->container->getByType(ExprPrinter::class),
40+
$this->container->getByType(ReflectionProvider::class),
41+
$this->container->getByType(PhpVersion::class),
42+
$functionTypeSpecifying,
43+
$methodTypeSpecifying,
44+
$staticMethodTypeSpecifying,
45+
$this->container->getParameter('rememberPossiblyImpureFunctionValues'),
46+
);
47+
}
3948

4049
foreach (array_merge(
4150
$this->container->getServicesByTag(BrokerFactory::PROPERTIES_CLASS_REFLECTION_EXTENSION_TAG),

src/DependencyInjection/GnsrExtension.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\Analyser\Analyser;
99
use PHPStan\Analyser\FileAnalyser;
1010
use PHPStan\Analyser\Generator\GeneratorNodeScopeResolver;
11+
use PHPStan\Analyser\Generator\GeneratorTypeSpecifier;
1112
use PHPStan\ShouldNotHappenException;
1213
use function getenv;
1314

@@ -34,6 +35,18 @@ public function beforeCompile()
3435
throw new ShouldNotHappenException();
3536
}
3637
$fileAnalyserDef->setArgument('nodeScopeResolver', '@' . GeneratorNodeScopeResolver::class);
38+
39+
$typeSpecifierDef = $builder->getDefinition('typeSpecifier');
40+
if (!$typeSpecifierDef instanceof ServiceDefinition) {
41+
throw new ShouldNotHappenException();
42+
}
43+
$typeSpecifierDef->setType(GeneratorTypeSpecifier::class);
44+
45+
$typeSpecifierFactoryDef = $builder->getDefinition('typeSpecifierFactory');
46+
if (!$typeSpecifierFactoryDef instanceof ServiceDefinition) {
47+
throw new ShouldNotHappenException();
48+
}
49+
$typeSpecifierFactoryDef->setArgument('gnsr', true);
3750
}
3851

3952
}

0 commit comments

Comments
 (0)