From 2b2bd9e53adc02808e64678efdf87e06b953e25c Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 1 Sep 2024 23:06:03 +0200 Subject: [PATCH] TypeSpecifier: Narrow `(int) $expr` like `$expr != false` --- src/Analyser/TypeSpecifier.php | 8 ++++--- .../{narrow-bool-cast.php => narrow-cast.php} | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) rename tests/PHPStan/Analyser/nsrt/{narrow-bool-cast.php => narrow-cast.php} (70%) diff --git a/src/Analyser/TypeSpecifier.php b/src/Analyser/TypeSpecifier.php index 66a60954b6..69b72a1772 100644 --- a/src/Analyser/TypeSpecifier.php +++ b/src/Analyser/TypeSpecifier.php @@ -196,15 +196,17 @@ public function specifyTypesInCondition( $context, $rootExpr, ); - } elseif ($expr instanceof Expr\Cast\String_) { + } elseif ( + $expr instanceof Expr\Cast\String_ + || $expr instanceof Expr\Cast\Int_ + || $expr instanceof Expr\Cast\Bool_ + ) { return $this->specifyTypesInCondition( $scope, new Node\Expr\BinaryOp\NotEqual($expr->expr, new ConstFetch(new Name\FullyQualified('false'))), $context, $rootExpr, ); - } elseif ($expr instanceof Expr\Cast\Bool_) { - return $this->resolveEqual(new Expr\BinaryOp\Equal($expr->expr, new ConstFetch(new Name\FullyQualified('true'))), $scope, $context, $rootExpr); } elseif ($expr instanceof Node\Expr\BinaryOp\Equal) { return $this->resolveEqual($expr, $scope, $context, $rootExpr); } elseif ($expr instanceof Node\Expr\BinaryOp\NotEqual) { diff --git a/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php b/tests/PHPStan/Analyser/nsrt/narrow-cast.php similarity index 70% rename from tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php rename to tests/PHPStan/Analyser/nsrt/narrow-cast.php index ea9486a77d..0d883cd6ba 100644 --- a/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php +++ b/tests/PHPStan/Analyser/nsrt/narrow-cast.php @@ -48,3 +48,24 @@ function castString($x, string $s, bool $b) { assertType('string', $s); } } + +/** @param int<-5, 5> $x */ +function castInt($x, string $s, bool $b) { + if ((int) $x) { + assertType('int<-5, -1>|int<1, 5>', $x); + } else { + assertType('0', $x); + } + + if ((int) $b) { + assertType('true', $b); + } else { + assertType('false', $b); + } + + if ((int) strpos($s, 'xy')) { + assertType('non-falsy-string', $s); + } else { + assertType('string', $s); + } +}