Skip to content

feat(errors): register UnhandledMatchError as a builtin Error subclass#521

Open
chadmandoo wants to merge 1 commit into
illegalstudio:mainfrom
chadmandoo:upstream-pr/unhandled-match-error
Open

feat(errors): register UnhandledMatchError as a builtin Error subclass#521
chadmandoo wants to merge 1 commit into
illegalstudio:mainfrom
chadmandoo:upstream-pr/unhandled-match-error

Conversation

@chadmandoo

Copy link
Copy Markdown
Contributor

What

UnhandledMatchError — PHP 8's error thrown when a match expression has no matching arm and no default — was not a registered builtin, so a program that references it (including the common default => throw new UnhandledMatchError(...) idiom) failed to type-check.

function classify(int $n): string {
    return match (true) {
        $n < 0   => "neg",
        $n === 0 => "zero",
        default  => throw new UnhandledMatchError("no arm for " . $n),
    };
}
try { classify(5); } catch (\UnhandledMatchError $e) { echo $e->getMessage(); }

How

Register UnhandledMatchError as a builtin class extending Error (the class-name list + the class_map insert in declarations.rs) and include it in the Error-family signature fixup (exception.rs), mirroring TypeError / ValueError / ArithmeticError.

Test

test_unhandled_match_error_throw_and_catch — newable, throwable from a match default arm, catchable by FQN, getMessage() round-trip. Byte-parity vs PHP 8.5.

🤖 Generated with Claude Code

A `match` expression with no `default` arm throws `UnhandledMatchError` at the
implicit no-match point, and codegen materializes that class reference — but it
was not among elephc's declared builtin throwables, so every default-less `match`
failed type resolution with "Undefined class: UnhandledMatchError" (ward-sse
DatastarEventSerializer and other match-dispatch classes).

Declare `UnhandledMatchError extends Error` alongside TypeError/ValueError/
ArithmeticError in `inject_builtin_throwables`, and add it to the autoload
builtin-class list. Like its siblings it is a nominal marker subclass —
constructor/getMessage/etc. are inherited from Error transitively.

Whole-codebase survey 852 -> 854 OK (80.4%), zero regressions: error_tests
byte-identical to baseline, full codegen sweep unchanged at the pre-existing 440
failures, a default-less `match` now compiles and runs natively. Adds regression
test test_match_without_default_compiles. Refs #605.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chadmandoo chadmandoo force-pushed the upstream-pr/unhandled-match-error branch from 4a82b7a to 5614400 Compare July 11, 2026 13:53
@github-actions github-actions Bot added area:resolver Touches include, namespace, name, or autoload resolution. area:types Touches type checking, inference, or compatibility. size:xs Very small pull request. type:feature Introduces new user-visible behavior or capabilities. labels Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:resolver Touches include, namespace, name, or autoload resolution. area:types Touches type checking, inference, or compatibility. size:xs Very small pull request. type:feature Introduces new user-visible behavior or capabilities.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant