From bcf4b4ac570f8023399567a95009541ef0dbd76b Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 30 Nov 2025 10:12:43 +0100 Subject: [PATCH] Implement Cast*Handler --- .../ExprHandler/CastArrayHandler.php | 52 +++++++++++++++++++ .../Generator/ExprHandler/CastBoolHandler.php | 52 +++++++++++++++++++ .../ExprHandler/CastDoubleHandler.php | 52 +++++++++++++++++++ .../ExprHandler/CastStringHandler.php | 52 +++++++++++++++++++ .../PHPStan/Analyser/Generator/data/gnsr.php | 11 ++++ 5 files changed, 219 insertions(+) create mode 100644 src/Analyser/Generator/ExprHandler/CastArrayHandler.php create mode 100644 src/Analyser/Generator/ExprHandler/CastBoolHandler.php create mode 100644 src/Analyser/Generator/ExprHandler/CastDoubleHandler.php create mode 100644 src/Analyser/Generator/ExprHandler/CastStringHandler.php diff --git a/src/Analyser/Generator/ExprHandler/CastArrayHandler.php b/src/Analyser/Generator/ExprHandler/CastArrayHandler.php new file mode 100644 index 0000000000..47ecb8175b --- /dev/null +++ b/src/Analyser/Generator/ExprHandler/CastArrayHandler.php @@ -0,0 +1,52 @@ + + */ +#[AutowiredService] +final class CastArrayHandler implements ExprHandler +{ + + public function supports(Expr $expr): bool + { + return $expr instanceof Expr\Cast\Array_; + } + + public function analyseExpr( + Stmt $stmt, + Expr $expr, + GeneratorScope $scope, + ExpressionContext $context, + ?callable $alternativeNodeCallback, + ): Generator + { + $exprResult = yield new ExprAnalysisRequest($stmt, $expr->expr, $scope, $context->enterDeep(), $alternativeNodeCallback); + + return new ExprAnalysisResult( + $exprResult->type->toArray(), + $exprResult->nativeType->toArray(), + $scope, + hasYield: false, + isAlwaysTerminating: false, + throwPoints: [], + impurePoints: [], + specifiedTruthyTypes: new SpecifiedTypes(), + specifiedFalseyTypes: new SpecifiedTypes(), + specifiedNullTypes: new SpecifiedTypes(), + ); + } + +} diff --git a/src/Analyser/Generator/ExprHandler/CastBoolHandler.php b/src/Analyser/Generator/ExprHandler/CastBoolHandler.php new file mode 100644 index 0000000000..5fd5c8a672 --- /dev/null +++ b/src/Analyser/Generator/ExprHandler/CastBoolHandler.php @@ -0,0 +1,52 @@ + + */ +#[AutowiredService] +final class CastBoolHandler implements ExprHandler +{ + + public function supports(Expr $expr): bool + { + return $expr instanceof Expr\Cast\Bool_; + } + + public function analyseExpr( + Stmt $stmt, + Expr $expr, + GeneratorScope $scope, + ExpressionContext $context, + ?callable $alternativeNodeCallback, + ): Generator + { + $exprResult = yield new ExprAnalysisRequest($stmt, $expr->expr, $scope, $context->enterDeep(), $alternativeNodeCallback); + + return new ExprAnalysisResult( + $exprResult->type->toBoolean(), + $exprResult->nativeType->toBoolean(), + $scope, + hasYield: false, + isAlwaysTerminating: false, + throwPoints: [], + impurePoints: [], + specifiedTruthyTypes: new SpecifiedTypes(), + specifiedFalseyTypes: new SpecifiedTypes(), + specifiedNullTypes: new SpecifiedTypes(), + ); + } + +} diff --git a/src/Analyser/Generator/ExprHandler/CastDoubleHandler.php b/src/Analyser/Generator/ExprHandler/CastDoubleHandler.php new file mode 100644 index 0000000000..e702813628 --- /dev/null +++ b/src/Analyser/Generator/ExprHandler/CastDoubleHandler.php @@ -0,0 +1,52 @@ + + */ +#[AutowiredService] +final class CastDoubleHandler implements ExprHandler +{ + + public function supports(Expr $expr): bool + { + return $expr instanceof Expr\Cast\Double; + } + + public function analyseExpr( + Stmt $stmt, + Expr $expr, + GeneratorScope $scope, + ExpressionContext $context, + ?callable $alternativeNodeCallback, + ): Generator + { + $exprResult = yield new ExprAnalysisRequest($stmt, $expr->expr, $scope, $context->enterDeep(), $alternativeNodeCallback); + + return new ExprAnalysisResult( + $exprResult->type->toFloat(), + $exprResult->nativeType->toFloat(), + $scope, + hasYield: false, + isAlwaysTerminating: false, + throwPoints: [], + impurePoints: [], + specifiedTruthyTypes: new SpecifiedTypes(), + specifiedFalseyTypes: new SpecifiedTypes(), + specifiedNullTypes: new SpecifiedTypes(), + ); + } + +} diff --git a/src/Analyser/Generator/ExprHandler/CastStringHandler.php b/src/Analyser/Generator/ExprHandler/CastStringHandler.php new file mode 100644 index 0000000000..766e4d9ad8 --- /dev/null +++ b/src/Analyser/Generator/ExprHandler/CastStringHandler.php @@ -0,0 +1,52 @@ + + */ +#[AutowiredService] +final class CastStringHandler implements ExprHandler +{ + + public function supports(Expr $expr): bool + { + return $expr instanceof Expr\Cast\String_; + } + + public function analyseExpr( + Stmt $stmt, + Expr $expr, + GeneratorScope $scope, + ExpressionContext $context, + ?callable $alternativeNodeCallback, + ): Generator + { + $exprResult = yield new ExprAnalysisRequest($stmt, $expr->expr, $scope, $context->enterDeep(), $alternativeNodeCallback); + + return new ExprAnalysisResult( + $exprResult->type->toString(), + $exprResult->nativeType->toString(), + $scope, + hasYield: false, + isAlwaysTerminating: false, + throwPoints: [], + impurePoints: [], + specifiedTruthyTypes: new SpecifiedTypes(), + specifiedFalseyTypes: new SpecifiedTypes(), + specifiedNullTypes: new SpecifiedTypes(), + ); + } + +} diff --git a/tests/PHPStan/Analyser/Generator/data/gnsr.php b/tests/PHPStan/Analyser/Generator/data/gnsr.php index aadd6edb21..2d3cc50649 100644 --- a/tests/PHPStan/Analyser/Generator/data/gnsr.php +++ b/tests/PHPStan/Analyser/Generator/data/gnsr.php @@ -236,6 +236,17 @@ public function doSpaceship($a, $b, string $c, string $d): void assertNativeType('int<-1, 1>', $c <=> $d); } + function doCast() { + $a = '1'; + + assertType('1', (int) $a); + assertType("array{'1'}", (array) $a); + // assertType("array{'1'}", (object) $a); + assertType('1.0', (double) $a); + assertType('true', (bool) $a); + assertType("'1'", (string) $a); + } + } function (): void {