-
Notifications
You must be signed in to change notification settings - Fork 506
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
Reproduce a weird bug with closures #3131
base: 1.12.x
Are you sure you want to change the base?
Conversation
Tests seem to pass in CI 🤯 But locally it fails |
This is exactly what I need to ruin my weekend thinking about this, thanks 😀 /jk of course 😊 |
heheh. It's a challenging one. One thing I just now discovered, I wasn't running the test locally 🤦🏽 I was using |
To be clear: You don't want this error to happen:
Because the return type of the closure shouldn't be limited, right? Because |
I guess this is the same bug as these that popped after that bugfix I did in Verona:
The problem is that we need as precise Closure return type as possible for generics for example. If we have But we don't need the exact type for example in ClosureReturnTypeRule or FunctionCallParametersCheck. Only the type required by involved signatures should be enforced there. The fact that this is enforced inconsistently is another issue that should be addressed. |
In this case, yes. It should respect the return type of the closure. Also if I add a return type to the closure in
Possible. But like I said this error was happening a year ago too. But maybe that bugfix made it become more clear. |
Just realized I hit this bug again, while debugging an issue. Trying to understand what is going on, and what can be the potential solution also gave me a headache 😅 Would be cool if anyone can gave me a direction to look at least. |
@ondrejmirtes I pushed a possible fix for this. My thinking was that we should compare the return type of the closure with the return type of the callable the closure is passed into. This fixes the test case I created and does not fail any other test case locally 🤞🏽 |
Hi, I've thought about this but I think we should make sure that diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php
index 0e7b7c328..0cdaf854b 100644
--- a/src/Analyser/MutatingScope.php
+++ b/src/Analyser/MutatingScope.php
@@ -1242,6 +1242,7 @@ final class MutatingScope implements Scope
$callableParameters = null;
$arrayMapArgs = $node->getAttribute(ArrayMapArgVisitor::ATTRIBUTE_NAME);
+ $inParameter = null;
if ($arrayMapArgs !== null) {
$callableParameters = [];
foreach ($arrayMapArgs as $funcCallArg) {
@@ -1522,6 +1523,17 @@ final class MutatingScope implements Scope
}
}
+ if (
+ $inParameter !== null
+ && !$inParameter->getType()->isCallable()->no()
+ ) {
+ $inParameterCallableReturnTypes = [];
+ foreach ($inParameter->getType()->getCallableParametersAcceptors($this) as $callableParametersAcceptor) {
+ $inParameterCallableReturnTypes[] = $callableParametersAcceptor->getReturnType();
+ }
+ $returnType = self::intersectButNotNever($returnType, TypeCombinator::union(...$inParameterCallableReturnTypes));
+ }
+
foreach ($parameters as $parameter) {
if ($parameter->passedByReference()->no()) {
continue;
But it doesn't because for some reason, Also, there's a problem in always trusting the "passedToType callable's return type" because it might be incompatible with the native return type of the closure. Which I also tried to solve ( |
But that would cause unexpected issues I think. When analyzing the closure body we need precise types, but only for the
Other rules like |
@ondrejmirtes Is there no way the current solution can be accepted? If not, I can start digging into returning correct type from |
@canvural I must admin I don't understand the problem entirely. I'm not sure what's the right type to return from |
@ondrejmirtes From my understanding the issue comes from analyzing the closure at different points. That inconsistency needs to be fixed I guess somehow. Closure is analyzed when it's an argument of a method/function call, and at this point some extensions like the It's also possible I did not understand how stuff works internally. I'll try to look into it again later. |
Hi 👋🏽
Since some time (actually over a a year or two) there is a bug that effects Larastan. Some of the reported ones I could find:
When
method do not supports clousure withwhereIn
expression larastan/larastan#1937And I and other people always suggested to remove the typehint inside the closure. Because that made the error go away, and PHPStan still did know the type.
But when I tried to reproduce it inside the PHPStan I couldn't do it. Until a couple days ago! So I reproduced the failing test, and started looking into the possible fix. But no luck 🫤
Here is a sample code:
Couple of things need to happen for this bug to happen:
someMethod
) needs to come from an extension. IfsomeMethod
was native method ofBuilder
, bug doesn't happen.I step debugged it and my current understanding is that the closure body itself is first analyzed by
ClosureReturnTypeRule
In this case there is no generic information forBuilder $builder
for PHPStan to infer, so it gets the upper boundModel
Later in the analysis the
MethodParameterClosureTypeExtension
kicks in, replaces the closure with correct parameter type. Then it knows the real return type.Side note:
MethodParameterClosureTypeExtension
does not cause this. The linked issues have the problem without that extension, but I just couldn't reproduce it here.So this is where I got so far and kinda blocked. Any clues where I can look further more?