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

CarbonImmutable Macro Causes PHPStan Internal Error #2828

Closed
LukeAbell opened this issue Jul 31, 2023 · 7 comments
Closed

CarbonImmutable Macro Causes PHPStan Internal Error #2828

LukeAbell opened this issue Jul 31, 2023 · 7 comments

Comments

@LukeAbell
Copy link

LukeAbell commented Jul 31, 2023

Hello,

I encountered an issue with the following code:

When using a CarbonImmutable macro in Laravel v10, PHPStan throws an error.

Internal error: Internal error: No closure found on line 161 in AppServiceProvider.php.

Line 161:

CarbonImmutable::macro('toCustomDisplayFormat', function (): string {
	return $this->format(AppServiceProvider::TIME_FORMAT_DISPLAY);
});

It does not error when using standard Carbon macros, but we use CarbonImmutable everywhere so need them defined there.

Carbon version: 2.68.1

PHP version: 8.1

I expected to get:

I expect it not to crash PHPStan.

But I actually get:

It crashes PHPStan
Stack Trace
 #0 ondrejmirtes/better-reflection/src/SourceLocator/Type/ClosureSourceLocator.php(132):
 PHPStan\BetterReflection\SourceLocator\Exception\NoClosureOnLine::create('/Users/lukeabel...', 161)
 #1 ondrejmirtes/better-reflection/src/SourceLocator/Type/ClosureSourceLocator.php(147):
 PhpParser\NodeVisitorAbstract@anonymous->getClosureNodes()
 #2 ondrejmirtes/better-reflection/src/SourceLocator/Type/ClosureSourceLocator.php(54):
 PHPStan\BetterReflection\SourceLocator\Type\ClosureSourceLocator->getReflectionFunction(Object(PHPStan\BetterReflection\Reflector\DefaultReflector), Object(PHPStan\BetterReflection\Identifier\IdentifierType))
 #3 ondrejmirtes/better-reflection/src/SourceLocator/Type/AggregateSourceLocator.php(26):
 PHPStan\BetterReflection\SourceLocator\Type\ClosureSourceLocator->locateIdentifier(Object(PHPStan\BetterReflection\Reflector\DefaultReflector), Object(PHPStan\BetterReflection\Identifier\Identifier))
 #4 ondrejmirtes/better-reflection/src/Reflector/DefaultReflector.php(58):
 PHPStan\BetterReflection\SourceLocator\Type\AggregateSourceLocator->locateIdentifier(Object(PHPStan\BetterReflection\Reflector\DefaultReflector), Object(PHPStan\BetterReflection\Identifier\Identifier))
 #5 ondrejmirtes/better-reflection/src/Reflection/ReflectionFunction.php(72):
 PHPStan\BetterReflection\Reflector\DefaultReflector->reflectFunction('{closure}')
 #6 nesbot/carbon/src/Carbon/PHPStan/AbstractMacro.php(130): PHPStan\BetterReflection\Reflection\ReflectionFunction::createFromClosure(Object(Closure))
 #7 nesbot/carbon/src/Carbon/PHPStan/AbstractMacro.php(87): Carbon\PHPStan\AbstractMacro->getReflectionFunction(Object(Closure))
 #8 nesbot/carbon/src/Carbon/PHPStan/MacroScanner.php(82): Carbon\PHPStan\AbstractMacro->__construct('Carbon\\CarbonIm...', 'toSailTimeDispl...', Object(Closure))
 #9 nesbot/carbon/src/Carbon/PHPStan/MacroExtension.php(66): Carbon\PHPStan\MacroScanner->getMethod('Carbon\\CarbonIm...', 'toSailTimeDispl...')
 #10 src/Reflection/ClassReflection.php(462): Carbon\PHPStan\MacroExtension->getMethod(Object(PHPStan\Reflection\ClassReflection),
 'toSailTimeDispl...')
 #11 src/Type/ObjectType.php(584): PHPStan\Reflection\ClassReflection->getMethod('toSailTimeDispl...',
 Object(PHPStan\Analyser\MutatingScope))
 #12 src/Type/ObjectType.php(561): PHPStan\Type\ObjectType->getUnresolvedMethodPrototype('toSailTimeDispl...',
 Object(PHPStan\Analyser\MutatingScope))
 #13 src/Analyser/MutatingScope.php(3412): PHPStan\Type\ObjectType->getMethod('toSailTimeDispl...',
 Object(PHPStan\Analyser\MutatingScope))
 #14 src/Analyser/NodeScopeResolver.php(1747): PHPStan\Analyser\MutatingScope->getMethodReflection(Object(PHPStan\Type\ObjectType),
 'toSailTimeDispl...')
 #15 src/Analyser/NodeScopeResolver.php(2904):
 PHPStan\Analyser\NodeScopeResolver->processExprNode(Object(PhpParser\Node\Expr\MethodCall), Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\ExpressionContext))
 #16 src/Analyser/NodeScopeResolver.php(1884):
 PHPStan\Analyser\NodeScopeResolver->processArgs(Object(PHPStan\Reflection\Php\PhpMethodReflection), Object(PHPStan\Reflection\FunctionVariantWithPhpDocs), Array, Object(PHPStan\Analyser\MutatingScope), Object(Closure),
 Object(PHPStan\Analyser\ExpressionContext), NULL)
 #17 src/Analyser/NodeScopeResolver.php(1731):
 PHPStan\Analyser\NodeScopeResolver->processExprNode(Object(PhpParser\Node\Expr\StaticCall), Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\ExpressionContext))
 #18 src/Analyser/NodeScopeResolver.php(1585):
 PHPStan\Analyser\NodeScopeResolver->processExprNode(Object(PhpParser\Node\Expr\MethodCall), Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\ExpressionContext))
 #19 src/Analyser/NodeScopeResolver.php(3007):
 PHPStan\Analyser\NodeScopeResolver->PHPStan\Analyser\{closure}(Object(PHPStan\Analyser\MutatingScope))
 #20 src/Analyser/NodeScopeResolver.php(1593):
 PHPStan\Analyser\NodeScopeResolver->processAssignVar(Object(PHPStan\Analyser\MutatingScope), Object(PhpParser\Node\Expr\Variable), Object(PhpParser\Node\Expr\MethodCall), Object(Closure),
 Object(PHPStan\Analyser\ExpressionContext), Object(Closure), true)
 #21 src/Analyser/NodeScopeResolver.php(599): PHPStan\Analyser\NodeScopeResolver->processExprNode(Object(PhpParser\Node\Expr\Assign),
 Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\ExpressionContext))
 #22 src/Analyser/NodeScopeResolver.php(384):
 PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Expression), Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #23 src/Analyser/NodeScopeResolver.php(766):
 PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Stmt\Foreach_), Array, Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #24 src/Analyser/NodeScopeResolver.php(384): PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Foreach_),
 Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #25 src/Analyser/NodeScopeResolver.php(557):
 PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Stmt\ClassMethod), Array, Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #26 src/Analyser/NodeScopeResolver.php(3594):
 PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\ClassMethod), Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #27 src/Analyser/NodeScopeResolver.php(3610):
 PHPStan\Analyser\NodeScopeResolver->processNodesForCalledMethod(Object(PhpParser\Node\Stmt\Class_), '/Users/lukeabel...', Object(PHPStan\Reflection\ResolvedMethodReflection), Object(Closure))
 #28 src/Analyser/NodeScopeResolver.php(3606): PHPStan\Analyser\NodeScopeResolver->processNodesForCalledMethod(Array,
 '/Users/lukeabel...', Object(PHPStan\Reflection\ResolvedMethodReflection), Object(Closure))
 #29 src/Analyser/NodeScopeResolver.php(3610):
 PHPStan\Analyser\NodeScopeResolver->processNodesForCalledMethod(Object(PhpParser\Node\Stmt\Namespace_), '/Users/lukeabel...', Object(PHPStan\Reflection\ResolvedMethodReflection), Object(Closure))
 #30 src/Analyser/NodeScopeResolver.php(3540): PHPStan\Analyser\NodeScopeResolver->processNodesForCalledMethod(Array,
 '/Users/lukeabel...', Object(PHPStan\Reflection\ResolvedMethodReflection), Object(Closure))
 #31 src/Analyser/NodeScopeResolver.php(1776):
 PHPStan\Analyser\NodeScopeResolver->processCalledMethod(Object(PHPStan\Reflection\ResolvedMethodReflection))
 #32 src/Analyser/NodeScopeResolver.php(2001):
 PHPStan\Analyser\NodeScopeResolver->processExprNode(Object(PhpParser\Node\Expr\MethodCall), Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\ExpressionContext))
 #33 src/Analyser/NodeScopeResolver.php(1986):
 PHPStan\Analyser\NodeScopeResolver->processExprNode(Object(PhpParser\Node\Expr\ArrayItem), Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\ExpressionContext))
 #34 src/Analyser/NodeScopeResolver.php(577): PHPStan\Analyser\NodeScopeResolver->processExprNode(Object(PhpParser\Node\Expr\Array_),
 Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\ExpressionContext))
 #35 src/Analyser/NodeScopeResolver.php(384): PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Return_),
 Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #36 src/Analyser/MutatingScope.php(1038): PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Expr\Closure),
 Array, Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #37 src/Analyser/MutatingScope.php(562): PHPStan\Analyser\MutatingScope->resolveType('function (int $...',
 Object(PhpParser\Node\Expr\Closure))
 #38 src/Reflection/ParametersAcceptorSelector.php(129): PHPStan\Analyser\MutatingScope->getType(Object(PhpParser\Node\Expr\Closure))
 #39 src/Analyser/MutatingScope.php(3424):
 PHPStan\Reflection\ParametersAcceptorSelector::selectFromArgs(Object(PHPStan\Analyser\MutatingScope), Array, Array)
 #40 src/Analyser/MutatingScope.php(1366):
 PHPStan\Analyser\MutatingScope->methodCallReturnType(Object(PHPStan\Type\Generic\GenericObjectType), 'mapWithKeys', Object(PhpParser\Node\Expr\MethodCall))
 #41 src/Analyser/MutatingScope.php(1372): PHPStan\Analyser\MutatingScope->PHPStan\Analyser\{closure}()
 #42 src/Analyser/MutatingScope.php(562): PHPStan\Analyser\MutatingScope->resolveType('\\Illuminate\\Sup...',
 Object(PhpParser\Node\Expr\MethodCall))
 #43 src/Analyser/MutatingScope.php(1366): PHPStan\Analyser\MutatingScope->getType(Object(PhpParser\Node\Expr\MethodCall))
 #44 src/Analyser/MutatingScope.php(1372): PHPStan\Analyser\MutatingScope->PHPStan\Analyser\{closure}()
 #45 src/Analyser/MutatingScope.php(562): PHPStan\Analyser\MutatingScope->resolveType('\\Illuminate\\Sup...',
 Object(PhpParser\Node\Expr\MethodCall))
 #46 src/Rules/FunctionReturnTypeCheck.php(53): PHPStan\Analyser\MutatingScope->getType(Object(PhpParser\Node\Expr\MethodCall))
 #47 src/Rules/Methods/ReturnTypeRule.php(43):
 PHPStan\Rules\FunctionReturnTypeCheck->checkReturnType(Object(PHPStan\Analyser\MutatingScope), Object(PHPStan\Type\ArrayType), Object(PhpParser\Node\Expr\MethodCall), Object(PhpParser\Node\Stmt\Return_), 'Method
 App\\Cont...', 'Method App\\Cont...', 'Method App\\Cont...', 'Method App\\Cont...', false)
 #48 src/Analyser/FileAnalyser.php(104): PHPStan\Rules\Methods\ReturnTypeRule->processNode(Object(PhpParser\Node\Stmt\Return_),
 Object(PHPStan\Analyser\MutatingScope))
 #49 src/Node/ClassStatementsGatherer.php(108):
 PHPStan\Analyser\FileAnalyser->PHPStan\Analyser\{closure}(Object(PhpParser\Node\Stmt\Return_), Object(PHPStan\Analyser\MutatingScope))
 #50 src/Analyser/NodeScopeResolver.php(539): PHPStan\Node\ClassStatementsGatherer->__invoke(Object(PhpParser\Node\Stmt\Return_),
 Object(PHPStan\Analyser\MutatingScope))
 #51 src/Analyser/NodeScopeResolver.php(441):
 PHPStan\Analyser\NodeScopeResolver::PHPStan\Analyser\{closure}(Object(PhpParser\Node\Stmt\Return_), Object(PHPStan\Analyser\MutatingScope))
 #52 src/Analyser/NodeScopeResolver.php(384): PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Return_),
 Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #53 src/Analyser/NodeScopeResolver.php(557):
 PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Stmt\ClassMethod), Array, Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #54 src/Analyser/NodeScopeResolver.php(384):
 PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\ClassMethod), Object(PHPStan\Analyser\MutatingScope), Object(PHPStan\Node\ClassStatementsGatherer),
 Object(PHPStan\Analyser\StatementContext))
 #55 src/Analyser/NodeScopeResolver.php(640): PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Stmt\Class_),
 Array, Object(PHPStan\Analyser\MutatingScope), Object(PHPStan\Node\ClassStatementsGatherer), Object(PHPStan\Analyser\StatementContext))
 #56 src/Analyser/NodeScopeResolver.php(384): PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Class_),
 Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #57 src/Analyser/NodeScopeResolver.php(612):
 PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Stmt\Namespace_), Array, Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #58 src/Analyser/NodeScopeResolver.php(353):
 PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Namespace_), Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
 #59 src/Analyser/FileAnalyser.php(173): PHPStan\Analyser\NodeScopeResolver->processNodes(Array,
 Object(PHPStan\Analyser\MutatingScope), Object(Closure))
 #60 src/Command/WorkerCommand.php(130): PHPStan\Analyser\FileAnalyser->analyseFile('/Users/lukeabel...', Array,
 Object(PHPStan\Rules\LazyRegistry), Object(PHPStan\Collectors\Registry), NULL)
 #61 evenement/evenement/src/Evenement/EventEmitterTrait.php(97):
 PHPStan\Command\WorkerCommand->PHPStan\Command\{closure}(Array)
 #62 clue/ndjson-react/src/Decoder.php(117): _PHPStan_d55c4f2c2\Evenement\EventEmitter->emit('data', Array)
 #63 evenement/evenement/src/Evenement/EventEmitterTrait.php(97):
 _PHPStan_d55c4f2c2\Clue\React\NDJson\Decoder->handleData(Array)
 #64 react/stream/src/Util.php(62): _PHPStan_d55c4f2c2\Evenement\EventEmitter->emit('data', Array)
 #65 evenement/evenement/src/Evenement/EventEmitterTrait.php(97):
 _PHPStan_d55c4f2c2\React\Stream\Util::_PHPStan_d55c4f2c2\React\Stream\{closure}('{"action":"anal...')
 #66 react/stream/src/DuplexResourceStream.php(154): _PHPStan_d55c4f2c2\Evenement\EventEmitter->emit('data', Array)
 #67 react/event-loop/src/StreamSelectLoop.php(201): _PHPStan_d55c4f2c2\React\Stream\DuplexResourceStream->handleData(Resource
 id #9095)
 #68 react/event-loop/src/StreamSelectLoop.php(173):
 _PHPStan_d55c4f2c2\React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
 #69 src/Command/WorkerCommand.php(96): _PHPStan_d55c4f2c2\React\EventLoop\StreamSelectLoop->run()
 #70 symfony/console/Command/Command.php(259):
 PHPStan\Command\WorkerCommand->execute(Object(_PHPStan_d55c4f2c2\Symfony\Component\Console\Input\ArgvInput), Object(_PHPStan_d55c4f2c2\Symfony\Component\Console\Output\ConsoleOutput))
 #71 symfony/console/Application.php(870):
 _PHPStan_d55c4f2c2\Symfony\Component\Console\Command\Command->run(Object(_PHPStan_d55c4f2c2\Symfony\Component\Console\Input\ArgvInput), Object(_PHPStan_d55c4f2c2\Symfony\Component\Console\Output\ConsoleOutput))
 #72 symfony/console/Application.php(261):
 _PHPStan_d55c4f2c2\Symfony\Component\Console\Application->doRunCommand(Object(PHPStan\Command\WorkerCommand), Object(_PHPStan_d55c4f2c2\Symfony\Component\Console\Input\ArgvInput),
 Object(_PHPStan_d55c4f2c2\Symfony\Component\Console\Output\ConsoleOutput))
 #73 symfony/console/Application.php(157):
 _PHPStan_d55c4f2c2\Symfony\Component\Console\Application->doRun(Object(_PHPStan_d55c4f2c2\Symfony\Component\Console\Input\ArgvInput), Object(_PHPStan_d55c4f2c2\Symfony\Component\Console\Output\ConsoleOutput))
 #74 bin/phpstan(124): _PHPStan_d55c4f2c2\Symfony\Component\Console\Application->run()
 #75 bin/phpstan(125): _PHPStan_d55c4f2c2\{closure}()
 #76 phpstan/phpstan/phpstan(8): require('phar:///Users/l...')
 #77 bin/phpstan(119): include('/Users/lukeabel...')
 #78 {main}

