diff --git a/src/Reflection/ParametersAcceptorSelector.php b/src/Reflection/ParametersAcceptorSelector.php index 2eb2f885944..d3d1773f802 100644 --- a/src/Reflection/ParametersAcceptorSelector.php +++ b/src/Reflection/ParametersAcceptorSelector.php @@ -592,9 +592,6 @@ public static function hasAcceptorTemplateOrLateResolvableType(ParametersAccepto return self::hasAcceptorTemplateOrLateResolvableParameterType($acceptor); } - /** - * @internal - */ public static function hasAcceptorTemplateOrLateResolvableParameterType(ParametersAcceptor $acceptor): bool { foreach ($acceptor->getParameters() as $parameter) { diff --git a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php index 0c94a5082c7..ef46fe63ac1 100644 --- a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php @@ -277,7 +277,18 @@ public function isBuiltin(): bool public function isGenerator(): bool { - return $this->nodeIsOrContainsYield($this->functionLike); + // the yield scan walks the whole body; reflections for the same node are + // recreated per ask, so the answer is memoized on the AST node itself + // and lives and dies with the parser-cached AST + $cached = $this->functionLike->getAttribute('phpstanIsGenerator'); + if ($cached !== null) { + return $cached; + } + + $isGenerator = NodeScanner::nodeIsOrContainsYield($this->functionLike); + $this->functionLike->setAttribute('phpstanIsGenerator', $isGenerator); + + return $isGenerator; } public function acceptsNamedArguments(): TrinaryLogic @@ -285,11 +296,6 @@ public function acceptsNamedArguments(): TrinaryLogic return TrinaryLogic::createFromBoolean($this->acceptsNamedArguments); } - private function nodeIsOrContainsYield(Node $node): bool - { - return NodeScanner::nodeIsOrContainsYield($node); - } - public function getAsserts(): Assertions { return $this->assertions; diff --git a/src/Rules/Generators/YieldFromTypeRule.php b/src/Rules/Generators/YieldFromTypeRule.php index b77f04b53a4..a0102c5c9e1 100644 --- a/src/Rules/Generators/YieldFromTypeRule.php +++ b/src/Rules/Generators/YieldFromTypeRule.php @@ -137,7 +137,7 @@ public function processNode(Node $node, Scope $scope): array ))->identifier('generator.sendType')->build(); } - if (!$scope->isInFirstLevelStatement() && $scope->getType($node)->isVoid()->yes()) { + if (!$scope->isInFirstLevelStatement() && $scope->getKeepVoidType($node)->isVoid()->yes()) { $messages[] = RuleErrorBuilder::message('Result of yield from (void) is used.') ->identifier('generator.void') ->build(); diff --git a/src/Rules/Generators/YieldTypeRule.php b/src/Rules/Generators/YieldTypeRule.php index e5f94c81932..0f42eecd120 100644 --- a/src/Rules/Generators/YieldTypeRule.php +++ b/src/Rules/Generators/YieldTypeRule.php @@ -86,7 +86,7 @@ public function processNode(Node $node, Scope $scope): array ->identifier('generator.valueType') ->build(); } - if (!$scope->isInFirstLevelStatement() && $scope->getType($node)->isVoid()->yes()) { + if (!$scope->isInFirstLevelStatement() && $scope->getKeepVoidType($node)->isVoid()->yes()) { $messages[] = RuleErrorBuilder::message('Result of yield (void) is used.') ->identifier('generator.void') ->build();