Skip to content

[6.x] Resolve self/static template args against implementing class before bound check - #11833

Merged
danog merged 2 commits into
vimeo:6.xfrom
alies-dev:fix/self-template-arg-not-expanded
Sep 28, 2026
Merged

danog merged 2 commits into
vimeo:6.xfrom
alies-dev:fix/self-template-arg-not-expanded

Conversation

@alies-dev

@alies-dev alies-dev commented May 6, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #11199.

Currently @implements I errors with Extended template param ... type self given, even when the implementing class clearly satisfies the bound. Replacing self with the FQN makes the error go away. Issue #11199 reports the same bound-check failure for trait @use HasCollection.

The cause: ClassLikeAnalyzer::checkTemplateParams passed $extended_type straight from template_extended_params into UnionTypeComparator::isContainedBy without running it through TypeExpander::expandUnion. So self/static survived as a raw TNamedObject and the bound check could not resolve them to the implementing class. Other call sites (Codebase\ClassLikes:1078, Codebase\Methods:750) already use TypeExpander::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-extends and trait @use, so all of them are covered. Tests exercise self and static across all five annotation forms, nested static in final and non-final classes, and nested self in a final class. Two negative cases expect InvalidTemplateParam for bound-violating self arguments in @implements and trait @use.

@alies-dev alies-dev changed the title Resolve self/static template args against implementing class before bound check [6.x] Resolve self/static template args against implementing class before bound check May 6, 2026
…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
alies-dev force-pushed the fix/self-template-arg-not-expanded branch from ce68a9c to e078b52 Compare September 27, 2026 22:19
@danog danog added the release:fix The PR will be included in 'Fixes' section of the release notes label Sep 28, 2026
@danog
danog merged commit 89db91c into vimeo:6.x Sep 28, 2026
61 of 62 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release:fix The PR will be included in 'Fixes' section of the release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

False positive InvalidTemplateParam when use "static" as Template Param

2 participants