diff --git a/tests/PHPStan/Analyser/ReturnedExprGetTypeRule.php b/tests/PHPStan/Analyser/ReturnedExprGetTypeRule.php new file mode 100644 index 00000000000..bd5295a32d7 --- /dev/null +++ b/tests/PHPStan/Analyser/ReturnedExprGetTypeRule.php @@ -0,0 +1,38 @@ + + */ +class ReturnedExprGetTypeRule implements Rule +{ + + public function getNodeType(): string + { + return ClassMethod::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $return = (new NodeFinder())->findFirstInstanceOf((array) $node->stmts, Return_::class); + if ($return === null || $return->expr === null) { + return []; + } + + $scope->getType($return->expr); + + return []; + } + +} diff --git a/tests/PHPStan/Analyser/ReturnedExprGetTypeRuleTest.php b/tests/PHPStan/Analyser/ReturnedExprGetTypeRuleTest.php new file mode 100644 index 00000000000..666fe8e194a --- /dev/null +++ b/tests/PHPStan/Analyser/ReturnedExprGetTypeRuleTest.php @@ -0,0 +1,26 @@ + + */ +class ReturnedExprGetTypeRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new ReturnedExprGetTypeRule(); + } + + #[RequiresPhp('>= 8.0.0')] + public function testRule(): void + { + $this->analyse([__DIR__ . '/data/returned-expr-get-type.php'], []); + } + +} diff --git a/tests/PHPStan/Analyser/data/returned-expr-get-type.php b/tests/PHPStan/Analyser/data/returned-expr-get-type.php new file mode 100644 index 00000000000..301a5feefd7 --- /dev/null +++ b/tests/PHPStan/Analyser/data/returned-expr-get-type.php @@ -0,0 +1,27 @@ += 8.0 + +declare(strict_types = 1); + +namespace ReturnedExprGetType; + +/** @template T */ +final class Bag { + /** @param list $items */ + public function __construct(private array $items) {} + /** @return list */ + public function all(): array { return $this->items; } +} + +/** + * @template TReturnType + * @param callable(): TReturnType $callback + * @return TReturnType + */ +function once4(callable $callback) { return $callback(); } + +final class Box4 { + /** @return Bag */ + public function items(): Bag { + return once4(function (): Bag { return new Bag(['a']); }); + } +} diff --git a/turbo-ext/src/ReturnHandler.cpp b/turbo-ext/src/ReturnHandler.cpp index f88043fb621..2a3f3c19788 100644 --- a/turbo-ext/src/ReturnHandler.cpp +++ b/turbo-ext/src/ReturnHandler.cpp @@ -79,6 +79,7 @@ class ReturnHandler zval *throwPoints = &emptyArray; zval *impurePoints = &emptyArray; zval *dependencies = NULL; + zv::Val result; zv::Val variableFlow; expr = returnedExpr(stmt); if (UNEXPECTED(expr == NULL)) return zv::Val(); @@ -96,7 +97,7 @@ class ReturnHandler Z_TYPE_P(expectedReturnType.raw()) == IS_OBJECT ? expectedReturnType.raw() : NULL, Z_TYPE_P(nativeExpectedReturnType.raw()) == IS_OBJECT ? nativeExpectedReturnType.raw() : NULL); if (UNEXPECTED(expressionContext.isUndef())) return zv::Val(); - zv::Val result = pt_node_scope_resolver_process_expr_node(nodeScopeResolver, stmt, expr, stmtScope.raw(), storage, nodeCallback, expressionContext.raw()); + result = pt_node_scope_resolver_process_expr_node(nodeScopeResolver, stmt, expr, stmtScope.raw(), storage, nodeCallback, expressionContext.raw()); if (UNEXPECTED(result.isUndef())) return zv::Val(); dependencies = pt_expression_result_dependencies(result.raw(), dependenciesHold); if (UNEXPECTED(dependencies == NULL)) return zv::Val();