Fix #5946: $this type of static (self, ...) type must remains static
#4902
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 a method with
@return $thisis called on astaticreturn type, the result type was incorrectly preserved as$thisinstead of being downgraded tostatic. This caused PHPStan to miss reporting a type error when returning the result of such a chain from a method that requires$this.For example:
$this->getParent()returnsstatic(Model), then callinggetModel()on that should yieldstatic(Model)(not$this(Model)), because$thiscannot be guaranteed when the caller is merelystatic.Changes
src/Type/StaticType.php: IntransformStaticType(), afterchangeBaseClass(), check if the resulting type isThisTypeand the caller ($this) is not aThisType— if so, construct a plainStaticTypeinsteadtests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php: AddedtestBug5946()test methodtests/PHPStan/Rules/Methods/data/bug-5946.php: New test data file reproducing the issueCLAUDE.md: Added documentation aboutStaticType::transformStaticTypeandThisTypedowngradingRoot cause
StaticType::transformStaticType()uses$type->changeBaseClass($classReflection)to transform return types. SinceThisType extends StaticType, both are caught by theinstanceof StaticTypecheck. However,ThisType::changeBaseClass()returns a newThisType(preserving$thissemantics), when it should have been downgraded to a plainStaticTypefor callers that arestaticbut not$this. The fix explicitly checks for this case and constructs aStaticTypeinstead.Test
Added a regression test with a
Modelclass that has agetParent()returningstaticand agetModel()returning$this. The test verifies that both$this->getParent()and$this->getParent()->getModel(false)are correctly reported as returningstatic(Model)instead of$this(Model).Fixes phpstan/phpstan#5946