vilan 0.11.0
Hot module replacement — the dev loop closes. vilan run --watch on a full-stack workspace now hot-reloads the browser: save a file and the app updates in place with module-level state carried across the swap (plain values by value, Signal/Shared by payload into fresh cells — keyed and fingerprinted by the compiler, so a changed shape fresh-inits instead of adopting stale data), while the server leg restarts behind the scenes and the client's rpc mirrors resync on their own. A CSS-only edit hot-swaps the stylesheet without a reload; a compile error shows an in-page overlay carrying the actual compiler diagnostics (file, line, message, note — the terminal's own rendering) and clears on the next good save; std::dev gives app code on_teardown and a type-checked stash/take carryover (only plain data may cross a swap — the compiler enforces what Vite leaves to convention). Watch rounds got structurally cheaper too: parse results are content-cached across rounds and a leg whose sources re-hash identically is skipped outright, its artifacts reused byte-for-byte. Multi-server workspaces pick their entry with vilan run --entry <name>. The dev-loop guide walks the whole loop.
The frontend is handwritten now — builds are ~2.7× faster. The chumsky combinator frontend is gone, replaced by a hand-rolled lexer and recursive-descent parser proven byte-identical first (279/279 whole-file tree agreement, every corpus program compiled to identical output through the new code before it was wired in) and then measured: a release build of the todo client dropped from ~0.49 s to 0.18 s, instruction counts fell 5.21 B → 2.01 B, and the frontend went from ~63% of a compile to under 4% — the debug binary gains the most. Parse errors improved with it: the 30-token "expected one of …" dumps are gone, a missing separator reports found 'y' expected ',' or '}' at the offending token, the a!==b spacing trap gets a first-class hint, and a syntax error no longer discards the whole file — the parsed prefix survives, so the language server keeps working on everything above the typo.
Trait impls must now match their trait's signatures. Previously an impl satisfied a trait by member name alone; receiver convention, parameter types, arity, and return type were never compared, so a wrong fun drop(self) compiled against fun drop(&mut self). Every member is now checked under the trait's own generics (Self included), with the mismatch spelled per dimension. This can reject code that previously compiled — the fix is to make the impl say what the trait says. (A deliberate leniency: an async impl of a sync-declared method stays legal — dispatch is monomorphized, so the caller always knows the concrete callee.)
Two real bugs died. A module-level closure referenced only by calls (let helper = || …; used as helper()) was tree-shaken out of the bundle while its call sites remained — a runtime ReferenceError; calls now count as references, and six sibling shapes (calls through ?./!, transitive closure chains, nested modules) were quietly broken the same way and are fixed with it. And a typo'd name in value position no longer cascades — one unknown identifier is one error, not a fan of Expected i32, but got void noise at every use.
vilan fmt formats everything. The formatter silently returned files unchanged when they used newer constructs — destructuring, fixed arrays, ?. chains, the macro forms, numeric suffixes. Every construct now has its printer, guarded by a standing zero-bail gate over the whole corpus, and two latent printer bugs found on the way (one would have reformatted -(2 + 3) into -2 + 3) are fixed. The standard library itself is freshly vilan fmt-formatted.
Sharper diagnostics across the board. Notes that pointed into std for user-caused conditions were audited (they are all genuinely declaration notes — "the trait declares it here" — and stay); one unresolved name suppresses its whole echo family; and the diagnostics ledger now runs as a living gate — every new compiler error message gets verdicted against the standard as it lands, not in batches after the fact.