codegen: lower match to scrutinee-save + chained i64.eq + nested if (closes #43)#61
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #43.
Cleave-compiled WASM modules can pattern match now. The v0.3 codegen rejected
matchwith the diagnostic "statement kind StmtMatch not yet supported in v0 codegen"; this PR lifts that. Builds directly on the if/else lowering from #49.What landed
Codegen
emit_matchsaves the scrutinee to a shared scratch local, then walks arms recursively. Each non-wildcard arm becomeslocal.get scratch; <pattern>; i64.eq; if 0x40 ... else ... end. Wildcard arms (any identifier in pattern position; v0 treats_and bound names alike) terminate the chain as the innermost else branch.Ok(x),Some(x)) need sum types (Sum types end-to-end: Result, Option, user-declared enums #48); binding patterns need typecheck integration (deferred).matchstatement and allocates one shared anonymous local for the scrutinee. Matches are sequential within a fn, so one scratch covers all of them.count_local_slotshelper replacescount_let_bindings; reports both let count and match presence.emit_fn_bodytranslates that into a single locals declaration group.leaves_value_on_stackextended to recurse into block result, so a match arm body that's a block ending in an assignment correctly skips the post-arm drop.Tests (5 new, byte-level)
local.get 0; local.set 1; local.get 1; i64.const N; i64.eq; if 0x40)if 0x40substrings for 3 arms with wildcard)call 1; end; endsubstring)ifbyte (just the unconditional body)Bench
codegen_match_heavyexercises 6 literal arms + wildcard. ~226K ops/sec on M3 Pro, the heaviest of the codegen benches.End-to-end demo
Compiles cleanly,
wasm-validate-clean, runs correctly:Disassembly shows exactly the lowering described:
What this PR does NOT yet do
match opt { Some(x) => use(x), None => default() }): identifier patterns are wildcards today. Real binding needs:All three are gated on sum types (Sum types end-to-end: Result, Option, user-declared enums #48), which is gated on the memory model RFC (RFC: memory model for Cleave (ownership, GC, escape hatches) #42).
Ok(x),Cons(head, tail)): same blocker.1 if x > 0 => ...): not in the parser.What unblocks next