Next Session — WASM Backend + Remaining Spec Failures
Baseline: b984ab71 (post impl recursion fix, trunk)
Session shape: WASM backend is multi-session. Remaining spec failures are quick individual fixes.
Tree state: Clean, guard stamp valid, fixpoint 1991 functions.
What this session accomplished (Apr 16, 2026)
10 commits. Major fixes:
- SEND-RECV-SHADOW — deleted dead
extern "C" send/recvfromstd/ffi/socket.qz. Unblocked 6+ specs. - generic_ufcs_dispatch_spec — not a compiler bug, fixed test string concat (triple-quote newline).
- Collection stubs — added
reversed()andsorted()to prelude. 21/21 green. - Async $poll extern collision —
cg_extern_var_index$-strip matched__Future_*$poll→ libcpoll(). Fixed by skipping__-prefixed names. .sizewart — typechecker auto-rewrites.sizeon Int-typed values tovec_size().- impl Option/Result infinite recursion — method bodies delegated to same-named free functions, causing infinite recursion. Inlined the match logic.
- ROADMAP cleanup — 10+ stale entries verified green on retest.
Impact: ~100+ tests unblocked across result_helpers, csv, option_result, concurrency, collection stubs, pattern matching, and more.
Item 1: WASM Backend (multi-session)
Current state
wasm_encode.qz(14K) — LEB128, opcodes, section encoding. Works.wasm_encode_spec15/15 green.codegen_wasm.qz(82K) — Main WASM backend.wasm_runtime.qz(300K) — WASM runtime synthesis.- Feature-gated behind
@cfg(feature: "wasm"). Current compiler binary doesn’t include it. - Building with
--feature wasmrequires ~30 GB RSS and 15+ minutes. wasmtimeis installed at/opt/homebrew/bin/wasmtime.
To test the WASM backend
# 1. Build compiler with WASM feature (30 GB RSS, 15+ min)
./self-hosted/bin/quartz --feature wasm \
-I self-hosted/frontend -I self-hosted/middle -I self-hosted/backend \
-I self-hosted/shared -I std -I tools --no-cache self-hosted/quartz.qz \
> /tmp/quartz_wasm.ll
# 2. Build the WASM-enabled binary
PATH="/opt/homebrew/opt/llvm/bin:$PATH"
llc -filetype=obj /tmp/quartz_wasm.ll -o /tmp/quartz_wasm.o
clang /tmp/quartz_wasm.o -o /tmp/quartz_wasm -lm -lpthread
# 3. Use it to compile a test to WASM
/tmp/quartz_wasm --backend wasm --no-cache test.qz -o test.wasm
wasmtime test.wasm
WASM specs
wasm_encode_spec— 15/15 green (encoding layer)wasm_core_spec— 27 tests (exit codes, variables, functions, control flow, recursion, stdout)wasm_data_spec— closures, bitwise, string/vec opswasm_extended_spec— char predicates, str_trim, str_repeat, str_cmp
All core/data/extended specs require the WASM-enabled binary.
Architecture reference
Memory file: project_wasm_direct_backend.md. 10-phase plan at .claude/plans/indexed-enchanting-dusk.md.
Item 2: Remaining Spec Failures
Known failures after this session
| Spec | Issue | Priority |
|---|---|---|
json_spec | SIGSEGV (exit 139) — runtime crash in JSON parser | P1 |
semaphore_spec | Timeout — scheduler-based test hangs in PTY | P2 (test infra) |
http2_frame_spec | Link error — missing library | P2 |
separate_compilation_spec | 5/6 FAIL:link — separate compilation linker gaps | P2 |
impl_trait_spec | Needs -I spec/qspec/fixtures | P3 (test infra) |
Specs that need QUARTZ_COMPILER / QUARTZ_FIXTURES
All subprocess-based specs require:
QUARTZ_COMPILER="$(pwd)/self-hosted/bin/quartz"QUARTZ_FIXTURES="$(pwd)/spec/qspec/fixtures"(for specs importing fixtures)
impl recursion pattern — more instances?
The impl Option/impl Result recursion bug (method def foo() = foo(self) where foo shadows the free function) may exist in other impl blocks. Grep for return.*\(self\) inside impl blocks to audit.
Item 3: Other observations
Triple-quoted string newline behavior
Quartz triple-quoted strings strip trailing newlines. Any helper() + """...""" concatenation needs explicit "\n" between to avoid enddef-style concatenation. This bit generic_ufcs_dispatch_spec.
cg_extern_var_index $-stripping
The fallback at codegen_util.qz:426-440 strips module prefixes via last-$ lookup. Now guarded against __-prefixed names, but could still match user module names containing extern function names (e.g. my_module$send → matches libc send). A more robust fix would be to track extern names in a separate namespace.
Memory stats on stdout
The [mem] debug output goes to stderr (via eputs), not stdout. IR output is clean. When testing, use 2>/dev/null to suppress, or grep -v '^\[mem\]' if mixing stderr into stdout.