void-payloads, multi-pattern arms, and range patterns (match statements)

This commit is contained in:
2026-06-29 19:52:05 +02:00
parent 462632554c
commit c82f070d55
8 changed files with 499 additions and 106 deletions
+36
View File
@@ -504,6 +504,42 @@
is not a runtime field type yet, so 21.5 can't declare them, though the no-capture arm
form is already wired; and multi-pattern arms (`.a, .b:`) / range patterns
22.5. `void`-payloads and multi-pattern arms / range patterns in match statements (implemented; see below)
- **void-payload variants**: a tagged union may declare a `void`-payload variant
(`quit void`). As in Zig, a void field carries no runtime value — it is allowed only on a
tagged union (the record-decl check skips the runtime-value requirement for it), contributes
nothing to the layout (`size` 0 / `align` 1, so it is never the carrier), and is constructed
with the **bare-key** literal `T{ variant }` (no `= value`). Construction stores only the tag;
codegen skips the payload store. Matched with a plain no-capture arm (`.quit:`); a capture on a
void variant, a `= value` on a void variant, a bare key on a non-void field, and a direct
`x.quit` payload read are all diagnosed
- **multi-pattern arms**: an arm may list several patterns (`.a, .b:` / `0, 1, 2:`); the AST
`Match_Arm` now carries a `patterns` list and the checker ORs their dispatch conditions. A
capturing multi-pattern arm over a tagged union is allowed when every listed variant has the
same payload type (Zig parity — payloads share the carrier offset, so it is one read);
mismatched payload types are a "capture group with incompatible types" error
- **range patterns**: a scalar arm may be a range (`0..10:` / `0..=10:`), desugared to
`key >= lo and key <(=) hi` (existing `.Ge`/`.Le`/`.Lt`/`.And` HIR); a range pattern on an
enum/union subject is rejected
- **pointer captures**: `|@cap|` binds a pointer into the subject's payload (mutate in place),
reusing the for-loop `@`-capture and `pointer_capture` flag; mutability follows the subject. It
requires an addressable subject — verified to need **no lowering/codegen change**: the subject
is spilled as `&subject` and captures route through a `Deref` (`lower_location(Deref)` is the
pointee address), so `Address(Field(Deref(ptr)))` aliases the original storage
- the only new codegen is the void construction skip (one `llvm` site) plus a one-line `lower`
guard so a void variant's absent payload operand is not lowered into a trapping recovery value;
everything else is parser + checker desugar
- deferred (`// ponytail:` follow-ups): contextual void construction (`e Event = .quit`) needs
enum-literal→union coercion (milestone 23); Zig `inline .a, .b => |v|` per-tag comptime
captures need monomorphization. Separately, a **call expression directly as a match subject**
(`match get()`) is a pre-existing gap (assign to a variable first, as the spec examples do);
the rvalue pointer-capture guard is defensive for when that lands
22.6. (`// ponytail:` follow-ups): contextual void construction (`e Event = .quit`) needs
enum-literal→union coercion. Separately, a **call expression directly as a match subject**
(`match get()`) is a pre-existing gap (assign to a variable first, as the spec examples do);
the rvalue pointer-capture guard is defensive for when that lands
23. error types (see below)
24. dynamic heap allocation