Fix phpstan/phpstan#14320: Since 2.1.37. Parameter of method MyAbstractClass::myFunction() should be contravariant with parameter of method MyFirstTrait::myFunction()#5244
Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Conversation
…h nested trait - Skip traits that inherited an abstract method from a sub-trait in ParentMethodHelper::collectParentMethods - The actual declaring trait is still checked separately in the same loop - New regression test in tests/PHPStan/Rules/Methods/data/bug-14320.php
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
False positive "should be contravariant with parameter" error when using nested traits (a trait that uses another trait containing an abstract method). The PHPDoc parameter type from the original trait was lost when the method was checked through the intermediate trait, causing the parameter type to fall back to the native
arrayinstead ofarray<string, mixed>.Changes
src/Rules/Methods/ParentMethodHelper.phpto skip traits where an abstract method is inherited from a sub-trait rather than declared directly. The actual declaring trait is still processed separately in the same loop, so the contravariance check still happens with the correct PHPDoc types.tests/PHPStan/Rules/Methods/data/bug-14320.phpandtests/PHPStan/Rules/Methods/MethodSignatureRuleTest.phpRoot cause
ParentMethodHelper::collectParentMethodsiterates all traits recursively via$class->getTraits(true). For nested traits (e.g.,MyFirstTraitusesMyTrait), both traits appear in the iteration. When checkingMyFirstTrait, the abstract methodmyFunctionis found viahasMethod()(since PHP's trait composition copies methods), but the PHPDoc from the original declaring traitMyTraitis not properly resolved through the intermediate trait. This causes the parameter type to be reported as justarray(native type) instead ofarray<string, mixed>(PHPDoc type), triggering a false contravariance error.The fix uses BetterReflection's
getDeclaringClass()(which returns the actual declaring class, unlike PHP's native reflection which returns the implementing/composing class) to skip traits that only inherited the method from a sub-trait.Test
Added
testBug14320inMethodSignatureRuleTestwith a test case reproducing the exact scenario: a trait with a PHPDoc-annotated abstract method, used by an intermediate trait, which is then used by an abstract class that implements the method with the same PHPDoc types. The test expects no errors.Fixes phpstan/phpstan#14320