Repository navigation
[6.x] Resolve self/static template args against implementing class before bound check - #11833
Merged
Merged
Conversation
…ound check
`ClassLikeAnalyzer::checkTemplateParams` was comparing the raw `$extended_type`
against the parent's template bound without first running it through
`TypeExpander::expandUnion`. As a result `self`/`static` survived as an
unresolved `TNamedObject('self'|'static')` and `UnionTypeComparator::isContainedBy`
correctly returned false against any class bound, producing a false-positive
`InvalidTemplateParam` on annotations like
/** @implements Holder */
final class C extends Base implements Holder {}
even when the implementing class clearly satisfied the bound. Replacing `self`
with the FQN made the error go away. The fix runs `expandUnion` against the
implementing class up-front, matching the call shape in
`Codebase\ClassLikes::1078` and `Codebase\Methods::750`.
Covers all four `@implements`/`@extends`/`@template-implements`/
`@template-extends` surfaces, plus trait `@use` (which routes through the same
`checkTemplateParams`). Resolves vimeo#11199.
…* coverage Matches the more cautious precedent in `Codebase\Methods::750`. For final classes, `static` and `self` are equivalent and the resulting type should not carry `is_static = true`; passing `$storage->final` preserves that. Adds 5 regression tests: - nestedStaticInGenericTemplateArgFinalClass (Holder> on a final class) - nestedStaticInGenericTemplateArgNonFinalClass - nestedSelfInGenericTemplateArg - staticAsTemplateArgInTemplateImplementsRespectsParentBound - staticAsTemplateArgInTemplateExtendsRespectsParentBound The nested-generic cases were already accepted by the previous patch (the expansion recurses through `TGenericObject::type_params`); they are committed as documentation that the bound check stays correct in those shapes.
alies-dev
force-pushed
the
fix/self-template-arg-not-expanded
branch
from
September 27, 2026 22:19
ce68a9c to
e078b52
Compare
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.
Fixes #11199.
Currently
@implements Ierrors withExtended template param ... type self given, even when the implementing class clearly satisfies the bound. Replacingselfwith the FQN makes the error go away. Issue #11199 reports the same bound-check failure for trait@use HasCollection.The cause:
ClassLikeAnalyzer::checkTemplateParamspassed$extended_typestraight fromtemplate_extended_paramsintoUnionTypeComparator::isContainedBywithout running it throughTypeExpander::expandUnion. Soself/staticsurvived as a rawTNamedObjectand the bound check could not resolve them to the implementing class. Other call sites (Codebase\ClassLikes:1078,Codebase\Methods:750) already useTypeExpander::expandUnion. This fix supplies the current class name, parent class and class finality when expanding template arguments before checking their bounds.The same code path handles
@extends,@template-implements,@template-extendsand trait@use, so all of them are covered. Tests exerciseselfandstaticacross all five annotation forms, nestedstaticin final and non-final classes, and nestedselfin a final class. Two negative cases expectInvalidTemplateParamfor bound-violatingselfarguments in@implementsand trait@use.