Skip to content

Conversation

@staabm
Copy link
Contributor

@staabm staabm commented Jan 9, 2026

@staabm
Copy link
Contributor Author

staabm commented Jan 9, 2026

I think the bug does not reproduce in tests (but it does when running the repro script standalone), because in tests a method is filtered out because it is reported to have impure point, while it doesn't have a impure point when running standalone

if (count($node->getImpurePoints()) !== 0) {
return null;
}

@staabm
Copy link
Contributor Author

staabm commented Jan 9, 2026

applying this diff makes the test fail, with the same error we get when run standalone:

diff --git a/src/Rules/DeadCode/CallToMethodStatementWithoutImpurePointsRule.php b/src/Rules/DeadCode/CallToMethodStatementWithoutImpurePointsRule.php
index a04d151ad9..65d63f8d29 100644
--- a/src/Rules/DeadCode/CallToMethodStatementWithoutImpurePointsRule.php
+++ b/src/Rules/DeadCode/CallToMethodStatementWithoutImpurePointsRule.php
@@ -34,6 +34,11 @@ final class CallToMethodStatementWithoutImpurePointsRule implements Rule
                        }
                }
 
+               $methods['bug13956\foo'] =  [
+                       'addsuccess' => 'Bug13956\Foo::addSuccess',
+                       'getsuccessmessages' => 'Bug13956\Foo::getSuccessMessages',
+               ];
+
                $errors = [];
                foreach ($node->get(PossiblyPureMethodCallCollector::class) as $filePath => $data) {
                        foreach ($data as [$classNames, $method, $line]) {

@staabm
Copy link
Contributor Author

staabm commented Jan 10, 2026

interessting.. I can see that in

$methodImpurePoints[] = new ImpurePoint(

a impure point is generated and appended to the by-ref array &$methodImpurePoints but when inspecting this line

$methodReflection = $methodScope->getFunction();

I can see the array is still empty.

so I suspect either xdebug is lying/buggy or php-src somehow looses the by-ref appended array content.
maybe its working like fiber should work by design, but thats something I haven't enough experience with to judge.

@staabm
Copy link
Contributor Author

staabm commented Jan 10, 2026

hmm maybe the problem is, that we are appending to the array from inside a fiber..

grafik

but the actual array lives in the non-fiber execution context

grafik

because I can see the array beeing empty after the callable, even though it was appended to it in the meantime


repro:

➜  phpstan-src git:(testBug13956) ✗ cp tests/PHPStan/Rules/Methods/data/bug-13956.php .


➜  phpstan-src git:(testBug13956) ✗ PHPSTAN_FNSR=1 php bin/phpstan analyze bug-13956.php --debug         
Note: Using configuration file /Users/staabm/workspace/phpstan-src/phpstan.neon.dist.
/Users/staabm/workspace/phpstan-src/bug-13956.php
int(0)
int(0)
appending
int(0)
 ------ ----------------------------------------------------------------------------- 
  Line   bug-13956.php                                                                
 ------ ----------------------------------------------------------------------------- 
  30     Call to method Bug13956\Foo::addSuccess() on a separate line has no effect.  
         🪪  method.resultUnused                                                      
         at bug-13956.php:30                                                          
 ------ ----------------------------------------------------------------------------- 


                                                                                                                        
 [ERROR] Found 1 error                                                                                                  
                                                                                                                        

with

--- a/src/Analyser/NodeScopeResolver.php
+++ b/src/Analyser/NodeScopeResolver.php
@@ -816,6 +816,7 @@ class NodeScopeResolver
                                                ) {
                                                        return;
                                                }
+                                               echo "appending\n";
                                                $methodImpurePoints[] = new ImpurePoint(
                                                        $scope,
                                                        $node,
@@ -839,6 +840,7 @@ class NodeScopeResolver
                                        $gatheredReturnStatements[] = new ReturnStatement($scope, $node);
                                }, StatementContext::createTopLevel())->toPublic();
 
+                               var_dump(count($methodImpurePoints));
                                $methodReflection = $methodScope->getFunction();
                                if (!$methodReflection instanceof PhpMethodFromParserNodeReflection) {
                                        throw new ShouldNotHappenException();

@ondrejmirtes
Copy link
Member

Fibers are not threads, they still work with the same objects and values, they are just "functions that can be paused and resumed later".

I'll look into it later, but caching of FileTypeMapper and releasing the current performance improvements is a priority 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FNSR false positive: Call to method X on a separate line has no effect

2 participants