Skip to content

Commit 01e44e0

Browse files
staabmondrejmirtes
authored andcommitted
Implement SpaceshipHandler
1 parent 46da18d commit 01e44e0

File tree

3 files changed

+78
-4
lines changed

3 files changed

+78
-4
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\Generator\ExprHandler;
4+
5+
use Generator;
6+
use PhpParser\Node\Expr;
7+
use PhpParser\Node\Stmt;
8+
use PHPStan\Analyser\ExpressionContext;
9+
use PHPStan\Analyser\Generator\ExprAnalysisRequest;
10+
use PHPStan\Analyser\Generator\ExprAnalysisResult;
11+
use PHPStan\Analyser\Generator\ExprHandler;
12+
use PHPStan\Analyser\Generator\GeneratorScope;
13+
use PHPStan\Analyser\SpecifiedTypes;
14+
use PHPStan\DependencyInjection\AutowiredService;
15+
use PHPStan\Reflection\InitializerExprTypeResolver;
16+
use function array_merge;
17+
18+
/**
19+
* @implements ExprHandler<Expr\BinaryOp\Spaceship>
20+
*/
21+
#[AutowiredService]
22+
final class SpaceshipHandler implements ExprHandler
23+
{
24+
25+
public function __construct(private InitializerExprTypeResolver $initializerExprTypeResolver)
26+
{
27+
}
28+
29+
public function supports(Expr $expr): bool
30+
{
31+
return $expr instanceof Expr\BinaryOp\Spaceship;
32+
}
33+
34+
public function analyseExpr(Stmt $stmt, Expr $expr, GeneratorScope $scope, ExpressionContext $context, ?callable $alternativeNodeCallback): Generator
35+
{
36+
$leftResult = yield new ExprAnalysisRequest($stmt, $expr->left, $scope, $context, $alternativeNodeCallback);
37+
$rightResult = yield new ExprAnalysisRequest($stmt, $expr->right, $leftResult->scope, $context, $alternativeNodeCallback);
38+
39+
return new ExprAnalysisResult(
40+
$this->initializerExprTypeResolver->getSpaceshipTypeFromTypes($leftResult->type, $rightResult->type),
41+
$this->initializerExprTypeResolver->getSpaceshipTypeFromTypes($leftResult->nativeType, $rightResult->nativeType),
42+
$rightResult->scope,
43+
hasYield: $leftResult->hasYield || $rightResult->hasYield,
44+
isAlwaysTerminating: $leftResult->isAlwaysTerminating || $rightResult->isAlwaysTerminating,
45+
throwPoints: array_merge($leftResult->throwPoints, $rightResult->throwPoints),
46+
impurePoints: array_merge($leftResult->impurePoints, $rightResult->impurePoints),
47+
specifiedTruthyTypes: new SpecifiedTypes(),
48+
specifiedFalseyTypes: new SpecifiedTypes(),
49+
specifiedNullTypes: new SpecifiedTypes(),
50+
);
51+
}
52+
53+
}

src/Reflection/InitializerExprTypeResolver.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,12 +1156,17 @@ public function getSpaceshipType(Expr $left, Expr $right, callable $getTypeCallb
11561156
$callbackLeftType = $getTypeCallback($left);
11571157
$callbackRightType = $getTypeCallback($right);
11581158

1159-
if ($callbackLeftType instanceof NeverType || $callbackRightType instanceof NeverType) {
1160-
return $this->getNeverType($callbackLeftType, $callbackRightType);
1159+
return $this->getSpaceshipTypeFromTypes($callbackLeftType, $callbackRightType);
1160+
}
1161+
1162+
public function getSpaceshipTypeFromTypes(Type $leftTypes, Type $rightTypes): Type
1163+
{
1164+
if ($leftTypes instanceof NeverType || $rightTypes instanceof NeverType) {
1165+
return $this->getNeverType($leftTypes, $rightTypes);
11611166
}
11621167

1163-
$leftTypes = $callbackLeftType->getConstantScalarTypes();
1164-
$rightTypes = $callbackRightType->getConstantScalarTypes();
1168+
$leftTypes = $leftTypes->getConstantScalarTypes();
1169+
$rightTypes = $rightTypes->getConstantScalarTypes();
11651170

11661171
$leftTypesCount = count($leftTypes);
11671172
$rightTypesCount = count($rightTypes);

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,22 @@ public function doShiftRight($a, $b, int $c, int $d): void
220220
assertType('int', $c >> $d);
221221
assertNativeType('int', $c >> $d);
222222
}
223+
224+
/**
225+
* @param string $a
226+
* @param string $b
227+
* @return void
228+
*/
229+
public function doSpaceship($a, $b, string $c, string $d): void
230+
{
231+
assertType('int<-1, 1>', $a <=> $b);
232+
assertNativeType('int<-1, 1>', $a <=> $b);
233+
assertType('-1', '1' <=> 'a');
234+
assertNativeType('-1', '1' <=> 'a');
235+
assertType('int<-1, 1>', $c <=> $d);
236+
assertNativeType('int<-1, 1>', $c <=> $d);
237+
}
238+
223239
}
224240

225241
function (): void {

0 commit comments

Comments
 (0)