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

Wrong type inference when using array_map and Generics #4902

Closed
b-viguier opened this issue Apr 25, 2021 · 6 comments
Closed

Wrong type inference when using array_map and Generics #4902

b-viguier opened this issue Apr 25, 2021 · 6 comments

Comments

@b-viguier
Copy link

Bug report

I'm playing a lot with Generics and I encountered a strange issue. I reproduced the issue with a minimal code. The goal is to wrap a value of Generic type in a wrapper class. When I want to unwrap a list of wrapped values, I use array_map, but when I try to wrap again this array I'm facing different results according to the used method.

Code snippet that reproduces the problem

https://phpstan.org/r/09243518-e539-4a98-8a24-4400d2d766a6

Expected output

The snippet contains two versions of the same function. PhpStan complains about unwrapAllAndWrapAgain but not about unwrapAllAndWrapAgain2. It's like the type narrowing fails, and then we have to compare a mixed type 🤨

🙇‍♂️Thanks a lot for your amazing work on PhpStan, it's really a game changer in Php ecosystem 👏

@ondrejmirtes
Copy link
Member

Hi, neither unwrapAllAndWrapAgain nor unwrapAll actually work, see: https://phpstan.org/r/dba21179-2463-4e08-bc9e-5b717dad5bbd

If you use a closure instead of a string argument, it all works: https://phpstan.org/r/f7ee5f7e-87c2-4efa-a1b2-867604694bbf

I don't think we can solve it in a nice way right now. The problem is that "function as a string" is supported through PHPStan\Type\Type::getCallableParametersAcceptors() which returns ParametersAcceptor[], but the template type map is on FunctionReflection/MethodReflection, one level up.

@ondrejmirtes
Copy link
Member

And thank you for your kind words! :)

@ondrejmirtes ondrejmirtes added this to the Generics milestone Apr 25, 2021
@b-viguier
Copy link
Author

Thanks for this fast and helpful reply 👍
Executable strings are always tedious to handle 😉 I had the same result with a callable array (i.e [$this, 'unwrap']), I imagine both cases are related.

For your information, I tested with an arrow function, I expected the same behavior than with a classic anonymous function, but it still produces the same error… Are arrow functions treated differently from normal closures? 🤔
https://phpstan.org/r/c75198c5-506f-4026-9ec0-93c7886ff818

By the way, I didn't know the \PHPStan\dumpType function, it will be very helpful to understand how type are inferred with Generics 👍

Since this behavior is a known limitation, we can close this issue from my point of view.
🙇‍♂️

@ondrejmirtes
Copy link
Member

The thing is - PHPStan mostly understands executable strings and callable arrays, it just doesn't work for generics in this case :)

Arrow functions are different from closures in some key areas so inferring the return type from the function body is not yet implemented, see: #3660

I'm gonna keep this open, it's always possible it will start working thanks to some internal change, or I get an idea how to implement it effortlessly :)

Thanks.

@phpstan-bot
Copy link
Contributor

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

@@ @@
-PHP 7.4 – 8.0 (5 errors)
+PHP 7.4 – 8.0 (4 errors)
 ==========
 
 50: Dumped type: Closure(Wrapper): mixed
 51: Dumped type: Closure(Wrapper): mixed
 53: Dumped type: array<int, T-all (function unwrapAllAndWrapAgain(), argument)>
-56: Dumped type: array<int, mixed>
-58: Function unwrapAllAndWrapAgain() should return Wrapper<array<int, T-all>> but returns Wrapper<array<int, mixed>>.
+56: Dumped type: array<int, T-all (function unwrapAllAndWrapAgain(), argument)>
 
 PHP 7.1 – 7.3 (5 errors)
 ==========
Full report

PHP 7.4 – 8.0 (4 errors)

Line Error
50 Dumped type: Closure(Wrapper): mixed
51 Dumped type: Closure(Wrapper): mixed
53 Dumped type: array<int, T-all (function unwrapAllAndWrapAgain(), argument)>
56 Dumped type: array<int, T-all (function unwrapAllAndWrapAgain(), argument)>

PHP 7.1 – 7.3 (5 errors)

Line Error
49 Syntax error, unexpected T_VARIABLE, expecting ')' on line 49
56 Syntax error, unexpected ',' on line 56
56 Syntax error, unexpected T_VARIABLE, expecting ')' on line 56
58 Syntax error, unexpected ',' on line 58
58 Syntax error, unexpected T_VARIABLE, expecting ')' on line 58

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

No branches or pull requests

3 participants