**FIXED** (`1f6e27d`, `examples/212`). Two root causes:
1. `instantiateGenericStruct` now binds the template name to the concrete
   instance (`tb.put(tmpl.name, id)`), so an impl method `self: *Combined`
   resolves `self.field` to the instance, not the 0-field generic stub. (This
   was a general pre-existing bug — `self.x` failed on *any* generic-struct
   impl method.)
2. `createProtocolThunk` monomorphizes the template method for a generic-struct
   instance (`Combined.get` → `Combined__i64_i64.get` with the instance
   bindings), so the erasure vtable dispatches instead of an `unreachable` thunk.

`xx c` (Combined → VL($R)) now dispatches correctly. The *full* canonical `map`
additionally needs mapper closure-pack typing + `$R` inference at the call site
(a separate piece) — tracked separately.

# Symptom

`xx c` where `c` is a generic-struct instance and the target is a parameterized
protocol — via a generic `impl P($R) for Combined($R, ..$Ts)` — **compiles
cleanly but traps at runtime** (exit 133) when a method is then called on the
erased value. The protocol value is built with a wrong/empty vtable, so the
dispatch jumps to a bad fn-ptr.

This is the last piece of the canonical `map` (`return xx c;`).

# Reproduction

```sx
#import "modules/std.sx";
VL :: protocol(T: Type) { get :: () -> T; }
IntCell :: struct { v: i64; }
impl VL(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
Combined :: struct($R: Type, ..$Ts: []Type) { sources: (..VL(Ts)); value: $R; }
impl VL($R) for Combined($R, ..$Ts) { get :: (self: *Combined) -> $R => self.value; }

make :: (..sources: VL) -> VL(i64) {
    c : Combined(i64, ..sources.T) = ---;
    c.value = 99;
    c.sources = (..sources);
    return xx c;                 // Combined__i64_i64 -> VL(i64)
}
main :: () -> i32 {
    r := make(IntCell.{ v = 1 });
    print("{}\n", r.get());      // expect 99; instead traps
    0;
}
```

`sx ir` produces clean, verifier-passing IR (no "no visible xx conversion"
diagnostic — so an impl *was* matched), but the JIT traps on `r.get()`.

# Root cause (suspected)

`param_impl_map` is keyed by **concrete** `(protocol, target_args_mangled,
source_mangled)`. The impl `impl VL($R) for Combined($R, ..$Ts)` is generic on
both sides — its source mangles to a generic `Combined` (with `$R`/`$Ts`), not
the concrete `Combined__i64_i64`. Erasing `Combined__i64_i64 → VL(i64)` looks up
`(VL, i64, Combined__i64_i64)`, which doesn't key-match the generic impl; some
looser path still produces a protocol value, but its vtable slot for `get`
isn't bound to the monomorphized `Combined__i64_i64.get` (which returns
`self.value` as `$R`=i64). Calling through it traps.

The fix needs generic-impl matching + per-instance monomorphization for protocol
erasure: when erasing a concrete generic-struct instance to a parameterized
protocol, find the generic impl whose source template matches the instance's
template (binding `$R`/`$Ts` from the instance's recorded bindings —
`struct_instance_bindings`), monomorphize the impl methods for those bindings,
and fill the vtable with the resulting fn-ptrs. Compare:
- `buildProtocolValue` / `buildProtocolErasure` ([src/ir/lower.zig](../src/ir/lower.zig))
  — the vtable construction + impl-method lookup.
- `param_impl_map` keying (`Proto\x00<args>\x00<src_mangled>`) and how a generic
  source template is (or isn't) matched against a concrete instance.
- `instantiateParamProtocol` (the dst side already works) and
  `instantiateGenericStruct`'s `struct_instance_bindings` (the source bindings).

# Verification

The reproduction should print `99`. Plain (non-generic) struct → parameterized
protocol erasure already works (`examples/206`: `xx IntCell -> VL(i64)`); the gap
is specifically a *generic-struct* source matched via a *generic* impl.

# Status

Everything else in the canonical `map` works: `Combined($R, ..sources.T)`
instantiation (`examples/209`), `c.sources = (..sources)` materialization with
per-element erasure (`examples/210`), and `mapper(..sources.value)` projection +
spread (`examples/211`). This erasure is the final blocker.
