From ab74f12d2bb96161bdaeed229c2b2b66df9959dd Mon Sep 17 00:00:00 2001 From: tajimayuki Date: Sun, 17 Aug 2025 07:13:22 +0000 Subject: [PATCH 1/5] test: reproduce #13358 (assert-if-true on $this lost via union) --- .../Rules/Methods/AssertIfTrueOnThisTest.php | 24 +++++++++++ .../PHPStan/Rules/Methods/data/bug-13358.php | 40 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/PHPStan/Rules/Methods/AssertIfTrueOnThisTest.php create mode 100644 tests/PHPStan/Rules/Methods/data/bug-13358.php diff --git a/tests/PHPStan/Rules/Methods/AssertIfTrueOnThisTest.php b/tests/PHPStan/Rules/Methods/AssertIfTrueOnThisTest.php new file mode 100644 index 0000000000..45a704851d --- /dev/null +++ b/tests/PHPStan/Rules/Methods/AssertIfTrueOnThisTest.php @@ -0,0 +1,24 @@ +assertFileAsserts($assertType, $file, ...$args); + } + +} diff --git a/tests/PHPStan/Rules/Methods/data/bug-13358.php b/tests/PHPStan/Rules/Methods/data/bug-13358.php new file mode 100644 index 0000000000..7c8af419e3 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-13358.php @@ -0,0 +1,40 @@ +isSystem()) { + assertType('Bug13358\SystemActor', $actor); + } else { + assertType('Bug13358\AnonymousVisitorActor', $actor); + } +} From 1f1e9163d263e03d61322ca791d6e18ee7ca4366 Mon Sep 17 00:00:00 2001 From: tajimayuki Date: Sun, 17 Aug 2025 07:15:17 +0000 Subject: [PATCH 2/5] fix(reflection): merge assertions in UnionTypeMethodReflection::getAsserts() --- src/Reflection/Type/UnionTypeMethodReflection.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Reflection/Type/UnionTypeMethodReflection.php b/src/Reflection/Type/UnionTypeMethodReflection.php index b330b6fdad..4dd7b0dca2 100644 --- a/src/Reflection/Type/UnionTypeMethodReflection.php +++ b/src/Reflection/Type/UnionTypeMethodReflection.php @@ -177,7 +177,13 @@ public function getDocComment(): ?string public function getAsserts(): Assertions { - return Assertions::createEmpty(); + $mergedAssertions = Assertions::createEmpty(); + + foreach ($this->methods as $method) { + $mergedAssertions = $mergedAssertions->intersectWith($method->getAsserts()); + } + + return $mergedAssertions; } public function acceptsNamedArguments(): TrinaryLogic From 31b55ac355cc16dd2c18ebaa4165135a2c181dbe Mon Sep 17 00:00:00 2001 From: tajimayuki Date: Tue, 19 Aug 2025 12:40:08 +0000 Subject: [PATCH 3/5] Move bug-13358 test to nsrt/ and remove obsolete test class --- .../data => Analyser/nsrt}/bug-13358.php | 0 .../Rules/Methods/AssertIfTrueOnThisTest.php | 24 ------------------- 2 files changed, 24 deletions(-) rename tests/PHPStan/{Rules/Methods/data => Analyser/nsrt}/bug-13358.php (100%) delete mode 100644 tests/PHPStan/Rules/Methods/AssertIfTrueOnThisTest.php diff --git a/tests/PHPStan/Rules/Methods/data/bug-13358.php b/tests/PHPStan/Analyser/nsrt/bug-13358.php similarity index 100% rename from tests/PHPStan/Rules/Methods/data/bug-13358.php rename to tests/PHPStan/Analyser/nsrt/bug-13358.php diff --git a/tests/PHPStan/Rules/Methods/AssertIfTrueOnThisTest.php b/tests/PHPStan/Rules/Methods/AssertIfTrueOnThisTest.php deleted file mode 100644 index 45a704851d..0000000000 --- a/tests/PHPStan/Rules/Methods/AssertIfTrueOnThisTest.php +++ /dev/null @@ -1,24 +0,0 @@ -assertFileAsserts($assertType, $file, ...$args); - } - -} From 6ca93cf1be92bb3c89f047ba4f6e29820b9d28e1 Mon Sep 17 00:00:00 2001 From: tajimayuki Date: Thu, 21 Aug 2025 15:46:45 +0000 Subject: [PATCH 4/5] Add regression test for #11441 (assert on UnionType) --- tests/PHPStan/Analyser/nsrt/bug-11441.php | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-11441.php diff --git a/tests/PHPStan/Analyser/nsrt/bug-11441.php b/tests/PHPStan/Analyser/nsrt/bug-11441.php new file mode 100644 index 0000000000..d1c497ec17 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-11441.php @@ -0,0 +1,39 @@ +getParam() */ + public function checkNotNull(): void { + if ($this->getParam() === null) { + throw new \Exception(); + } + } +} + +class Bar { + public function getParam(): ?int { + return 1; + } + + /** @phpstan-assert !null $this->getParam() */ + public function checkNotNull(): void { + if ($this->getParam() === null) { + throw new \Exception(); + } + } +} + +function test(Foo|Bar $obj): void { + assertType('int|string|null', $obj->getParam()); + + $obj->checkNotNull(); + + assertType('int|string', $obj->getParam()); +} From 65ac9e0e202ec2decff94d684a042c00b9e967f8 Mon Sep 17 00:00:00 2001 From: tajimayuki Date: Thu, 21 Aug 2025 15:52:30 +0000 Subject: [PATCH 5/5] Consistent variable name in getAsserts() --- src/Reflection/Type/UnionTypeMethodReflection.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Reflection/Type/UnionTypeMethodReflection.php b/src/Reflection/Type/UnionTypeMethodReflection.php index 4dd7b0dca2..072d950882 100644 --- a/src/Reflection/Type/UnionTypeMethodReflection.php +++ b/src/Reflection/Type/UnionTypeMethodReflection.php @@ -177,13 +177,13 @@ public function getDocComment(): ?string public function getAsserts(): Assertions { - $mergedAssertions = Assertions::createEmpty(); + $assertions = Assertions::createEmpty(); foreach ($this->methods as $method) { - $mergedAssertions = $mergedAssertions->intersectWith($method->getAsserts()); + $assertions = $assertions->intersectWith($method->getAsserts()); } - return $mergedAssertions; + return $assertions; } public function acceptsNamedArguments(): TrinaryLogic