From 82688afec91cb5b1963c3d3d7fd45948ee26c2aa Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 28 Apr 2022 11:31:55 +0200 Subject: [PATCH 1/4] Support string accessory types in BitwiseNot --- tests/PHPStan/Analyser/data/bitwise-not.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/PHPStan/Analyser/data/bitwise-not.php b/tests/PHPStan/Analyser/data/bitwise-not.php index f7f07c1996..5f4de7f654 100644 --- a/tests/PHPStan/Analyser/data/bitwise-not.php +++ b/tests/PHPStan/Analyser/data/bitwise-not.php @@ -6,10 +6,16 @@ /** * @param string|int $stringOrInt + * @param numeric-string $numericString + * @param literal-string $literalString + * @param non-empty-string $nonEmptyString */ -function foo(int $int, string $string, float $float, $stringOrInt) : void{ +function foo(int $int, string $string, float $float, $stringOrInt, $numericString, $literalString, string $nonEmptyString) : void{ assertType('int', ~$int); assertType('string', ~$string); + assertType('non-empty-string&numeric-string', ~$numericString); + assertType('literal-string', ~$literalString); + assertType('non-empty-string', ~$nonEmptyString); assertType('int', ~$float); assertType('int|string', ~$stringOrInt); assertType("'" . (~"abc") . "'", ~"abc"); From a910db94595c525797627f96e3348f18c9b30ee2 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 28 Apr 2022 11:32:24 +0200 Subject: [PATCH 2/4] fix --- src/Analyser/MutatingScope.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 5f73560bd7..5dcba31348 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -62,6 +62,7 @@ use PHPStan\TrinaryLogic; use PHPStan\Type\Accessory\AccessoryLiteralStringType; use PHPStan\Type\Accessory\AccessoryNonEmptyStringType; +use PHPStan\Type\Accessory\AccessoryNumericStringType; use PHPStan\Type\Accessory\NonEmptyArrayType; use PHPStan\Type\ArrayType; use PHPStan\Type\BenevolentUnionType; @@ -687,8 +688,21 @@ private function resolveType(Expr $node): Type if ($type instanceof ConstantStringType) { return new ConstantStringType(~$type->getValue()); } - if ($type instanceof StringType) { - return new StringType(); + if ($type->isString()->yes()) { + $accessories = [ + new StringType(), + ]; + if ($type->isNonEmptyString()->yes()) { + $accessories[] = new AccessoryNonEmptyStringType(); + } + if ($type->isLiteralString()->yes()) { + $accessories[] = new AccessoryLiteralStringType(); + } + if ($type->isNumericString()->yes()) { + $accessories[] = new AccessoryNumericStringType(); + } + + return TypeCombinator::intersect(...$accessories); } if ($type instanceof IntegerType || $type instanceof FloatType) { return new IntegerType(); //no const types here, result depends on PHP_INT_SIZE From 2fa51e001182eb6c1a946a58d832ecd053d3abff Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 10 May 2022 09:47:56 +0200 Subject: [PATCH 3/4] it's useful to apply numeric and literal strings this way --- src/Analyser/MutatingScope.php | 6 ------ tests/PHPStan/Analyser/data/bitwise-not.php | 4 ---- 2 files changed, 10 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 5dcba31348..c3a289ec9b 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -695,12 +695,6 @@ private function resolveType(Expr $node): Type if ($type->isNonEmptyString()->yes()) { $accessories[] = new AccessoryNonEmptyStringType(); } - if ($type->isLiteralString()->yes()) { - $accessories[] = new AccessoryLiteralStringType(); - } - if ($type->isNumericString()->yes()) { - $accessories[] = new AccessoryNumericStringType(); - } return TypeCombinator::intersect(...$accessories); } diff --git a/tests/PHPStan/Analyser/data/bitwise-not.php b/tests/PHPStan/Analyser/data/bitwise-not.php index 5f4de7f654..a9e406d489 100644 --- a/tests/PHPStan/Analyser/data/bitwise-not.php +++ b/tests/PHPStan/Analyser/data/bitwise-not.php @@ -6,15 +6,11 @@ /** * @param string|int $stringOrInt - * @param numeric-string $numericString - * @param literal-string $literalString * @param non-empty-string $nonEmptyString */ function foo(int $int, string $string, float $float, $stringOrInt, $numericString, $literalString, string $nonEmptyString) : void{ assertType('int', ~$int); assertType('string', ~$string); - assertType('non-empty-string&numeric-string', ~$numericString); - assertType('literal-string', ~$literalString); assertType('non-empty-string', ~$nonEmptyString); assertType('int', ~$float); assertType('int|string', ~$stringOrInt); From 6379aff74e4c2a0f9389f37da1a072329d2bfbac Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 10 May 2022 09:49:37 +0200 Subject: [PATCH 4/4] comment --- src/Analyser/MutatingScope.php | 3 ++- tests/PHPStan/Analyser/data/bitwise-not.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index c3a289ec9b..bbefa0933c 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -62,7 +62,6 @@ use PHPStan\TrinaryLogic; use PHPStan\Type\Accessory\AccessoryLiteralStringType; use PHPStan\Type\Accessory\AccessoryNonEmptyStringType; -use PHPStan\Type\Accessory\AccessoryNumericStringType; use PHPStan\Type\Accessory\NonEmptyArrayType; use PHPStan\Type\ArrayType; use PHPStan\Type\BenevolentUnionType; @@ -695,6 +694,8 @@ private function resolveType(Expr $node): Type if ($type->isNonEmptyString()->yes()) { $accessories[] = new AccessoryNonEmptyStringType(); } + // it is not useful to apply numeric and literal strings here. + // numeric string isn't certainly kept numeric: 3v4l.org/JERDB return TypeCombinator::intersect(...$accessories); } diff --git a/tests/PHPStan/Analyser/data/bitwise-not.php b/tests/PHPStan/Analyser/data/bitwise-not.php index a9e406d489..d3ec67530c 100644 --- a/tests/PHPStan/Analyser/data/bitwise-not.php +++ b/tests/PHPStan/Analyser/data/bitwise-not.php @@ -8,7 +8,7 @@ * @param string|int $stringOrInt * @param non-empty-string $nonEmptyString */ -function foo(int $int, string $string, float $float, $stringOrInt, $numericString, $literalString, string $nonEmptyString) : void{ +function foo(int $int, string $string, float $float, $stringOrInt, string $nonEmptyString) : void{ assertType('int', ~$int); assertType('string', ~$string); assertType('non-empty-string', ~$nonEmptyString);