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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to extract nullable type #3623

Closed
lud opened this issue Jul 17, 2020 · 14 comments
Closed

How to extract nullable type #3623

lud opened this issue Jul 17, 2020 · 14 comments
Labels
Milestone

Comments

@lud
Copy link

lud commented Jul 17, 2020

Hi,

I would like to build this function:

function bang($value)
{
    if (null === $value) throw ...
   return $value;
}

And I would call it like this:

class A {
    public function maybeString(): ?string
    {
        if (...) return null;
        else return 'hello';
    }
    
    public function maybeThis(): ?self
    {
        if (...) return null;
        else return $this;
    }
}

bang($a->maybeString()); // @return string
bang($a->maybeThis()); // @return A

So I would like to write a typespec for the bang function, i.e. transforming a type ?T into T.

Is it possible to write such a typespec ?

Thank you.

@ondrejmirtes
Copy link
Member

This should work but currently doesn't: https://phpstan.org/r/15a41cbf-20e8-409e-898f-19afcf823750

@lud
Copy link
Author

lud commented Jul 17, 2020

Thanks @ondrejmirtes that was my first approach too but yes, not working.

I rewrote your example to make it show the problem better (at least to my taste edit: no, I see where yours shows the problem now) : https://phpstan.org/r/38a882d5-d57b-4927-9acd-43a4a0213e99

@ondrejmirtes ondrejmirtes added this to the Generics milestone Jul 17, 2020
@lud
Copy link
Author

lud commented Jul 27, 2020

/**
 * @template T
 * @param T|null $value
 * @return T
 */

When you say it should work, does it means that if the type of the passed argument is ?string, phpstan knows that by mapping T|null to ?string, T is string ?

So what happens there is just that T is mapped to ?string and so @return T logically tells that the function returns ?string. Am I right?

@ondrejmirtes
Copy link
Member

It has to be accounted for in the bugfix.

@lud
Copy link
Author

lud commented Jul 27, 2020

But I am not sure that is correct.

For instance imagine another function where param is T|int, and the passed argument is string|int, should return T mean that the function will only return string?

edit: or is it correct only because of the if (null === $value) part ?

@ondrejmirtes
Copy link
Member

I’m not sure, that would have to investigated and discussed.

@lud
Copy link
Author

lud commented Jul 27, 2020

Ok :)

I hope that will interest someone because I do not have the required skills right now :S

@enumag
Copy link
Contributor

enumag commented Oct 28, 2020

@ondrejmirtes Hmm... I assume this won't be an easy one eh? Ofc it's not just null, the same can be done with other types. So it's most likely a non-trivial generics problem.

@ondrejmirtes
Copy link
Member

I think it's a matter of touching UnionType::inferTemplateTypes() and UnionType::inferTemplateTypesOn(). And yeah, the logic has to account for some edge cases that need to continue to work...

@phpstan-bot
Copy link
Contributor

@ondrejmirtes After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
-28: Strict comparison using === between string|null and 1 will always evaluate to false.
-29: Strict comparison using === between A|null and 1 will always evaluate to false.
+28: Strict comparison using === between string and 1 will always evaluate to false.
+29: Strict comparison using === between A and 1 will always evaluate to false.
Full report
Line Error
28 Strict comparison using === between string and 1 will always evaluate to false.
29 Strict comparison using === between A and 1 will always evaluate to false.

@phpstan-bot
Copy link
Contributor

@lud After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
-32: Parameter #1 $str of function acceptString expects string, string|null given.
-33: Parameter #1 $str of function acceptString expects string, string|null given.
+32: Parameter #1 $str of function acceptString expects string, string|null given.
Full report
Line Error
32 `Parameter #1 $str of function acceptString expects string, string

@ondrejmirtes
Copy link
Member

Fixed: phpstan/phpstan-src@a1b7b38

@lud
Copy link
Author

lud commented Mar 14, 2021

Great, thank you!

@github-actions
Copy link

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 29, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants