Skip to content

Commit 0af1576

Browse files
committed
keepVoidType solution for GNSR
1 parent 3460e2c commit 0af1576

11 files changed

+63
-18
lines changed

build/PHPStan/Build/ScopeGetTypeInGeneratorNamespaceRule.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function processNode(Node $node, Scope $scope): array
6969
$invalidNamespace,
7070
);
7171

72-
if (in_array($methodReflection->getName(), ['getType', 'getNativeType'], true)) {
72+
if (in_array($methodReflection->getName(), ['getType', 'getNativeType', 'getKeepVoidType'], true)) {
7373
return [
7474
RuleErrorBuilder::message($message)
7575
->identifier('phpstan.scopeGetType')

src/Analyser/Generator/ExprAnalysisResult.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
final class ExprAnalysisResult
1010
{
1111

12+
public readonly Type $keepVoidType;
13+
1214
/**
1315
* @param InternalThrowPoint[] $throwPoints
1416
* @param ImpurePoint[] $impurePoints
@@ -23,8 +25,10 @@ public function __construct(
2325
public readonly array $impurePoints,
2426
public readonly SpecifiedTypes $specifiedTruthyTypes,
2527
public readonly SpecifiedTypes $specifiedFalseyTypes,
28+
?Type $keepVoidType = null,
2629
)
2730
{
31+
$this->keepVoidType = $keepVoidType ?? $type;
2832
}
2933

3034
}

src/Analyser/Generator/ExprHandler/ArrowFunctionHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ private function getArrowFunctionScope(Stmt $stmt, GeneratorScope $scope, ArrowF
187187
new VoidType(),
188188
]);
189189
} else {
190-
$returnType = $arrowFunctionExprResult->type; // todo keep void
190+
$returnType = $arrowFunctionExprResult->keepVoidType;
191191
if ($node->returnType !== null) {
192192
$nativeReturnType = $scope->getFunctionType($node->returnType, false, false);
193193
$returnType = GeneratorScope::intersectButNotNever($nativeReturnType, $returnType);

src/Analyser/Generator/ExprHandler/MethodCallHelper.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ public function methodCallReturnType(
4343
): Generator
4444
{
4545
if ($normalizedMethodCall === null) {
46-
//return $this->transformVoidToNull($parametersAcceptor->getReturnType(), $methodCall);
4746
return $parametersAcceptor->getReturnType();
4847
}
4948

@@ -83,11 +82,9 @@ public function methodCallReturnType(
8382
}
8483

8584
if (count($resolvedTypes) > 0) {
86-
//return $this->transformVoidToNull(TypeCombinator::union(...$resolvedTypes), $methodCall);
8785
return TypeCombinator::union(...$resolvedTypes);
8886
}
8987

90-
//return $this->transformVoidToNull($parametersAcceptor->getReturnType(), $methodCall);
9188
return $parametersAcceptor->getReturnType();
9289
}
9390

src/Analyser/Generator/ExprHandler/StaticCallHandler.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public function __construct(
6161
private readonly DynamicThrowTypeExtensionProvider $dynamicThrowTypeExtensionProvider,
6262
private readonly NullsafeShortCircuitingHelper $nullsafeShortCircuitingHelper,
6363
private readonly MethodCallHelper $methodCallHelper,
64+
private readonly VoidTypeHelper $voidTypeHelper,
6465
#[AutowiredParameter(ref: '%exceptions.implicitThrows%')]
6566
private readonly bool $implicitThrows,
6667
)
@@ -262,9 +263,10 @@ public function analyseExpr(Stmt $stmt, Expr $expr, GeneratorScope $scope, Expre
262263
}
263264

264265
return new ExprAnalysisResult(
265-
$methodReturnType,
266-
$nativeMethodReturnType,
267-
$scope,
266+
$this->voidTypeHelper->transformVoidToNull($methodReturnType),
267+
$this->voidTypeHelper->transformVoidToNull($nativeMethodReturnType),
268+
keepVoidType: $methodReturnType,
269+
scope: $scope,
268270
hasYield: $hasYield || $argsResult->hasYield,
269271
isAlwaysTerminating: ($methodReturnType instanceof NeverType && $methodReturnType->isExplicit()) || $argsResult->isAlwaysTerminating,
270272
throwPoints: array_merge($throwPoints, $argsResult->throwPoints),
@@ -392,9 +394,10 @@ private function processClassExpr(Stmt $stmt, StaticCall $expr, Expr $class, Gen
392394
$scope = $argsResult->scope;
393395

394396
return new ExprAnalysisResult(
395-
$methodReturnType,
396-
$nativeMethodReturnType,
397-
$scope,
397+
$this->voidTypeHelper->transformVoidToNull($methodReturnType),
398+
$this->voidTypeHelper->transformVoidToNull($nativeMethodReturnType),
399+
keepVoidType: $methodReturnType,
400+
scope: $scope,
398401
hasYield: $hasYield || $argsResult->hasYield,
399402
isAlwaysTerminating: $isAlwaysTerminating || $argsResult->isAlwaysTerminating,
400403
throwPoints: array_merge($throwPoints, $argsResult->throwPoints),
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\Generator\ExprHandler;
4+
5+
use PHPStan\DependencyInjection\AutowiredService;
6+
use PHPStan\Type\IntersectionType;
7+
use PHPStan\Type\NullType;
8+
use PHPStan\Type\Type;
9+
use PHPStan\Type\TypeTraverser;
10+
use PHPStan\Type\UnionType;
11+
12+
#[AutowiredService]
13+
final class VoidTypeHelper
14+
{
15+
16+
public function transformVoidToNull(Type $type): Type
17+
{
18+
return TypeTraverser::map($type, static function (Type $type, callable $traverse): Type {
19+
if ($type instanceof UnionType || $type instanceof IntersectionType) {
20+
return $traverse($type);
21+
}
22+
23+
if ($type->isVoid()->yes()) {
24+
return new NullType();
25+
}
26+
27+
return $type;
28+
});
29+
}
30+
31+
}

src/Analyser/Generator/GeneratorNodeScopeResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ private function analyseExprForType(ExprAnalysisResultStorage $storage, Expr $ex
541541
$result = $storage->findExprAnalysisResult($expr);
542542
if ($result !== null) {
543543
yield from [];
544-
return new TypeExprResult($result->type, $result->nativeType);
544+
return new TypeExprResult($result->type, $result->nativeType, $result->keepVoidType);
545545
}
546546

547547
throw new ShouldNotHappenException('Not yet implemented - park expr request for type until later when it has been analysed');

src/Analyser/Generator/GeneratorScope.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2473,8 +2473,11 @@ private function promoteNativeTypes(): self
24732473

24742474
public function getKeepVoidType(Expr $node): Type
24752475
{
2476-
// TODO: Implement getKeepVoidType() method.
2477-
throw new ShouldNotHappenException('Not implemented yet');
2476+
return TypeUtils::resolveLateResolvableTypes(
2477+
Fiber::suspend(
2478+
new ExprAnalysisRequest(new Node\Stmt\Expression($node), $node, $this, ExpressionContext::createTopLevel(), new NoopNodeCallback()),
2479+
)->keepVoidType,
2480+
);
24782481
}
24792482

24802483
/**

src/Analyser/Generator/TypeExprResult.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ final class TypeExprResult
1010
public function __construct(
1111
public readonly Type $type,
1212
public readonly Type $nativeType,
13+
public readonly Type $keepVoidType,
1314
)
1415
{
1516
}

tests/PHPStan/Build/ScopeGetTypeInGeneratorNamespaceRuleTest.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,26 @@ public function testRule(): void
3939
49,
4040
'Use yield new TypeExprRequest instead.',
4141
],
42+
[
43+
'Scope::getKeepVoidType() cannot be called in PHPStan\Analyser\Generator namespace.',
44+
50,
45+
'Use yield new TypeExprRequest instead.',
46+
],
4247
[
4348
'Scope::filterByTruthyValue() cannot be called in PHPStan\Analyser\Generator namespace.',
44-
59,
49+
60,
4550
],
4651
[
4752
'Scope::filterByFalseyValue() cannot be called in PHPStan\Analyser\Generator namespace.',
48-
60,
53+
61,
4954
],
5055
[
5156
'Scope::filterByTruthyValue() cannot be called in PHPStan\Analyser\Generator namespace.',
52-
65,
57+
66,
5358
],
5459
[
5560
'Scope::filterByFalseyValue() cannot be called in PHPStan\Analyser\Generator namespace.',
56-
66,
61+
67,
5762
],
5863
]);
5964
}

0 commit comments

Comments
 (0)