Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Template type is not narrowed down in conditional return types #10622

Closed
canvural opened this issue Feb 23, 2024 · 7 comments
Closed

Template type is not narrowed down in conditional return types #10622

canvural opened this issue Feb 23, 2024 · 7 comments

Comments

@canvural
Copy link
Contributor

Bug report

Hello 馃憢馃徑

I have the following snippet:

<?php declare(strict_types = 1);

class Model {}

/**
 * @template TKey of array-key
 * @template TModel
 *
 */
class SupportCollection {}

/**
 * @template TKey of array-key
 * @template TModel of Model
 *
 */
class Collection
{
    /**
     * Run a map over each of the items.
     *
     * @template TMapValue
     *
     * @param  callable(TModel, TKey): TMapValue  $callback
     * @return (TMapValue is Model ? static<TKey, TMapValue> : SupportCollection<TKey, TMapValue>)
     */
    public function map(callable $callback) {} // @phpstan-ignore return.missing
}

I was expecting the TMapValue to be narrowed down to Model in static<TKey, TMapValue> because we are in the truthy branch of the if condition. But as it can be seen in the playground, it doesn't work like that.

Am I wrong to expect that, or is it a bug?

Code snippet that reproduces the problem

https://phpstan.org/r/92226828-0e09-4210-9906-6b1df14395c0

Expected output

No errors.

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

It helps me every day!

@ondrejmirtes
Copy link
Member

Even if we eliminate static<TKey, TMapValue> which isn't supported, it still does not work: https://phpstan.org/r/385b8e60-9e39-474f-963b-2a6559a975d8

I think we need some logic to make it understand that TMapValue in the then part of the conditional type always has Model bound which it currently doesn't understand.

If you try to use this signature does it work as expected? You can try some dumpType calls.

@canvural
Copy link
Contributor Author

Yes it works, the return type is narrowed down correctly. But this code is in the stubs, so it throws the same error you see in the playground, when it validates the stub files.

For now I'll try to do the same thing with return type extensions.

@rvanvelzen
Copy link
Contributor

When the conditional type is resolved the type is narrowed correctly, but GenericObjectTypeCheck does not do this as there is no real way to do it without resolving the type (which in turn could cause false negatives).

@ondrejmirtes
Copy link
Member

I think it could apply the condition in the then branch and apply it inversely in the else branch. So the type in the then branch would be an intersection with the subject type.

@rvanvelzen
Copy link
Contributor

Yep, that's basically what's happening in ConditionalType::getResult() already. That logic should be reused for this.

@ondrejmirtes
Copy link
Member

Fixed phpstan/phpstan-src#2948

phpstan-bot added a commit that referenced this issue Mar 22, 2024
phpstan/phpstan-src@0f2366b Add more tests for issue #10622
phpstan/phpstan-src@ec1209d Merge branch refs/heads/1.10.x into 1.11.x
phpstan/phpstan-src@944673f Fix slow enum cases union with lots of cases
phpstan/phpstan-src@625298a Merge branch refs/heads/1.10.x into 1.11.x
phpstan-bot added a commit that referenced this issue Mar 22, 2024
Copy link

github-actions bot commented Apr 2, 2024

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants