vimeo / psalm

A static analysis tool for finding errors in PHP applications
https://psalm.dev
MIT License
5.57k stars 660 forks source link

Incompatible types found when calling another templated function inside a trait #10820

Open StephaneLeveugle opened 8 months ago

StephaneLeveugle commented 8 months ago

I have an error when calling a templated function expecting collections inside a trait, here is the minimal reproducer I could make: https://psalm.dev/r/fac6728ba5

In this example a Vector is used but it behaves the same for other collections like Doctrine collections

However the same code using an array doesn't raise any error: https://psalm.dev/r/4efb1ca461

I'm not sure if this is a bug or a misunderstanding on my part, please tell me if there's another way to achieve the desired result.

Thank you

psalm-github-bot[bot] commented 8 months ago

I found these snippets:

https://psalm.dev/r/fac6728ba5 ```php $param1 * @param Vector $param2 */ public static function method(Vector $param1, Vector $param2): void { } } abstract class SubEntity {} class FirstSubEntity extends SubEntity {} class Entity { /** @use MyTrait */ use MyTrait; public function __construct( /** @var Vector */ public Vector $subEntities = new Vector(), ) { } } /** * @template T of SubEntity */ trait MyTrait { /** @var Vector */ public Vector $subEntities; /** * @param Vector $param1 */ public function traitMethod(Vector $param1): void { Helper::method($this->subEntities, $param1); } } $entity = new Entity(); $entity->subEntities->push(new FirstSubEntity()); $firstSubEntities = new Vector([new FirstSubEntity()]); $entity->traitMethod($firstSubEntities); ``` ``` Psalm output (using commit ef3b018): ERROR: InvalidArgument - 44:9 - Incompatible types found for T (must have only one of FirstSubEntity, T:MyTrait as SubEntity) ```
https://psalm.dev/r/4efb1ca461 ```php $param1 * @param list $param2 */ public static function method(array $param1, array $param2): void { } } abstract class SubEntity {} class FirstSubEntity extends SubEntity {} class Entity { /** @use MyTrait */ use MyTrait; public function __construct( /** @var list */ public array $subEntities = [], ) { } } /** * @template T of SubEntity */ trait MyTrait { /** @var list */ public array $subEntities; /** * @param list $param1 */ public function traitMethod(array $param1): void { Helper::method($this->subEntities, $param1); } } $wow = new Entity(); $wow->subEntities[] = new FirstSubEntity(); $firstSubEntities = [new FirstSubEntity()]; $wow->traitMethod($firstSubEntities); ``` ``` Psalm output (using commit ef3b018): No issues! ```