From 6427f14430e3acc205ad128b3343ff70ee115a2d Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 1 Sep 2024 10:15:55 +0200 Subject: [PATCH 1/7] TypeSpecifier: Narrow `(bool) $expr` like `$expr == true` --- src/Analyser/TypeSpecifier.php | 2 ++ .../Analyser/LegacyNodeScopeResolverTest.php | 4 +-- .../Analyser/nsrt/narrow-bool-cast.php | 29 +++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php diff --git a/src/Analyser/TypeSpecifier.php b/src/Analyser/TypeSpecifier.php index e5bd2bbd57..b279185906 100644 --- a/src/Analyser/TypeSpecifier.php +++ b/src/Analyser/TypeSpecifier.php @@ -196,6 +196,8 @@ public function specifyTypesInCondition( $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/LegacyNodeScopeResolverTest.php b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php index 4d0ca33581..1b67568efa 100644 --- a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php @@ -355,7 +355,7 @@ public function dataAssignInIf(): array $testScope, 'matches3', TrinaryLogic::createYes(), - 'array{0?: string}', + 'array{}|array{string}', ], [ $testScope, @@ -415,7 +415,7 @@ public function dataAssignInIf(): array $testScope, 'ternaryMatches', TrinaryLogic::createYes(), - 'array{0?: string}', + 'array{string}', ], [ $testScope, diff --git a/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php b/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php new file mode 100644 index 0000000000..582062deb7 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php @@ -0,0 +1,29 @@ + $arr */ +function doFoo(string $x, array $arr): void { + if ((bool) strlen($x)) { + assertType('string', $x); // could be non-empty-string + } else { + assertType('string', $x); + } + assertType('string', $x); + + if ((bool) array_search($x, $arr, true)) { + assertType('non-empty-array', $arr); + } else { + assertType('array', $arr); + } + assertType('string', $x); + + if ((bool) preg_match('~.*~', $x, $matches)) { + assertType('array{string}', $matches); + } else { + assertType('array{}', $matches); + } + assertType('array{}|array{string}', $matches); +} From d6de4dc00ac2a622e102d86aba4c32a22e4a1ad1 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 1 Sep 2024 10:33:40 +0200 Subject: [PATCH 2/7] added regression test --- .../PHPStan/Rules/Functions/ReturnTypeRuleTest.php | 7 +++++++ tests/PHPStan/Rules/Functions/data/bug-8881.php | 13 +++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/PHPStan/Rules/Functions/data/bug-8881.php diff --git a/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php index 45ddca1767..f16d288869 100644 --- a/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php @@ -290,4 +290,11 @@ public function testBug11518(): void $this->analyse([__DIR__ . '/data/bug-11518.php'], []); } + public function testBug8881(): void + { + $this->checkExplicitMixed = true; + $this->checkNullables = true; + $this->analyse([__DIR__ . '/data/bug-8881.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Functions/data/bug-8881.php b/tests/PHPStan/Rules/Functions/data/bug-8881.php new file mode 100644 index 0000000000..85c59c4fae --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-8881.php @@ -0,0 +1,13 @@ + Date: Sun, 1 Sep 2024 10:39:21 +0200 Subject: [PATCH 3/7] regression test --- tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php b/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php index 582062deb7..eab6a4308b 100644 --- a/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php +++ b/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php @@ -27,3 +27,15 @@ function doFoo(string $x, array $arr): void { } assertType('array{}|array{string}', $matches); } + + +interface Reader { + public function getFilePath(): string|false; +} + +function bug7685(Reader $reader): void { + $filePath = $reader->getFilePath(); + if (false !== (bool) $filePath) { + assertType('non-falsy-string', $filePath); + } +} From 32b251b986b0faedb64e5f0f3bd68f3612c52337 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 1 Sep 2024 10:41:32 +0200 Subject: [PATCH 4/7] regression test --- tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php b/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php index eab6a4308b..b4ab1924a5 100644 --- a/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php +++ b/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php @@ -39,3 +39,15 @@ function bug7685(Reader $reader): void { assertType('non-falsy-string', $filePath); } } + +function bug6006() { + /** @var array $data */ + $data = [ + 'name' => 'John', + 'dob' => null, + ]; + + $data = array_filter($data, fn(?string $input): bool => (bool)$input); + + assertType('', $data); +} From 58edd534add90b10f1081c7382592740ae23aa1e Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 1 Sep 2024 10:43:36 +0200 Subject: [PATCH 5/7] added regression test --- tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php b/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php index b4ab1924a5..76b6703232 100644 --- a/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php +++ b/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php @@ -49,5 +49,16 @@ function bug6006() { $data = array_filter($data, fn(?string $input): bool => (bool)$input); - assertType('', $data); + assertType('array', $data); +} + +function bug10528(string $string): void { + $pos = strpos('*', $string); + assert((bool) $pos); + + assertType('int<1, max>', $pos); + + $sub = substr($string, 0, $pos); + assert($pos !== FALSE); + $sub = substr($string, 0, $pos); } From 5b1543a82df9f5d0ce24b100ca96cbe2e24e2dd3 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 1 Sep 2024 15:49:01 +0200 Subject: [PATCH 6/7] one test per bug --- tests/PHPStan/Analyser/nsrt/bug10528.php | 17 +++++++++ tests/PHPStan/Analyser/nsrt/bug6006.php | 19 ++++++++++ tests/PHPStan/Analyser/nsrt/bug7685.php | 17 +++++++++ .../Analyser/nsrt/narrow-bool-cast.php | 35 ------------------- 4 files changed, 53 insertions(+), 35 deletions(-) create mode 100644 tests/PHPStan/Analyser/nsrt/bug10528.php create mode 100644 tests/PHPStan/Analyser/nsrt/bug6006.php create mode 100644 tests/PHPStan/Analyser/nsrt/bug7685.php diff --git a/tests/PHPStan/Analyser/nsrt/bug10528.php b/tests/PHPStan/Analyser/nsrt/bug10528.php new file mode 100644 index 0000000000..07fe77ade0 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug10528.php @@ -0,0 +1,17 @@ +', $pos); + + $sub = substr($string, 0, $pos); + assert($pos !== FALSE); + $sub = substr($string, 0, $pos); +} + diff --git a/tests/PHPStan/Analyser/nsrt/bug6006.php b/tests/PHPStan/Analyser/nsrt/bug6006.php new file mode 100644 index 0000000000..e9ad4e2464 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug6006.php @@ -0,0 +1,19 @@ + $data */ + $data = [ + 'name' => 'John', + 'dob' => null, + ]; + + $data = array_filter($data, fn(?string $input): bool => (bool)$input); + + assertType('array', $data); +} + + diff --git a/tests/PHPStan/Analyser/nsrt/bug7685.php b/tests/PHPStan/Analyser/nsrt/bug7685.php new file mode 100644 index 0000000000..580ad7f33f --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug7685.php @@ -0,0 +1,17 @@ +getFilePath(); + if (false !== (bool) $filePath) { + assertType('non-falsy-string', $filePath); + } +} + diff --git a/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php b/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php index 76b6703232..582062deb7 100644 --- a/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php +++ b/tests/PHPStan/Analyser/nsrt/narrow-bool-cast.php @@ -27,38 +27,3 @@ function doFoo(string $x, array $arr): void { } assertType('array{}|array{string}', $matches); } - - -interface Reader { - public function getFilePath(): string|false; -} - -function bug7685(Reader $reader): void { - $filePath = $reader->getFilePath(); - if (false !== (bool) $filePath) { - assertType('non-falsy-string', $filePath); - } -} - -function bug6006() { - /** @var array $data */ - $data = [ - 'name' => 'John', - 'dob' => null, - ]; - - $data = array_filter($data, fn(?string $input): bool => (bool)$input); - - assertType('array', $data); -} - -function bug10528(string $string): void { - $pos = strpos('*', $string); - assert((bool) $pos); - - assertType('int<1, max>', $pos); - - $sub = substr($string, 0, $pos); - assert($pos !== FALSE); - $sub = substr($string, 0, $pos); -} From 02c971a95518fab90341f10a3616a416c088bae9 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 1 Sep 2024 15:51:20 +0200 Subject: [PATCH 7/7] move --- tests/PHPStan/Analyser/nsrt/{bug10528.php => bug-10528.php} | 0 tests/PHPStan/Analyser/nsrt/{bug6006.php => bug-6006.php} | 0 tests/PHPStan/Analyser/nsrt/{bug7685.php => bug-7685.php} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tests/PHPStan/Analyser/nsrt/{bug10528.php => bug-10528.php} (100%) rename tests/PHPStan/Analyser/nsrt/{bug6006.php => bug-6006.php} (100%) rename tests/PHPStan/Analyser/nsrt/{bug7685.php => bug-7685.php} (100%) diff --git a/tests/PHPStan/Analyser/nsrt/bug10528.php b/tests/PHPStan/Analyser/nsrt/bug-10528.php similarity index 100% rename from tests/PHPStan/Analyser/nsrt/bug10528.php rename to tests/PHPStan/Analyser/nsrt/bug-10528.php diff --git a/tests/PHPStan/Analyser/nsrt/bug6006.php b/tests/PHPStan/Analyser/nsrt/bug-6006.php similarity index 100% rename from tests/PHPStan/Analyser/nsrt/bug6006.php rename to tests/PHPStan/Analyser/nsrt/bug-6006.php diff --git a/tests/PHPStan/Analyser/nsrt/bug7685.php b/tests/PHPStan/Analyser/nsrt/bug-7685.php similarity index 100% rename from tests/PHPStan/Analyser/nsrt/bug7685.php rename to tests/PHPStan/Analyser/nsrt/bug-7685.php