Skip to content

Fix phpstan/phpstan#11314: Template of imported type breaks imported type#5360

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-xt25se8
Open

Fix phpstan/phpstan#11314: Template of imported type breaks imported type#5360
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-xt25se8

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

When a class has both @phpstan-import-type Breed from Cat and @template T of Breed in the same PHPDoc comment, the imported type alias Breed could not be resolved. Properties typed with @var Breed were incorrectly resolved to string (the native type) instead of the imported type alias.

Changes

  • Modified src/Type/FileTypeMapper.php to store a partial NameScope (with type aliases resolved but before template tag resolution) and return it when a cyclic dependency is detected during getNameScope(), instead of throwing NameScopeAlreadyBeingCreatedException
  • Added $inProcessNameScopes field to track partial NameScopes during resolution
  • Added regression test in tests/PHPStan/Analyser/nsrt/bug-11314.php

Root cause

When FileTypeMapper::getNameScope() resolves template tag bounds, it calls TypeNodeResolver::resolve() which triggers type alias resolution through UsefulTypeAliasResolver::resolveLocalTypeAlias(). This in turn calls ClassReflection::getTypeAliases(), which needs getResolvedPhpDoc(), which calls back to FileTypeMapper::getNameScope() for the same class. The cycle detection in getNameScope() threw NameScopeAlreadyBeingCreatedException, causing getResolvedPhpDoc() to return an empty PHPDoc block. With empty PHPDoc, getTypeAliases() returned an empty array, so the imported type alias could not be found.

The fix stores the NameScope built so far (which already has type alias information) before template resolution begins. When the cycle is detected, this partial NameScope is returned instead of throwing. This allows ClassReflection::getTypeAliases() to correctly extract type alias information from the PHPDoc, breaking the cycle while preserving the data needed for type alias resolution.

Test

Added tests/PHPStan/Analyser/nsrt/bug-11314.php which verifies that Cat2::$breed (with both @phpstan-import-type and @template T of Breed) correctly resolves to 'British Shorthair'|'Maine Coon'|'Siamese' instead of string.

Fixes phpstan/phpstan#11314

…type

- When a class has both @phpstan-import-type and @template with the imported type as bound, resolving the template bound triggered a cyclic dependency in FileTypeMapper
- The cycle occurred because resolving the type alias went through ClassReflection::getTypeAliases() which needed the full resolved PHPDoc, but the PHPDoc was still being built
- Fix: store a partial NameScope (with type aliases but before template resolution) and return it on cycle detection instead of throwing NameScopeAlreadyBeingCreatedException
- New regression test in tests/PHPStan/Analyser/nsrt/bug-11314.php
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.

1 participant