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

First-class callable #7196

Closed
userqq opened this issue Dec 21, 2021 · 6 comments · Fixed by #7232
Closed

First-class callable #7196

userqq opened this issue Dec 21, 2021 · 6 comments · Fixed by #7232

Comments

@userqq
Copy link

userqq commented Dec 21, 2021

Hi.
I'm reopening #6989 -

$ php composer.phar show | grep psalm
vimeo/psalm                           dev-master 8ce6c26 A static analysis tool for finding errors in PHP applications
$ vendor/bin/psalm
Target PHP version: 8.1 (set by config file)
Scanning files...
Analyzing files...

Uncaught AssertionError: assert(!$this->isFirstClassCallable()) in /app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php:36
Stack trace:
#0 /app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php(36): assert(false, 'assert(!$this->...')
#1 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/ExpressionIdentifier.php(202): PhpParser\Node\Expr\CallLike->getArgs()
#2 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php(735): Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier::getArrayVarId(Object(PhpParser\Node\Expr\MethodCall), 'UserQQ\\PhpTeleg...', Object(Psalm\Internal\Analyzer\StatementsAnalyzer))
#3 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/AssertionFinder.php(248): Psalm\Internal\Analyzer\Statements\Expression\AssertionFinder::processFunctionCall(Object(PhpParser\Node\Expr\FuncCall), 'UserQQ\\PhpTeleg...', Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(Psalm\Codebase), false)
#4 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(115): Psalm\Internal\Analyzer\Statements\Expression\AssertionFinder::scrapeAssertions(Object(PhpParser\Node\Expr\FuncCall), 'UserQQ\\PhpTeleg...', Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(Psalm\Codebase), false, true, false)
#5 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(575): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context), false, NULL, true)
#6 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(206): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Expression), Object(Psalm\Context), NULL)
#7 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/SwitchCaseAnalyzer.php(471): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context))
#8 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/SwitchAnalyzer.php(123): Psalm\Internal\Analyzer\Statements\Block\SwitchCaseAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(Psalm\Codebase), Object(PhpParser\Node\Stmt\Switch_), '$message->name', Object(PhpParser\Node\Stmt\Case_), Object(Psalm\Context), Object(Psalm\Context), 'return_throw', Array, false, Object(Psalm\Internal\Scope\SwitchScope))
#9 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(555): Psalm\Internal\Analyzer\Statements\Block\SwitchAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Switch_), Object(Psalm\Context))
#10 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(206): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Switch_), Object(Psalm\Context), Object(Psalm\Context))
#11 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(463): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), Object(Psalm\Context), true)
#12 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(1788): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), Object(Psalm\Context))
#13 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(425): Psalm\Internal\Analyzer\ClassAnalyzer->analyzeClassMethod(Object(PhpParser\Node\Stmt\ClassMethod), Object(Psalm\Storage\ClassLikeStorage), Object(Psalm\Internal\Analyzer\ClassAnalyzer), Object(Psalm\Context), Object(Psalm\Context))
#14 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(229): Psalm\Internal\Analyzer\ClassAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Context))
#15 /app/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(362): Psalm\Internal\Analyzer\FileAnalyzer->analyze()
#16 /app/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(619): Psalm\Internal\Codebase\Analyzer->Psalm\Internal\Codebase\{closure}(0, '/app/src/Client...')
#17 /app/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(291): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 1)
#18 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(685): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 1, false, true)
#19 /app/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php(372): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/app/', true)
#20 /app/vendor/vimeo/psalm/psalm(4): Psalm\Internal\Cli\Psalm::run(Array)
#21 {main}
(Psalm dev-master@8ce6c262024979696d93cca8a4ecaca8ba375af9 crashed due to an uncaught Throwable)

8ce6c26 - currently the latest commit in master branch.

@psalm-github-bot
Copy link

Hey @userqq, can you reproduce the issue on https://psalm.dev ?

@FractalizeR
Copy link

FractalizeR commented Dec 21, 2021

Tried to reproduce on psalm.dev, but had no luck. Tests seem to pass ok. Verified my PHP-Parser version - it's v4.13.2.

Guilty line in my case is
return array_map(Uuid::fromString(...), $uuids);

Uuid is from https://github.com/ramsey/uuid. $uuids is a getSingleColumnResult() from Doctrine. PHPStorm detects its type like int|mixed[]|string, however, Doctrine\ORM\AbstractQuery::getSingleColumnResult has only mixed[] type annotation.

@orklah
Copy link
Collaborator

orklah commented Dec 21, 2021

@trowski would you mind looking at this? We have two different stack, the one in the author's issue and the one here #6989 (comment) that fails when using first class callable

Thanks!

@userqq
Copy link
Author

userqq commented Dec 21, 2021

