Skip to content

Fix #11463: Using phpstan-import-type between classes makes alias unresolvable#4976

Open
phpstan-bot wants to merge 1 commit into2.1.xfrom
create-pull-request/patch-y8thmln
Open

Fix #11463: Using phpstan-import-type between classes makes alias unresolvable#4976
phpstan-bot wants to merge 1 commit into2.1.xfrom
create-pull-request/patch-y8thmln

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When two classes have mutual @phpstan-import-type dependencies (e.g., FooType imports Bar from BarType, and BarType imports Foo from FooType), PHPStan reported "PHPDoc tag @param contains unresolvable type" even though each imported type was a locally-defined @phpstan-type on the target class.

Changes

  • Modified ClassReflection::getTypeAliases() in src/Reflection/ClassReflection.php to return local type aliases (defined via @phpstan-type) when circular import resolution is detected, instead of immediately throwing CircularTypeAliasDefinitionException
  • Added regression test in tests/PHPStan/Rules/PhpDoc/data/bug-11463.php and corresponding test method in IncompatiblePhpDocTypeRuleTest.php

Root cause

ClassReflection::getTypeAliases() uses a static $resolvingTypeAliasImports array to detect circular import chains. When class A's imports trigger resolution of class B's aliases, which in turn tries to resolve class A's aliases, the method immediately threw CircularTypeAliasDefinitionException. However, this is overly conservative: the imported type is a local @phpstan-type definition on the target class, not another import. Local type aliases don't depend on other classes' imports and can be safely returned even during circular resolution.

The fix checks whether the class has local type aliases before throwing the exception. If it does, those are returned to break the cycle, allowing the importing class to find the locally-defined type it needs.

Test

The regression test reproduces the exact scenario from the issue: two classes with mutual @phpstan-import-type tags where each imports a @phpstan-type defined locally on the other class. The test expects no errors (previously it produced "contains unresolvable type").

Fixes phpstan/phpstan#11463

…solvable

- When two classes have mutual @phpstan-import-type tags (FooType imports Bar
  from BarType, BarType imports Foo from FooType), the circular detection in
  ClassReflection::getTypeAliases() was too aggressive
- The fix returns local type aliases (defined via @phpstan-type) when circular
  import resolution is detected, since local aliases don't depend on imports
- Added regression test in tests/PHPStan/Rules/PhpDoc/data/bug-11463.php

Closes phpstan/phpstan#11463
Comment on lines +1382 to +1385
$localAliases = array_map(static fn (TypeAliasTag $typeAliasTag): TypeAlias => $typeAliasTag->getTypeAlias(), $typeAliasTags);
if ($localAliases !== []) {
return $localAliases;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this assign to $this->typeAliases?

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.

2 participants