phpstan / phpstan

PHP Static Analysis Tool - discover bugs in your code without running it!
https://phpstan.org/
MIT License
12.72k stars 861 forks source link

Nested Conditional Return Types Don't Work #11188

Open clementbirkle opened 1 month ago

clementbirkle commented 1 month ago

Bug report

Hello,

I have a function like this:

/**
 * @template TDefault
 * @template TExplicit
 *
 * @param  class-string<TDefault>|string  $abstract
 * @param  array<string, mixed>  $parameters
 * @param  class-string<TExplicit>|null  $type
 * @return ($type is class-string ? TExplicit : ($abstract is class-string ? TDefault : mixed))
 */
function instance(string $abstract, array $parameters = [], ?string $type = null): mixed
{
    return app($abstract, $parameters);
}

PHPStan will find an error if the function is called like this: instance('cache', [], Cache::class)->nonExistingMethod();

However, if the function is called like this: instance(Cache::class)->nonExistingMethod(); PHPStan will not find the error.

I think the issue arises from the nested conditional return type.

According to this article, it should work.

My IDE (VS Code with PHP Intelephense) understands this nested condition.

Code snippet that reproduces the problem

https://phpstan.org/r/8720f545-358a-49bb-bbd4-5df79636fc4a

Expected output

PHPStan should return an error about the missing method in both cases. It correctly finds an error if the function is called like this: instance('cache', [], Cache::class)->nonExistingMethod();

Did PHPStan help you today? Did it make you happy in any way?

No response

mergeable[bot] commented 1 month ago

This bug report is missing a link to reproduction at phpstan.org/try.

It will most likely be closed after manual review.

clementbirkle commented 1 month ago

Here is the link: https://phpstan.org/r/8720f545-358a-49bb-bbd4-5df79636fc4a

ondrejmirtes commented 1 month ago

This is how the example should look like: https://phpstan.org/r/b2863df1-593a-4ff2-915a-4457fa7f23e1

But it still doesn't work. If the condition is not nested then it works fine for the 2nd case: https://phpstan.org/r/235cc7bf-bfcd-4775-b879-5bba56105450

This kind of pattern is supported since https://github.com/phpstan/phpstan-src/pull/1465but it doesn't work nested conditions. //cc @rvanvelzen could you look at this? Thanks :)

clementbirkle commented 1 month ago

Thank you, @ondrejmirtes, for your explanation and for correcting me. The autocompletion in my IDE doesn't work in your first example because @param class-string<TDefault>|string $abstract was removed.

So, for me, the correct example is: https://phpstan.org/r/50dcee86-0454-4d8c-94f4-7de57d0ca193, but as you said, it still doesn't work.

According to my example, PHPStan should return 2 same errors: Call to an undefined method DateTime::nonExistingMethod(). and not Cannot call method nonExistingMethod() on mixed.