Skip to content

[Bug]: Relative class name inside an array shape in a generic argument is not resolved #93

Closed

Description

@fdaviddpt

Bug report

In @extends Box<array{user: User}>, User is not resolved against the current namespace, so the right object is rejected.

<?php

namespace App;

class User {}

/** @template T */
class Box
{
    /** @param T $value */
    public function put(mixed $value): void {}
}

/** @extends Box<array{user: User}> */
class UserBox extends Box {}

(new UserBox())->put(['user' => new User()]);
Fatal error: Uncaught TypePHP\Exception\TypeError: App\UserBox::put(): Argument $value (template T = array{user: User})['user'] must be of type User, App\User given in playground.php on line 17

What passes and what fails:

Docblock Result
@param array{user: User} $v (no generics) OK
@extends Box<User> OK
@extends Box<list<User>> OK
@extends Box<array{user: \App\User}> OK
@extends Box<array{user: User}> fails

Same with an imported class (use Models\User;): must be of type User, Models\User given.
Tested on v0.10.26 and on main (2ec0426).

Code snippet that reproduces the problem

https://typephp-php.github.io/docs/playground#code=N4IgLglmA2CmIC4QCUCuA7SBbWACZsEAZhLACa4Dis6sAThAMYDOIANCIwPZnxIA8AfgAOAC2EAddFPQBDHM2GzGeAILDhAbilTG0Wc2a4Aqs3q5gAXx3oA9ACp7uAAJhYWYfre4AKrnu2uvqGuABCXAAeUsBSuHG4Dk7OSnTyvrgAJABustCoeAGx8cKoAEbQTLhEGIyQXOi4JWAAFFgQEeSZOXmwAJQIuFlcEBRWUtbSdo4usBFu6GRG4RH8snSpAJ7AqGZ0A6b0lgB8-oHoegZGB3TLuLPzi2GRFhNSzbQA7ia7y829vQBaI5NZoAbQA5Dt6ODcABeE6fb70P4AXV62nQ7E49RIAHNEKAaLJyuREGA6PkOBBceguHRYD5UioACKwYRgUSIABMAFYOGtNgA1XIjWR1TFIarQaBY5jkphgAhgVB0dDUWgMRgASXQOQYsnOfHJlJA9MUsFqADkxRAsrBLahpcSIBUwBsyRTYBwzcILWAtTS6QzZLjWAhjV6QFgQ0wAAp0Li+uhugiyRaIIi5MxU9AVWjCuhh0DCBNJyCwMMRji4mj0JiVz0cRi5fQkhsm5jN-SFj0mgWyDbtyNcUoAKz9Q8sU6AA

Expected output

No error: User inside the shape is App\User, as it is everywhere else in the file and as PHPStan resolves it.

Context: in our codebase almost every command declares its options as @extends Command<array{module: SiModule, agency: Agency, ...}>, so this stops our test suite at bootstrap. Thanks for TypePHP, it already caught three wrong docblocks in our core that PHPStan missed.

Activity

  1. self-assigned this
    on Oct 3, 2026
  2. rcalicdan commented on Oct 3, 2026

    @rcalicdan
    Member

    Thank you for this bug report, this will be fix in next patch release..

  3. linked a pull request that will close this issueInternal improvements 36 #96on Oct 3, 2026
  4. rcalicdan commented on Oct 3, 2026

    @rcalicdan
    Member

    Hi

    This issue has now been resolved//
    Under the hood, I have added recursive FQCN namespace resolution across all inherited generic tags (@extends, @implements, and @use on traits). Beyond array shapes, this fix also comprehensively covers unqualified class names inside:

    Array & Object shapes (e.g. array{user: User}, object{user: User})
    Callables & Closures (e.g. callable(User): User)
    Iterables & Generators (e.g. iterable, Traversable<string, User>, Generator<int, User>)

    A full regression test suite covering classes, interfaces, and traits has been added, and the fix will be included in the v0.10.28 patch released..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions