diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index ca1daa6f340..c821df615e1 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -907,6 +907,8 @@ public function processStmtNode( return new InternalStatementResult($scope, $hasYield, true, [ new InternalStatementExitPoint($stmt, $scope), ], $overridingThrowPoints ?? $throwPoints, $impurePoints); + } elseif ($stmt instanceof Node\Stmt\Goto_) { + return new InternalStatementResult($scope, false, true, [], $overridingThrowPoints ?? [], []); } elseif ($stmt instanceof Node\Stmt\Expression) { if ($stmt->expr instanceof Expr\Throw_) { $scope = $stmtScope; diff --git a/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php b/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php index b848a761d7c..109bb23dd80 100644 --- a/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php +++ b/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php @@ -373,4 +373,11 @@ public function testBug12722(): void $this->analyse([__DIR__ . '/data/bug-12722.php'], []); } + #[RequiresPhp('>= 8.0')] + public function testBug9444(): void + { + $this->checkExplicitMixedMissingReturn = true; + $this->analyse([__DIR__ . '/data/bug-9444.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Missing/data/bug-9444.php b/tests/PHPStan/Rules/Missing/data/bug-9444.php new file mode 100644 index 00000000000..cdc5848b50d --- /dev/null +++ b/tests/PHPStan/Rules/Missing/data/bug-9444.php @@ -0,0 +1,53 @@ += 8.0 + +declare(strict_types = 1); + +namespace Bug9444; + +class HelloWorld +{ + + /** @throws \Exception */ + public static function riskyOp(): string + { + return 'ok'; + } + + public function gotoRetry(): string + { + $i = 0; + beginning: + try { + return self::riskyOp(); + } catch (\Throwable $e) { + if (++$i < 5) { + goto beginning; + } else { + throw $e; + } + } + } + + public function gotoRetrySimple(): string + { + beginning: + try { + return self::riskyOp(); + } catch (\Throwable $e) { + goto beginning; + } + } + + public function gotoInCatch(): int + { + $result = 0; + beginning: + try { + $result = random_int(1, 100); + } catch (\Throwable $e) { + goto beginning; + } + return $result; + } + +}