Fix phpstan/phpstan#12964: Support for covariant templates in interface properties in 8.4#5415
Fix phpstan/phpstan#12964: Support for covariant templates in interface properties in 8.4#5415phpstan-bot wants to merge 3 commits intophpstan:2.1.xfrom
Conversation
…oks and asymmetric visibility - Treat properties with only a get hook (no set hook) as covariant position - Treat properties with private(set) or protected(set) as covariant position - New regression test in tests/PHPStan/Rules/Generics/data/bug-12964.php
VincentLanglet
left a comment
There was a problem hiding this comment.
isEffectivelyReadOnly is an unclear name
Address review feedback: the previous name was unclear about what it checked. The new name better communicates that the method detects properties with restricted write access (asymmetric visibility or get-only hooks). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Done. I renamed |
VincentLanglet
left a comment
There was a problem hiding this comment.
/**
* @template-covariant T
*/
class A
{
/**
* @param T $data
*/
public function __construct(
protected mixed $data,
) {}
}
is currently reported by PHPStan so I don't see a reason to ignore protectedSet
protected(set) allows subclasses to write to the property, just like regular protected properties. Only private(set) truly restricts writes to the declaring class, so only private(set) should be treated as covariant. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
All 11,736 tests pass. Here's a summary of the change: Problem: The reviewer correctly pointed out that Fix: Removed |
Summary
PHP 8.4 introduced property hooks and asymmetric visibility. Properties with only a
gethook (nosethook) and properties withprivate(set)orprotected(set)are effectively read-only from the public API perspective. PHPStan was incorrectly treating these properties as invariant for template variance checking, producing false positive errors like "Template type T is declared as covariant, but occurs in invariant position in property".Changes
src/Rules/Generics/PropertyVarianceRule.phpto detect effectively read-only properties:private(set)orprotected(set)asymmetric visibilitygethook and nosethookreadonlyproperties)Root cause
The
PropertyVarianceRuleonly checkedisReadOnly()andisReadOnlyByPhpDoc()when deciding whether a property is in covariant position. It did not account for PHP 8.4's property hooks (get-only) and asymmetric visibility (private(set),protected(set)), which also make properties effectively read-only from the external API.Test
Added
tests/PHPStan/Rules/Generics/data/bug-12964.phpwith comprehensive test cases covering:{ get; }hook (covariant and contravariant templates)private(set)(covariant and contravariant templates)protected(set)(covariant templates){ get; set; }hooks (should remain invariant)@template-covariantand{ get; }, class withprivate(set)Fixes phpstan/phpstan#12964