Skip to content

Commit d1c5f09

Browse files
committed
Implement UnaryMinusHandler
1 parent 61b221c commit d1c5f09

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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+
17+
/**
18+
* @implements ExprHandler<Expr\UnaryMinus>
19+
*/
20+
#[AutowiredService]
21+
final class UnaryMinusHandler implements ExprHandler
22+
{
23+
24+
public function __construct(private InitializerExprTypeResolver $initializerExprTypeResolver)
25+
{
26+
}
27+
28+
public function supports(Expr $expr): bool
29+
{
30+
return $expr instanceof Expr\UnaryMinus;
31+
}
32+
33+
public function analyseExpr(Stmt $stmt, Expr $expr, GeneratorScope $scope, ExpressionContext $context, ?callable $alternativeNodeCallback): Generator
34+
{
35+
$result = yield new ExprAnalysisRequest($stmt, $expr->expr, $scope, $context->enterDeep(), $alternativeNodeCallback);
36+
37+
return new ExprAnalysisResult(
38+
$this->initializerExprTypeResolver->getUnaryMinusTypeFromType($expr->expr, $result->type),
39+
$this->initializerExprTypeResolver->getUnaryMinusTypeFromType($expr->expr, $result->nativeType),
40+
$result->scope,
41+
hasYield: $result->hasYield,
42+
isAlwaysTerminating: $result->isAlwaysTerminating,
43+
throwPoints: $result->throwPoints,
44+
impurePoints: $result->impurePoints,
45+
specifiedTruthyTypes: new SpecifiedTypes(),
46+
specifiedFalseyTypes: new SpecifiedTypes(),
47+
specifiedNullTypes: new SpecifiedTypes(),
48+
);
49+
}
50+
51+
}

src/Reflection/InitializerExprTypeResolver.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2522,7 +2522,14 @@ public function getClassConstFetchType(Name|Expr $class, string $constantName, ?
25222522
*/
25232523
public function getUnaryMinusType(Expr $expr, callable $getTypeCallback): Type
25242524
{
2525-
$type = $getTypeCallback($expr)->toNumber();
2525+
$type = $getTypeCallback($expr);
2526+
2527+
return $this->getUnaryMinusTypeFromType($expr, $type);
2528+
}
2529+
2530+
public function getUnaryMinusTypeFromType(Expr $expr, Type $type): Type
2531+
{
2532+
$type = $type->toNumber();
25262533
$scalarValues = $type->getConstantScalarValues();
25272534

25282535
if (count($scalarValues) > 0) {

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ public function doConcat($a, $b, string $c, string $d): void
191191
assertNativeType('string', $c . $d);
192192
}
193193

194-
function doUnaryPlus(int $i) {
194+
function doUnaryPlus(int $i)
195+
{
195196
$a = '1';
196197

197198
assertType('1', +$a);
@@ -200,6 +201,15 @@ function doUnaryPlus(int $i) {
200201
assertNativeType('int', +$i);
201202
}
202203

204+
function doUnaryMinus(int $i) {
205+
$a = '1';
206+
207+
assertType('-1', -$a);
208+
assertNativeType('-1', -$a);
209+
assertType('int', -$i);
210+
assertNativeType('int', -$i);
211+
}
212+
203213
/**
204214
* @param int $a
205215
* @param int $b

0 commit comments

Comments
 (0)