From df3acc5de0f0b6d2a6608f55405db30e070c3302 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 8 Sep 2024 14:45:49 +0200 Subject: [PATCH 01/21] More precise mixed-type subtraction --- src/Type/MixedType.php | 10 ++++++++++ tests/PHPStan/Analyser/nsrt/non-empty-string.php | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index c45642f0d2..528bfde116 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -27,6 +27,7 @@ use PHPStan\Type\Accessory\OversizedArrayType; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Constant\ConstantBooleanType; +use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\Generic\TemplateMixedType; use PHPStan\Type\Generic\TemplateType; use PHPStan\Type\Traits\NonGeneralizableTypeTrait; @@ -494,6 +495,15 @@ public function toFloat(): Type public function toString(): Type { + if ($this->subtractedType !== null) { + if ($this->subtractedType->isSuperTypeOf(new ConstantStringType(''))->yes()) { + return new IntersectionType([ + new StringType(), + new AccessoryNonEmptyStringType(), + ]); + } + } + return new StringType(); } diff --git a/tests/PHPStan/Analyser/nsrt/non-empty-string.php b/tests/PHPStan/Analyser/nsrt/non-empty-string.php index 976071cb84..57d15d5b21 100644 --- a/tests/PHPStan/Analyser/nsrt/non-empty-string.php +++ b/tests/PHPStan/Analyser/nsrt/non-empty-string.php @@ -408,4 +408,15 @@ function multiplesPrintfFormats(string $s) { assertType('non-empty-string', sprintf($nonEmpty, $s)); assertType('non-falsy-string', sprintf($nonFalsy, $s)); } + + function subtract(mixed $m) { + if ($m != '') { + assertType("mixed", $m); + assertType('string', (string) $m); + } + if ($m !== '') { + assertType("mixed~''", $m); + assertType('non-empty-string', (string) $m); + } + } } From 181ded7a9aa370d5a7a94d577db9d7b690b44a71 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 8 Sep 2024 14:52:37 +0200 Subject: [PATCH 02/21] More precise mixed~int subtraction --- src/Type/MixedType.php | 10 ++++++++++ tests/PHPStan/Analyser/nsrt/integer-range-types.php | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 528bfde116..4204e92e5e 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -27,6 +27,7 @@ use PHPStan\Type\Accessory\OversizedArrayType; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Constant\ConstantBooleanType; +use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\Generic\TemplateMixedType; use PHPStan\Type\Generic\TemplateType; @@ -485,6 +486,15 @@ public function toAbsoluteNumber(): Type public function toInteger(): Type { + if ($this->subtractedType !== null) { + if ($this->subtractedType->isSuperTypeOf(new ConstantIntegerType(0))->yes()) { + return new UnionType([ + IntegerRangeType::fromInterval(null, -1), + IntegerRangeType::fromInterval(1, null) + ]); + } + } + return new IntegerType(); } diff --git a/tests/PHPStan/Analyser/nsrt/integer-range-types.php b/tests/PHPStan/Analyser/nsrt/integer-range-types.php index c769890c9e..c9531486b1 100644 --- a/tests/PHPStan/Analyser/nsrt/integer-range-types.php +++ b/tests/PHPStan/Analyser/nsrt/integer-range-types.php @@ -446,3 +446,14 @@ public function zeroIssues($positive, $negative) } } + +function subtract(mixed $m) { + if ($m != 0) { + assertType("mixed", $m); + assertType('string', (int) $m); + } + if ($m !== 0) { + assertType("mixed~0", $m); + assertType('int|int<1, max>', (int) $m); + } +} From 87384f53be6cf36502723bac52e6448a02da1ac2 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 8 Sep 2024 15:00:54 +0200 Subject: [PATCH 03/21] cs --- src/Type/MixedType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 4204e92e5e..120c20f7bb 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -490,7 +490,7 @@ public function toInteger(): Type if ($this->subtractedType->isSuperTypeOf(new ConstantIntegerType(0))->yes()) { return new UnionType([ IntegerRangeType::fromInterval(null, -1), - IntegerRangeType::fromInterval(1, null) + IntegerRangeType::fromInterval(1, null), ]); } } From 92516eddd7cc5b638eb66804095d941e878f709b Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 8 Sep 2024 15:09:04 +0200 Subject: [PATCH 04/21] fix --- src/Type/MixedType.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 120c20f7bb..c905c5c995 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -474,8 +474,6 @@ public function toBoolean(): BooleanType public function toNumber(): Type { return new UnionType([ - $this->toInteger(), - $this->toFloat(), ]); } From 6528f3c2f54de5092843e7bab75fb6503f4f6889 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 8 Sep 2024 15:10:31 +0200 Subject: [PATCH 05/21] Update integer-range-types.php --- tests/PHPStan/Analyser/nsrt/integer-range-types.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Analyser/nsrt/integer-range-types.php b/tests/PHPStan/Analyser/nsrt/integer-range-types.php index c9531486b1..d5c53a4ed3 100644 --- a/tests/PHPStan/Analyser/nsrt/integer-range-types.php +++ b/tests/PHPStan/Analyser/nsrt/integer-range-types.php @@ -450,7 +450,7 @@ public function zeroIssues($positive, $negative) function subtract(mixed $m) { if ($m != 0) { assertType("mixed", $m); - assertType('string', (int) $m); + assertType('int', (int) $m); } if ($m !== 0) { assertType("mixed~0", $m); From 5b0909f214aa2fdec865e292e5255dd32466b0c6 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 8 Sep 2024 15:10:45 +0200 Subject: [PATCH 06/21] Update MixedType.php --- src/Type/MixedType.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index c905c5c995..007138ec12 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -474,6 +474,8 @@ public function toBoolean(): BooleanType public function toNumber(): Type { return new UnionType([ + new IntegerType(), + new FloatType(), ]); } From 3c5bdd342f21ffecba8fe914754f0f9ff9eca857 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 8 Sep 2024 16:40:59 +0200 Subject: [PATCH 07/21] support non-falsy-string in mixed subtraction --- src/Type/MixedType.php | 8 +++++++- tests/PHPStan/Analyser/nsrt/non-empty-string.php | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 007138ec12..dd7e7c9257 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -507,9 +507,15 @@ public function toString(): Type { if ($this->subtractedType !== null) { if ($this->subtractedType->isSuperTypeOf(new ConstantStringType(''))->yes()) { + $accessories = [ + new AccessoryNonEmptyStringType(), + ]; + if ($this->subtractedType->isSuperTypeOf(new ConstantStringType('0'))->yes()) { + $accessories[] = new AccessoryNonFalsyStringType(); + } return new IntersectionType([ new StringType(), - new AccessoryNonEmptyStringType(), + ...$accessories, ]); } } diff --git a/tests/PHPStan/Analyser/nsrt/non-empty-string.php b/tests/PHPStan/Analyser/nsrt/non-empty-string.php index 57d15d5b21..004331c566 100644 --- a/tests/PHPStan/Analyser/nsrt/non-empty-string.php +++ b/tests/PHPStan/Analyser/nsrt/non-empty-string.php @@ -410,6 +410,9 @@ function multiplesPrintfFormats(string $s) { } function subtract(mixed $m) { + if ($m) { + assertType('non-falsy-string', (string) $m); + } if ($m != '') { assertType("mixed", $m); assertType('string', (string) $m); From 87f91fa5f1993a4508898c240279cb39a5a84ff7 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 8 Sep 2024 16:45:42 +0200 Subject: [PATCH 08/21] try fix 7.2 --- src/Type/MixedType.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index dd7e7c9257..7b5b734b07 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -508,15 +508,15 @@ public function toString(): Type if ($this->subtractedType !== null) { if ($this->subtractedType->isSuperTypeOf(new ConstantStringType(''))->yes()) { $accessories = [ + new StringType(), new AccessoryNonEmptyStringType(), ]; if ($this->subtractedType->isSuperTypeOf(new ConstantStringType('0'))->yes()) { $accessories[] = new AccessoryNonFalsyStringType(); } - return new IntersectionType([ - new StringType(), - ...$accessories, - ]); + return new IntersectionType( + $accessories, + ); } } From 8d5f9f3b9a8407f34d170e43e1260f6e9c23dcdc Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 8 Sep 2024 17:03:14 +0200 Subject: [PATCH 09/21] drop php8 only param types --- tests/PHPStan/Analyser/nsrt/integer-range-types.php | 2 +- tests/PHPStan/Analyser/nsrt/non-empty-string.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PHPStan/Analyser/nsrt/integer-range-types.php b/tests/PHPStan/Analyser/nsrt/integer-range-types.php index d5c53a4ed3..2a127c863a 100644 --- a/tests/PHPStan/Analyser/nsrt/integer-range-types.php +++ b/tests/PHPStan/Analyser/nsrt/integer-range-types.php @@ -447,7 +447,7 @@ public function zeroIssues($positive, $negative) } -function subtract(mixed $m) { +function subtract($m) { if ($m != 0) { assertType("mixed", $m); assertType('int', (int) $m); diff --git a/tests/PHPStan/Analyser/nsrt/non-empty-string.php b/tests/PHPStan/Analyser/nsrt/non-empty-string.php index 004331c566..5f2c149740 100644 --- a/tests/PHPStan/Analyser/nsrt/non-empty-string.php +++ b/tests/PHPStan/Analyser/nsrt/non-empty-string.php @@ -409,7 +409,7 @@ function multiplesPrintfFormats(string $s) { assertType('non-falsy-string', sprintf($nonFalsy, $s)); } - function subtract(mixed $m) { + function subtract($m) { if ($m) { assertType('non-falsy-string', (string) $m); } From 02d09791c8ba27d1f57a3e360dbb95671a308672 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 9 Sep 2024 11:04:33 +0200 Subject: [PATCH 10/21] more tests --- .../Analyser/nsrt/integer-range-types.php | 24 ++++++++++++++++++- .../Analyser/nsrt/non-empty-string.php | 13 ++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/tests/PHPStan/Analyser/nsrt/integer-range-types.php b/tests/PHPStan/Analyser/nsrt/integer-range-types.php index 2a127c863a..97b0168731 100644 --- a/tests/PHPStan/Analyser/nsrt/integer-range-types.php +++ b/tests/PHPStan/Analyser/nsrt/integer-range-types.php @@ -449,11 +449,33 @@ public function zeroIssues($positive, $negative) function subtract($m) { if ($m != 0) { - assertType("mixed", $m); + assertType("mixed", $m); // could be "mixed~0|0.0|''|'0'|array{}|false|null" assertType('int', (int) $m); } if ($m !== 0) { assertType("mixed~0", $m); assertType('int|int<1, max>', (int) $m); } + if (!is_int($m)) { + assertType("mixed~int", $m); + assertType('int', (int) $m); + } + + if ($m != true) { + assertType("0|0.0|''|'0'|array{}|false|null", $m); + assertType('0', (int) $m); + } + if ($m !== true) { + assertType("mixed~true", $m); + assertType('int', (int) $m); + } + + if ($m != false) { + assertType("mixed~0|0.0|''|'0'|array{}|false|null", $m); + assertType('int|int<1, max>', (int) $m); + } + if ($m !== false) { + assertType("mixed~false", $m); + assertType('int', (int) $m); + } } diff --git a/tests/PHPStan/Analyser/nsrt/non-empty-string.php b/tests/PHPStan/Analyser/nsrt/non-empty-string.php index 5f2c149740..883e4315df 100644 --- a/tests/PHPStan/Analyser/nsrt/non-empty-string.php +++ b/tests/PHPStan/Analyser/nsrt/non-empty-string.php @@ -421,5 +421,18 @@ function subtract($m) { assertType("mixed~''", $m); assertType('non-empty-string', (string) $m); } + if (!is_string($m)) { + assertType("mixed~string", $m); + assertType('string', (string) $m); + } + + if ($m !== true) { + assertType("mixed~true", $m); + assertType('string', (string) $m); + } + if ($m !== false) { + assertType("mixed~false", $m); + assertType('string', (string) $m); + } } } From 5b6bbcd51c7d11c0e645a6e9b41c5a54fd94daea Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 9 Sep 2024 13:45:52 +0200 Subject: [PATCH 11/21] fix --- src/Type/MixedType.php | 36 ++++++++++++------- .../Analyser/nsrt/integer-range-types.php | 8 ++--- .../Analyser/nsrt/non-empty-string.php | 3 +- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 7b5b734b07..2c683016a7 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -27,6 +27,7 @@ use PHPStan\Type\Accessory\OversizedArrayType; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Constant\ConstantBooleanType; +use PHPStan\Type\Constant\ConstantFloatType; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\Generic\TemplateMixedType; @@ -473,10 +474,10 @@ public function toBoolean(): BooleanType public function toNumber(): Type { - return new UnionType([ - new IntegerType(), - new FloatType(), - ]); + return TypeCombinator::union( + $this->toInteger(), + $this->toFloat(), + ); } public function toAbsoluteNumber(): Type @@ -486,13 +487,11 @@ public function toAbsoluteNumber(): Type public function toInteger(): Type { - if ($this->subtractedType !== null) { - if ($this->subtractedType->isSuperTypeOf(new ConstantIntegerType(0))->yes()) { - return new UnionType([ - IntegerRangeType::fromInterval(null, -1), - IntegerRangeType::fromInterval(1, null), - ]); - } + if ($this->subtractedType !== null && StaticTypeFactory::falsey()->equals($this->subtractedType)) { + return new UnionType([ + IntegerRangeType::fromInterval(null, -1), + IntegerRangeType::fromInterval(1, null), + ]); } return new IntegerType(); @@ -506,12 +505,23 @@ public function toFloat(): Type public function toString(): Type { if ($this->subtractedType !== null) { - if ($this->subtractedType->isSuperTypeOf(new ConstantStringType(''))->yes()) { + $castsToEmptyString = new UnionType([ + new NullType(), + new ConstantBooleanType(false), + new ConstantStringType(''), + ]); + if ($this->subtractedType->isSuperTypeOf($castsToEmptyString)->yes()) { $accessories = [ new StringType(), new AccessoryNonEmptyStringType(), ]; - if ($this->subtractedType->isSuperTypeOf(new ConstantStringType('0'))->yes()) { + + $castsToZeroString = new UnionType([ + new ConstantFloatType(0.0), + new ConstantStringType('0'), + new ConstantIntegerType(0), + ]); + if ($this->subtractedType->isSuperTypeOf($castsToZeroString)->yes()) { $accessories[] = new AccessoryNonFalsyStringType(); } return new IntersectionType( diff --git a/tests/PHPStan/Analyser/nsrt/integer-range-types.php b/tests/PHPStan/Analyser/nsrt/integer-range-types.php index 97b0168731..ef23eee863 100644 --- a/tests/PHPStan/Analyser/nsrt/integer-range-types.php +++ b/tests/PHPStan/Analyser/nsrt/integer-range-types.php @@ -450,15 +450,15 @@ public function zeroIssues($positive, $negative) function subtract($m) { if ($m != 0) { assertType("mixed", $m); // could be "mixed~0|0.0|''|'0'|array{}|false|null" - assertType('int', (int) $m); + assertType('int', (int) $m); // could be int|int<1, max> } if ($m !== 0) { assertType("mixed~0", $m); - assertType('int|int<1, max>', (int) $m); + assertType('int', (int) $m); // mixed could still contain falsey values, which cast to 0 } if (!is_int($m)) { assertType("mixed~int", $m); - assertType('int', (int) $m); + assertType('int', (int) $m); // mixed could still contain falsey values, which cast to 0 } if ($m != true) { @@ -476,6 +476,6 @@ function subtract($m) { } if ($m !== false) { assertType("mixed~false", $m); - assertType('int', (int) $m); + assertType('int', (int) $m); // mixed could still contain falsey values, which cast to 0 } } diff --git a/tests/PHPStan/Analyser/nsrt/non-empty-string.php b/tests/PHPStan/Analyser/nsrt/non-empty-string.php index 883e4315df..8bf38c3e5f 100644 --- a/tests/PHPStan/Analyser/nsrt/non-empty-string.php +++ b/tests/PHPStan/Analyser/nsrt/non-empty-string.php @@ -411,6 +411,7 @@ function multiplesPrintfFormats(string $s) { function subtract($m) { if ($m) { + assertType("mixed~0|0.0|''|'0'|array{}|false|null", $m); assertType('non-falsy-string', (string) $m); } if ($m != '') { @@ -419,7 +420,7 @@ function subtract($m) { } if ($m !== '') { assertType("mixed~''", $m); - assertType('non-empty-string', (string) $m); + assertType('string', (string) $m); } if (!is_string($m)) { assertType("mixed~string", $m); From ba3acbdefae496aaafd71906d912f9923d33e67e Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 9 Sep 2024 13:47:45 +0200 Subject: [PATCH 12/21] Update non-empty-string.php --- tests/PHPStan/Analyser/nsrt/non-empty-string.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/PHPStan/Analyser/nsrt/non-empty-string.php b/tests/PHPStan/Analyser/nsrt/non-empty-string.php index 8bf38c3e5f..ec751312fe 100644 --- a/tests/PHPStan/Analyser/nsrt/non-empty-string.php +++ b/tests/PHPStan/Analyser/nsrt/non-empty-string.php @@ -435,5 +435,9 @@ function subtract($m) { assertType("mixed~false", $m); assertType('string', (string) $m); } + if ($m !== false && $m !== '' && $m !== null) { + assertType("mixed~''|false|null", $m); + assertType('non-empty-string', (string) $m); + } } } From 0e36a8862414e7e31d9da5e32a8cfafd0de72cea Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 9 Sep 2024 13:56:33 +0200 Subject: [PATCH 13/21] more tests --- tests/PHPStan/Analyser/nsrt/non-empty-string.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/PHPStan/Analyser/nsrt/non-empty-string.php b/tests/PHPStan/Analyser/nsrt/non-empty-string.php index ec751312fe..571f383d0f 100644 --- a/tests/PHPStan/Analyser/nsrt/non-empty-string.php +++ b/tests/PHPStan/Analyser/nsrt/non-empty-string.php @@ -439,5 +439,9 @@ function subtract($m) { assertType("mixed~''|false|null", $m); assertType('non-empty-string', (string) $m); } + if (!is_bool($m) && $m !== '' && $m !== null) { + assertType("mixed~''|bool|null", $m); + assertType('non-empty-string', (string) $m); + } } } From d1b4322580582df8f00571bda865a5f9707282fb Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 12 Sep 2024 16:34:32 +0200 Subject: [PATCH 14/21] Update integer-range-types.php --- tests/PHPStan/Analyser/nsrt/integer-range-types.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Analyser/nsrt/integer-range-types.php b/tests/PHPStan/Analyser/nsrt/integer-range-types.php index ef23eee863..817bfe914c 100644 --- a/tests/PHPStan/Analyser/nsrt/integer-range-types.php +++ b/tests/PHPStan/Analyser/nsrt/integer-range-types.php @@ -472,7 +472,7 @@ function subtract($m) { if ($m != false) { assertType("mixed~0|0.0|''|'0'|array{}|false|null", $m); - assertType('int|int<1, max>', (int) $m); + assertType('int', (int) $m); } if ($m !== false) { assertType("mixed~false", $m); From cfea649ed79b86c99c090071ffa65f1b1674b17c Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 12 Sep 2024 17:42:00 +0200 Subject: [PATCH 15/21] Update MixedType.php --- src/Type/MixedType.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 2c683016a7..6bf5222e7f 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -487,7 +487,11 @@ public function toAbsoluteNumber(): Type public function toInteger(): Type { - if ($this->subtractedType !== null && StaticTypeFactory::falsey()->equals($this->subtractedType)) { + if ( + $this->subtractedType !== null + && StaticTypeFactory::falsey()->equals($this->subtractedType) + && $this->subtractedType->isSuperTypeOf(new StringType())->yes() + ) { return new UnionType([ IntegerRangeType::fromInterval(null, -1), IntegerRangeType::fromInterval(1, null), From 2323becdc94b78df149a079edb8fa770e89abf2c Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 12 Sep 2024 17:43:00 +0200 Subject: [PATCH 16/21] Discard changes to tests/PHPStan/Analyser/nsrt/non-empty-string.php --- .../Analyser/nsrt/non-empty-string.php | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/tests/PHPStan/Analyser/nsrt/non-empty-string.php b/tests/PHPStan/Analyser/nsrt/non-empty-string.php index 571f383d0f..976071cb84 100644 --- a/tests/PHPStan/Analyser/nsrt/non-empty-string.php +++ b/tests/PHPStan/Analyser/nsrt/non-empty-string.php @@ -408,40 +408,4 @@ function multiplesPrintfFormats(string $s) { assertType('non-empty-string', sprintf($nonEmpty, $s)); assertType('non-falsy-string', sprintf($nonFalsy, $s)); } - - function subtract($m) { - if ($m) { - assertType("mixed~0|0.0|''|'0'|array{}|false|null", $m); - assertType('non-falsy-string', (string) $m); - } - if ($m != '') { - assertType("mixed", $m); - assertType('string', (string) $m); - } - if ($m !== '') { - assertType("mixed~''", $m); - assertType('string', (string) $m); - } - if (!is_string($m)) { - assertType("mixed~string", $m); - assertType('string', (string) $m); - } - - if ($m !== true) { - assertType("mixed~true", $m); - assertType('string', (string) $m); - } - if ($m !== false) { - assertType("mixed~false", $m); - assertType('string', (string) $m); - } - if ($m !== false && $m !== '' && $m !== null) { - assertType("mixed~''|false|null", $m); - assertType('non-empty-string', (string) $m); - } - if (!is_bool($m) && $m !== '' && $m !== null) { - assertType("mixed~''|bool|null", $m); - assertType('non-empty-string', (string) $m); - } - } } From 39bea0e59e59344c538881aeff7123a935a3d1ad Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 12 Sep 2024 17:43:38 +0200 Subject: [PATCH 17/21] Update MixedType.php --- src/Type/MixedType.php | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 6bf5222e7f..f10fb79e74 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -508,32 +508,6 @@ public function toFloat(): Type public function toString(): Type { - if ($this->subtractedType !== null) { - $castsToEmptyString = new UnionType([ - new NullType(), - new ConstantBooleanType(false), - new ConstantStringType(''), - ]); - if ($this->subtractedType->isSuperTypeOf($castsToEmptyString)->yes()) { - $accessories = [ - new StringType(), - new AccessoryNonEmptyStringType(), - ]; - - $castsToZeroString = new UnionType([ - new ConstantFloatType(0.0), - new ConstantStringType('0'), - new ConstantIntegerType(0), - ]); - if ($this->subtractedType->isSuperTypeOf($castsToZeroString)->yes()) { - $accessories[] = new AccessoryNonFalsyStringType(); - } - return new IntersectionType( - $accessories, - ); - } - } - return new StringType(); } From 56fb0c9f086501056f05dc169e1f46c14bf40ea8 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 12 Sep 2024 17:47:38 +0200 Subject: [PATCH 18/21] Update integer-range-types.php --- tests/PHPStan/Analyser/nsrt/integer-range-types.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Analyser/nsrt/integer-range-types.php b/tests/PHPStan/Analyser/nsrt/integer-range-types.php index 817bfe914c..51ce5ef4c1 100644 --- a/tests/PHPStan/Analyser/nsrt/integer-range-types.php +++ b/tests/PHPStan/Analyser/nsrt/integer-range-types.php @@ -450,7 +450,7 @@ public function zeroIssues($positive, $negative) function subtract($m) { if ($m != 0) { assertType("mixed", $m); // could be "mixed~0|0.0|''|'0'|array{}|false|null" - assertType('int', (int) $m); // could be int|int<1, max> + assertType('int', (int) $m); } if ($m !== 0) { assertType("mixed~0", $m); From 97d500366dd18afd16c4b86466f80f2489bdf96e Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 12 Sep 2024 17:49:58 +0200 Subject: [PATCH 19/21] Update MixedType.php --- src/Type/MixedType.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index f10fb79e74..4aa4add6e2 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -487,10 +487,19 @@ public function toAbsoluteNumber(): Type public function toInteger(): Type { + $castsToZero = new UnionType([ + new NullType(), + new ConstantBooleanType(false), + new ConstantIntegerType(0), + new ConstantFloatType(0.0), + new ConstantStringType(''), + new ConstantStringType('0'), + new ConstantArrayType([], []), + new StringType() + ]); if ( $this->subtractedType !== null - && StaticTypeFactory::falsey()->equals($this->subtractedType) - && $this->subtractedType->isSuperTypeOf(new StringType())->yes() + && $this->subtractedType->isSuperTypeOf($castsToZero)->yes() ) { return new UnionType([ IntegerRangeType::fromInterval(null, -1), From fda3416c39adfb0b8221850da90b72ca0c304a48 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 12 Sep 2024 19:22:43 +0200 Subject: [PATCH 20/21] fix --- src/Type/MixedType.php | 6 ++---- tests/PHPStan/Analyser/nsrt/integer-range-types.php | 8 ++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 4aa4add6e2..e902aa92a8 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -491,11 +491,9 @@ public function toInteger(): Type new NullType(), new ConstantBooleanType(false), new ConstantIntegerType(0), - new ConstantFloatType(0.0), - new ConstantStringType(''), - new ConstantStringType('0'), new ConstantArrayType([], []), - new StringType() + new StringType(), + new FloatType() ]); if ( $this->subtractedType !== null diff --git a/tests/PHPStan/Analyser/nsrt/integer-range-types.php b/tests/PHPStan/Analyser/nsrt/integer-range-types.php index 51ce5ef4c1..308064e2a4 100644 --- a/tests/PHPStan/Analyser/nsrt/integer-range-types.php +++ b/tests/PHPStan/Analyser/nsrt/integer-range-types.php @@ -478,4 +478,12 @@ function subtract($m) { assertType("mixed~false", $m); assertType('int', (int) $m); // mixed could still contain falsey values, which cast to 0 } + if (!is_string($m) && !is_float($m)) { + assertType("mixed~float|string", $m); + assertType('int', (int) $m); + if ($m != false) { + assertType("mixed~0|array{}|float|string|false|null", $m); + assertType('int|int<1, max>', (int) $m); + } + } } From e540d3745d924b484174bd3711ef68b378ca6c74 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 12 Sep 2024 19:29:22 +0200 Subject: [PATCH 21/21] cs --- src/Type/MixedType.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index e902aa92a8..41c87bf7a2 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -27,9 +27,7 @@ use PHPStan\Type\Accessory\OversizedArrayType; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Constant\ConstantBooleanType; -use PHPStan\Type\Constant\ConstantFloatType; use PHPStan\Type\Constant\ConstantIntegerType; -use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\Generic\TemplateMixedType; use PHPStan\Type\Generic\TemplateType; use PHPStan\Type\Traits\NonGeneralizableTypeTrait; @@ -487,13 +485,13 @@ public function toAbsoluteNumber(): Type public function toInteger(): Type { - $castsToZero = new UnionType([ + $castsToZero = new UnionType([ new NullType(), new ConstantBooleanType(false), new ConstantIntegerType(0), new ConstantArrayType([], []), new StringType(), - new FloatType() + new FloatType(), ]); if ( $this->subtractedType !== null