Bug Fixes
- **Auto-reactive
Text(\...${state.value}...`)in HIR lowering (#104)** — the docs atstate.mdpromised template literals containingstate.valuereads would bind reactively, but no backend emitted the binding;count.set(...)fired subscribers, nothing had ever subscribed. Fixed incrates/perry-hir/src/lower.rsby desugaringText(Tpl-with-state)into an IIFE closure that creates the widget, registersstateOnChangeper distinct state (each capturing the widget handle and re-rendering viatextSetString), and returns the handle. The outer IIFE is required becausecollect_module_let_idsonly tracksStmt::Let; bareLocalSet/LocalGetinsideExpr::Sequenceat module top level had no backing WASM global or local and returnedTAG_UNDEFINED`, silently dropping the widget. - Wasm codegen
collect_strings_in_exprtraversesExpr::Sequence— was aUpdate | Sequence(_) => {}catch-all. Nested bridge-function names (perry_ui_text_create,perry_ui_state_on_change,perry_ui_text_set_string) and string literals ("Count: ") were dropped from the WASM string table, so the memcalls resolved to the empty name slot. - Wasm
map_ui_methodaccepts"stateOnChange"— previously only"onChange"/"state_on_change"; the LLVM-side camelCase naming didn't round-trip to wasm.
Verification
- Web/wasm: jsdom click-through —
Text(\Count: ${count.value}`)` → 3 × Increment → "Count: 3". - Multi-state:
test_ui_state_binding.ts(4 different template forms sharing onecountstate) all update together through +1 and -1 clicks. - macOS native: AppleScript driving AppKit window confirms reactive updates.
- iOS/tvOS/watchOS/Android/GTK4/Windows: statically audited — identical FFI signatures (
perry_ui_state_on_change(i64, f64),perry_ui_text_set_string(i64, i64)), real (non-stub) bodies, samejs_closure_call1extern-C ABI. Not exercised on hardware.