Fix #11441: @phpstan-assert isn't working with Union#4900
Merged
ondrejmirtes merged 2 commits into2.1.xfrom Feb 12, 2026
Merged
Fix #11441: @phpstan-assert isn't working with Union#4900ondrejmirtes merged 2 commits into2.1.xfrom
ondrejmirtes merged 2 commits into2.1.xfrom
Conversation
- UnionTypeMethodReflection::getAsserts() returned empty assertions, causing @phpstan-assert tags to be ignored when calling methods on union types like Foo|Bar - Changed getAsserts() to combine assertions from all union member methods, mirroring IntersectionTypeMethodReflection's implementation - New regression test in tests/PHPStan/Analyser/nsrt/bug-11441.php
Closes phpstan/phpstan#13358 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
staabm
reviewed
Feb 12, 2026
| $assertions = Assertions::createEmpty(); | ||
|
|
||
| foreach ($this->methods as $method) { | ||
| $assertions = $assertions->intersectWith($method->getAsserts()); |
Contributor
There was a problem hiding this comment.
looking at this implementation and the tests, I think we miss test coverage for the case when asserts do not intersect.
maybe thats someting we could enhance the prompt about so more test cases are generated
Contributor
There was a problem hiding this comment.
alternatively thats something which could be detected by infection and claude could run mutation tests (which could make the whole process slow though)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When calling a method with
@phpstan-asserton a union type (e.g.Foo|Bar), the assertion was not applied, so type narrowing did not occur. For example,@phpstan-assert !null $this->getParam()on bothFoo::checkNotNull()andBar::checkNotNull()should narrow$fooOrBar->getParam()fromint|string|nulltoint|stringafter the call, but it remainedint|string|null.Changes
src/Reflection/Type/UnionTypeMethodReflection.php: ChangedgetAsserts()from returningAssertions::createEmpty()to iterating over all member methods and combining their assertions viaintersectWith(), matching the pattern already used byIntersectionTypeMethodReflection::getAsserts()tests/PHPStan/Analyser/nsrt/bug-11441.phpCLAUDE.mdwith guidance about maintaining parity betweenUnionTypeMethodReflectionandIntersectionTypeMethodReflectionRoot cause
UnionTypeMethodReflection::getAsserts()was hardcoded to returnAssertions::createEmpty(). When TypeSpecifier processes a method call and checks for@phpstan-assertannotations, it calls$methodReflection->getAsserts(). For union types, the method reflection is aUnionTypeMethodReflection, which returned no assertions, so the type narrowing was never applied. The fix combines assertions from all union member methods, which is the same approach used byIntersectionTypeMethodReflection.Test
The regression test in
tests/PHPStan/Analyser/nsrt/bug-11441.phpreproduces the exact scenario from the issue: two classes (FooandBar) each with acheckNotNull()method annotated with@phpstan-assert !null $this->getParam(). When called on aFoo|Barunion, the test verifies thatgetParam()is narrowed fromint|string|nulltoint|string.Fixes phpstan/phpstan#11441
Closes phpstan/phpstan#13358