Skip to content

Commit 64e339b

Browse files
phpstan-botclaude
andcommitted
Fix catch block scope for union throw types with direct match
When a method declares `@throws A|B` and a catch block catches `A`, the check for direct explicit non-throw match was using `$catchType->isSuperTypeOf($throwType)->yes()` which returns `maybe` for union throw types (since the catch doesn't cover `B`). This caused implicit throw points to be included unnecessarily, leading to false "variable might not be defined" reports. The fix decomposes union throw types and checks each member individually, so `A` in `A|B` is recognized as a direct match for `catch (A)`. Non-union types retain the original behavior, preserving correctness for cases like `@throws RuntimeException` caught as `PDOException`. Fixes inconsistency between DbCommand5 and DbCommand6 test cases. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a191a3b commit 64e339b

1 file changed

Lines changed: 7 additions & 2 deletions

File tree

src/Analyser/NodeScopeResolver.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,8 +1896,13 @@ public function processStmtNode(
18961896
&& !($throwNode instanceof Node\Stmt\Expression && $throwNode->expr instanceof Expr\Throw_)
18971897
) {
18981898
$onlyExplicitIsThrow = false;
1899-
if ($catchTypeItem->isSuperTypeOf($throwPoint->getType())->yes()) {
1900-
$hasDirectExplicitNonThrowMatch = true;
1899+
$throwType = $throwPoint->getType();
1900+
$innerTypes = $throwType instanceof UnionType ? $throwType->getTypes() : [$throwType];
1901+
foreach ($innerTypes as $innerThrowType) {
1902+
if ($catchTypeItem->isSuperTypeOf($innerThrowType)->yes()) {
1903+
$hasDirectExplicitNonThrowMatch = true;
1904+
break;
1905+
}
19011906
}
19021907
}
19031908
$matchingThrowPoints[$throwPointIndex] = $throwPoint;

0 commit comments

Comments
 (0)