Skip to content

Resolve generic static<...> property types against the fetched-on class - #6799

Closed
HawkForge wants to merge 1 commit into
phpstan:2.3.xfrom
HawkForge:fix/15378-generic-static-property
Closed

HawkForge wants to merge 1 commit into
phpstan:2.3.xfrom
HawkForge:fix/15378-generic-static-property

Conversation

@HawkForge

Copy link
Copy Markdown
Contributor

Closes phpstan/phpstan#15378

Thanks @LastDragon-ru for the report.

A property declared as @var static<ANode> in a generic class NodeCursor<TNode> was read as NodeCursor<BNode>|null when fetched on NodeCursor<BNode>: the explicit type argument was lost.

CalledOnTypeUnresolvedPropertyPrototypeReflection::transformStaticType() replaced every StaticType - including GenericStaticType - with the fetched-on type, so the type arguments written in static<...> were dropped. Method return types do not have this problem because CalledOnTypeUnresolvedMethodPrototypeReflection::transformStaticType() already handles GenericStaticType by changing its base class to the called-on class and taking its static object type.

This applies the same GenericStaticType handling to the property prototype; bare @var static still resolves to the fetched-on type. The class is shadowed by the turbo extension, so the same change is ported to turbo-ext/src/CalledOnTypeUnresolvedPropertyPrototypeReflection.cpp (mirroring the method-side C++ code).

The regression test tests/PHPStan/Analyser/nsrt/bug-15378.php is the reproducer from the issue; it fails without the fix (Expected: Bug15378\NodeCursor<Bug15378\ANode>|null, Actual: Bug15378\NodeCursor<Bug15378\BNode>|null) and passes with it, both with and without the turbo extension loaded.

@ondrejmirtes

Copy link
Copy Markdown
Member

Looks like a property equivalent to #6695.

@ondrejmirtes

Copy link
Copy Markdown
Member

Superseded by #6826

ondrejmirtes added a commit that referenced this pull request Oct 24, 2026
CalledOnTypeUnresolvedPropertyPrototypeReflection replaced every StaticType,
GenericStaticType included, with the fetched-on type, so the type arguments
written in `@var static<...>` were dropped: on `NodeCursor<BNode>`, a property
declared `static<ANode>` was read as `NodeCursor<BNode>`. This handles
GenericStaticType like CalledOnTypeUnresolvedMethodPrototypeReflection does
for method return types.

The bug-15378 regression test comes from #6799.

Co-Authored-By: HawkForge <75696486+HawkForge@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011i2xTiyrXgfVkG1tmwMtUM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

static<Class> incorrectly resolved as static (Class is lost)

2 participants