https://psalm.dev/r/e9f65669f5

https://psalm.dev/check responds with error - Argument 1 of array_map expects callable|null, void provided

Local test:

$ php composer.phar show | grep vimeo
vimeo/psalm                           dev-master 8ce6c26 A static analysis tool for finding errors in PHP applications
$ cat error.php
<?php

$q = new \SplQueue();

array_map($q->enqueue(...), [1, 2, 3]);

var_dump($q);
$ php error.php
object(SplQueue)#1 (2) {
  ["flags":"SplDoublyLinkedList":private]=>
  int(4)
  ["dllist":"SplDoublyLinkedList":private]=>
  array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    int(3)
  }
}
$ vendor/bin/psalm error.php
Target PHP version: 8.1 (set by config file)
Scanning files...
Analyzing files...

Uncaught AssertionError: assert(!$this->isFirstClassCallable()) in /app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php:36
Stack trace:
#0 /app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php(36): assert(false, 'assert(!$this->...')
#1 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/MethodCallReturnTypeFetcher.php(115): PhpParser\Node\Expr\CallLike->getArgs()
#2 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/ExistingAtomicMethodCallAnalyzer.php(220): Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MethodCallReturnTypeFetcher::fetch(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(Psalm\Codebase), Object(PhpParser\Node\Expr\MethodCall), Object(Psalm\Context), Object(Psalm\Internal\MethodIdentifier), Object(Psalm\Internal\MethodIdentifier), Object(Psalm\Internal\MethodIdentifier), 'SplQueue::enque...', Object(Psalm\Type\Atomic\TGenericObject), Object(Psalm\Type\Atomic\TGenericObject), Array, Object(Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicMethodCallAnalysisResult), Object(Psalm\Internal\Type\TemplateResult))
#3 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/Method/AtomicMethodCallAnalyzer.php(429): Psalm\Internal\Analyzer\Statements\Expression\Call\Method\ExistingAtomicMethodCallAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\MethodCall), Object(PhpParser\Node\Identifier), Array, Object(Psalm\Codebase), Object(Psalm\Context), Object(Psalm\Type\Atomic\TGenericObject), Object(Psalm\Type\Atomic\TGenericObject), '$q', Object(Psalm\Internal\MethodIdentifier), Object(Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicMethodCallAnalysisResult))
#4 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php(186): Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicMethodCallAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\MethodCall), Object(Psalm\Codebase), Object(Psalm\Context), Object(Psalm\Type\Union), Object(Psalm\Type\Atomic\TGenericObject), Object(Psalm\Type\Atomic\TGenericObject), false, '$q', Object(Psalm\Internal\Analyzer\Statements\Expression\Call\Method\AtomicMethodCallAnalysisResult))
#5 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(186): Psalm\Internal\Analyzer\Statements\Expression\Call\MethodCallAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\MethodCall), Object(Psalm\Context))
#6 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(78): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\MethodCall), Object(Psalm\Context), false, NULL, false)
#7 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php(213): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\MethodCall), Object(Psalm\Context))
#8 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php(174): Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Array, Array, 'array_map', true, Object(Psalm\Context))
#9 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(296): Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context))
#10 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(78): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context), false, NULL, true)
#11 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(575): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context), false, NULL, true)
#12 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(206): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Expression), Object(Psalm\Context), NULL)
#13 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(205): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), NULL, true)
#14 /app/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(362): Psalm\Internal\Analyzer\FileAnalyzer->analyze()
#15 /app/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(619): Psalm\Internal\Codebase\Analyzer->Psalm\Internal\Codebase\{closure}(0, '/app/error.php')
#16 /app/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(291): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 1)
#17 /app/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(1206): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 1, false, false)
#18 /app/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php(374): Psalm\Internal\Analyzer\ProjectAnalyzer->checkPaths(Array)
#19 /app/vendor/vimeo/psalm/psalm(4): Psalm\Internal\Cli\Psalm::run(Array)
#20 {main}
(Psalm dev-master@8ce6c262024979696d93cca8a4ecaca8ba375af9 crashed due to an uncaught Throwable)
root@99fe0df78810:/app#

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/e9f65669f5
<?php

$q = new \SplQueue();

array_map($q->enqueue(...), [1, 2, 3]);

var_dump($q);
Psalm output (using commit 8ce6c26):

ERROR: InvalidArgument - 5:11 - Argument 1 of array_map expects callable|null, void provided

ERROR: UnusedFunctionCall - 5:1 - The call to array_map is not used

ERROR: ForbiddenCode - 7:1 - Unsafe var_dump

@orklah
Copy link
Collaborator

orklah commented Dec 21, 2021

I can reproduce locally too, psalm.dev absence of the same error may be due to psalm/psalm.dev#68

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants