// `List(Protocol)` appended from inside a helper function, dispatched
// repeatedly from `main` after the helper returns. Exercises the heap-copy
// path for both implicit-erasure-on-append and pre-erased protocol values.

#import "modules/std.sx";

Sizable :: protocol {
    size :: () -> i64;
}

Leaf :: struct { value: i64; }
impl Sizable for Leaf {
    size :: (self: *Leaf) -> i64 { self.value }
}

add :: (items: *List(Sizable), w: Leaf) {
    p := w;
    items.append(p);  // protocol value created from stack local `p`
}

main :: () -> void {
    // Works: protocol value created in main, appended to list
    out("=== Created in main ===\n");
    list_a : List(Sizable) = .{};
    s : Sizable = Leaf.{ value = 42 };
    list_a.append(s);
    r1 := list_a.items[0].size();
    print("first:  {} (expected 42)\n", r1);
    r2 := list_a.items[0].size();
    print("second: {} (expected 42)\n", r2);

    // BUG: protocol value created in add(), first dispatch works, second crashes
    out("=== Created in add() ===\n");
    list_b : List(Sizable) = .{};
    add(@list_b, Leaf.{ value = 99 });
    r3 := list_b.items[0].size();
    print("first:  {} (expected 99)\n", r3);   // works (stack not yet clobbered)
    r4 := list_b.items[0].size();
    print("second: {} (expected 99)\n", r4);   // CRASH: stack memory reused

    out("=== OK ===\n");
}
