// Phase 6 — `c.sources = (..sources)`: materialize a pack into a
// protocol-typed tuple field, erasing each concrete pack element to the field's
// protocol slot. The pack `..sources: VL` holds concrete cells; `(..sources)`
// into a `(..VL(Ts))` field `xx`-erases each to its `VL(Ti)` value.

#import "modules/std.sx";

VL :: protocol(T: Type) { get :: () -> T; }
IntCell :: struct { v: i64; }
StrCell :: struct { s: string; }
impl VL(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
impl VL(string) for StrCell { get :: (self: *StrCell) -> string => self.s; }

Combined :: struct($R: Type, ..$Ts: []Type) {
    sources: (..VL(Ts));
    value:   $R;
}

build :: (..sources: VL) -> void {
    c : Combined(i64, ..sources.T) = ---;
    c.sources = (..sources);                          // pack → tuple, per-element erase
    print("{} {}\n", c.sources.0.get(), c.sources.1.get());
}

main :: () -> i32 {
    build(IntCell.{ v = 10 }, StrCell.{ s = "hi" });   // 10 hi
    0
}
