From c0c9d1f56f6c6220bc8d65674ea902c51702fb0b Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 11 Jan 2025 11:21:17 +0100 Subject: [PATCH 1/5] More precise constant variants of BooleanType --- src/Type/BooleanType.php | 12 +++++++++++- src/Type/Php/StrlenFunctionReturnTypeExtension.php | 13 +------------ tests/PHPStan/Analyser/nsrt/bug-11201.php | 2 +- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/Type/BooleanType.php b/src/Type/BooleanType.php index 0b0eb798ec..aeccddddf0 100644 --- a/src/Type/BooleanType.php +++ b/src/Type/BooleanType.php @@ -41,9 +41,19 @@ public function __construct() { } + public function getConstantScalarTypes(): array + { + return [new ConstantBooleanType(true), new ConstantBooleanType(false)]; + } + public function getConstantStrings(): array { - return []; + return [new ConstantStringType('1'), new ConstantStringType('0')]; + } + + public function getConstantScalarValues(): array + { + return [true, false]; } public function describe(VerbosityLevel $level): string diff --git a/src/Type/Php/StrlenFunctionReturnTypeExtension.php b/src/Type/Php/StrlenFunctionReturnTypeExtension.php index e50dc20676..40b1c85587 100644 --- a/src/Type/Php/StrlenFunctionReturnTypeExtension.php +++ b/src/Type/Php/StrlenFunctionReturnTypeExtension.php @@ -5,8 +5,6 @@ use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Type\BooleanType; -use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\DynamicFunctionReturnTypeExtension; @@ -44,16 +42,7 @@ public function getTypeFromFunctionCall( } $argType = $scope->getType($args[0]->value); - - if ($argType->isSuperTypeOf(new BooleanType())->yes()) { - $constantScalars = TypeCombinator::remove($argType, new BooleanType())->getConstantScalarTypes(); - if (count($constantScalars) > 0) { - $constantScalars[] = new ConstantBooleanType(true); - $constantScalars[] = new ConstantBooleanType(false); - } - } else { - $constantScalars = $argType->getConstantScalarTypes(); - } + $constantScalars = $argType->getConstantScalarTypes(); $lengths = []; foreach ($constantScalars as $constantScalar) { diff --git a/tests/PHPStan/Analyser/nsrt/bug-11201.php b/tests/PHPStan/Analyser/nsrt/bug-11201.php index 202e5b1700..17890a823c 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-11201.php +++ b/tests/PHPStan/Analyser/nsrt/bug-11201.php @@ -53,4 +53,4 @@ function returnsBool(): bool { assertType("' 1'", $s); $s = sprintf('%20s', returnsBool()); -assertType("lowercase-string&non-falsy-string", $s); +assertType("' '|' 1'", $s); From 2659130b33d2e9ea3cfd91d23b634e8461fb7ab4 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 11 Jan 2025 11:30:55 +0100 Subject: [PATCH 2/5] simplify MbStrlenFunctionReturnTypeExtension --- src/Type/Php/MbStrlenFunctionReturnTypeExtension.php | 12 +----------- tests/PHPStan/Analyser/nsrt/bug-10952b.php | 9 +++++++++ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Type/Php/MbStrlenFunctionReturnTypeExtension.php b/src/Type/Php/MbStrlenFunctionReturnTypeExtension.php index 73bdfa483f..84464f30bd 100644 --- a/src/Type/Php/MbStrlenFunctionReturnTypeExtension.php +++ b/src/Type/Php/MbStrlenFunctionReturnTypeExtension.php @@ -8,7 +8,6 @@ use PHPStan\Reflection\FunctionReflection; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\ShouldNotHappenException; -use PHPStan\Type\BooleanType; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; @@ -93,16 +92,7 @@ public function getTypeFromFunctionCall( } $argType = $scope->getType($args[0]->value); - - if ($argType->isSuperTypeOf(new BooleanType())->yes()) { - $constantScalars = TypeCombinator::remove($argType, new BooleanType())->getConstantScalarTypes(); - if (count($constantScalars) > 0) { - $constantScalars[] = new ConstantBooleanType(true); - $constantScalars[] = new ConstantBooleanType(false); - } - } else { - $constantScalars = $argType->getConstantScalarTypes(); - } + $constantScalars = $argType->getConstantScalarTypes(); $lengths = []; foreach ($constantScalars as $constantScalar) { diff --git a/tests/PHPStan/Analyser/nsrt/bug-10952b.php b/tests/PHPStan/Analyser/nsrt/bug-10952b.php index f8f70e07d0..02386aa4b7 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-10952b.php +++ b/tests/PHPStan/Analyser/nsrt/bug-10952b.php @@ -37,5 +37,14 @@ public function test(): void mb_strlen($string) > 0 => assertType('non-empty-string', $string), default => assertType("''", $string), }; + + assertType('int<0, 1>', strlen($this->getBool())); + assertType('int<0, 1>', mb_strlen($this->getBool())); } + + public function getBool(): bool + { + return rand(0, 1) === 1; + } + } From b1c847ec89455203713937839d97eb9b29e4a0bb Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 11 Jan 2025 12:09:14 +0100 Subject: [PATCH 3/5] test implode() resolves unions with bool --- tests/PHPStan/Analyser/nsrt/implode.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/PHPStan/Analyser/nsrt/implode.php b/tests/PHPStan/Analyser/nsrt/implode.php index 51e121a4c1..16f060465c 100644 --- a/tests/PHPStan/Analyser/nsrt/implode.php +++ b/tests/PHPStan/Analyser/nsrt/implode.php @@ -51,4 +51,9 @@ public function constArrays5($constArr) { public function constArrays6($constArr) { assertType("string", implode('', $constArr)); } + + /** @param array{10: 1|2|bool, xy: 'a'|'b'|'c'} $constArr */ + public function constArrays7($constArr) { + assertType("'1a'|'1b'|'1c'|'2a'|'2b'|'2c'|'a'|'b'|'c'", implode('', $constArr)); + } } From 554783ee9bc48fd3e2d6ff302a830aa1d1dfd293 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 11 Jan 2025 14:16:25 +0100 Subject: [PATCH 4/5] Update BooleanType.php --- src/Type/BooleanType.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Type/BooleanType.php b/src/Type/BooleanType.php index aeccddddf0..94c40ef8fc 100644 --- a/src/Type/BooleanType.php +++ b/src/Type/BooleanType.php @@ -46,11 +46,6 @@ public function getConstantScalarTypes(): array return [new ConstantBooleanType(true), new ConstantBooleanType(false)]; } - public function getConstantStrings(): array - { - return [new ConstantStringType('1'), new ConstantStringType('0')]; - } - public function getConstantScalarValues(): array { return [true, false]; From b45fbef5e97b4c1e31fd470a05950e44bc7b4786 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 11 Jan 2025 14:17:59 +0100 Subject: [PATCH 5/5] Update BooleanType.php --- src/Type/BooleanType.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Type/BooleanType.php b/src/Type/BooleanType.php index 94c40ef8fc..0e26b52a67 100644 --- a/src/Type/BooleanType.php +++ b/src/Type/BooleanType.php @@ -41,6 +41,11 @@ public function __construct() { } + public function getConstantStrings(): array + { + return []; + } + public function getConstantScalarTypes(): array { return [new ConstantBooleanType(true), new ConstantBooleanType(false)];