vimeo / psalm

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

[bug] psalm doesn't recognize @implements on concrete class #11051

Open andreifurrnica opened 1 month ago

andreifurrnica commented 1 month ago

Concrete example: ~https://psalm.dev/r/318efd13bb~ https://psalm.dev/r/7bd876d3f7

I was expecting Psalm to know that SampleTransformer is an instance of TransformerInterface<object, object>.

Not sure if it's a bug or if I'm doing something wrong, but it looks like a bug to me

psalm-github-bot[bot] commented 1 month ago

I found these snippets:

https://psalm.dev/r/318efd13bb ```php id; } } class B { private string $id = ''; public function setId(string $id): static { $this->id = $id; return $this; } } /** * @template T of object * @template TResult of object */ abstract class TransformerInterface { /** * @param T $a * @return TResult */ abstract public function transform(object $a): object; } /** * @extends TransformerInterface */ class SampleTransformer extends TransformerInterface { public function transform(object $a): object { $response = new B(); $response->setId((string)$a->getId()); return $response; } } /** * @param class-string $entityClass */ function applyListProperties( string $entityClass, TransformerInterface $transformer, ):object { return $transformer->transform(new \stdClass); } applyListProperties(\stdClass::class, new SampleTransformer()); ``` ``` Psalm output (using commit 16b24bd): ERROR: InvalidArgument - 63:39 - Argument 2 of applyListProperties expects TransformerInterface, but SampleTransformer provided ```
https://psalm.dev/r/7bd876d3f7 ```php id; } } class B { private string $id = ''; public function setId(string $id): static { $this->id = $id; return $this; } } /** * @template T of object * @template TResult of object */ interface TransformerInterface { /** * @param T $a * @return TResult */ public function transform(object $a): object; } /** * @implements TransformerInterface */ class SampleTransformer implements TransformerInterface { public function transform(object $a): object { $response = new B(); $response->setId((string)$a->getId()); return $response; } } function applyListProperties( TransformerInterface $transformer, ): object { return $transformer->transform(new \stdClass); } applyListProperties(new SampleTransformer()); ``` ``` Psalm output (using commit 16b24bd): ERROR: InvalidArgument - 60:21 - Argument 1 of applyListProperties expects TransformerInterface, but SampleTransformer provided ```