I opened an issue in the PHPStan repo but they pointed me here.

Thanks!

@kylekatarnls
Copy link
Collaborator

Hello,

I went to the line nesbot/carbon/src/Carbon/PHPStan/AbstractMacro.php(130) the one belonging to our project in the stak trace.

And we do: BetterReflectionFunction::createFromClosure($spec) with $spec being the closure line 161 in AppServiceProvider.php and the code for our PHPStan extension does not have specific behavior for Carbon vs. CarbonImmutable as it targets CarbonInterface so I have to dig deeper.

@LukeAbell
Copy link
Author

@kylekatarnls thanks for looking into it!

@LukeAbell
Copy link
Author

@kylekatarnls the error does not happen with the following versions:

  • larastan v2.2.6
  • phpstan v1.8.11
  • carbon v2.62.1

@ondrejmirtes
Copy link
Contributor

Hi, I've fixed a similar problem in PHPStan, it might have fixed this problem too: phpstan/phpstan#9776

@kylekatarnls
Copy link
Collaborator

kylekatarnls commented Aug 19, 2023

@LukeAbell Please check if phpstan/phpstan:1.11.x-dev fixes the issue.

From here I'm unable to reproduce the issue with any version of phpstan (on Laravel 10, with carbon 2.69.0 and larastan 2.6.4)

If you still have the issue with the latest PHPStan 1.11.x-dev, please create a small repository that reproduces the problem and re-open the issue.

@kylekatarnls
Copy link
Collaborator

Hello, I was able to get the same error with PHPStan 1.10.29 in a simpler context (no Laravel, but with the Carbon extension loaded). And upgrading to composer require phpstan/phpstan:1.11.x-dev fixed the issue, so there is good chances that it also fixes this one.

@ondrejmirtes
Copy link
Contributor

1.10.x-dev should also fix the issue. That's what's going to be tagged as 1.10.30 early next week.

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

No branches or pull requests

3 participants