// Comptime VALUE params bind on methods of GENERIC structs. // // A free function's `$o: Ord` comptime value param binds via // lowerComptimeCall → bindComptimeValueParams (see 0627 / 0640). The // generic-struct-instance method path (`b.pick(.b)`) takes a different // dispatch route: the struct monomorphizes for `T`, but the method's `$o` // must STILL bind by inlining the body — a plain call to the monomorphized // FuncId would leave `o` unresolved. This locks the composition: `T` is bound // from the struct instantiation, `$o` from the comptime value arg, and a // `self.field` read through the pointer receiver works inside the inlined body. // // Regression: composition gap — comptime value params on generic-struct methods. #import "modules/std.sx"; Ord :: enum { a; b; c; } Box :: struct ($T: Type) { value: i64; // Enum comptime value param: `if o == .x` lowers as a tag comparison; the // receiver `self` is bound so `self.value` reads correctly. pick :: (self: *Box(T), $o: Ord) -> i64 { if o == .a { return self.value + 1; } if o == .b { return self.value + 2; } return self.value + 3; } // The bound tag is also readable in a TYPE position ([o]i64), via // comptimeIntNamed — the same accessor the atomics stream uses for // `Atomic($T).load($o)`. size_for :: (self: *Box(T), $o: Ord) -> i64 { arr : [o]i64 = ---; return arr.len; } } Shape :: enum { circle: f64; point; } Drawer :: struct ($T: Type) { // Tagged-union comptime value param on a generic-struct method. area :: (self: *Drawer(T), $s: Shape) -> i64 { if s == .circle { return 1; } return 0; } } main :: () { b := Box(i64).{ value = 10 }; print("{}\n", b.pick(.a)); // 11 print("{}\n", b.pick(.b)); // 12 print("{}\n", b.pick(.c)); // 13 print("{}\n", b.size_for(.a)); // tag 0 → [0]i64 → 0 print("{}\n", b.size_for(.b)); // tag 1 → [1]i64 → 1 print("{}\n", b.size_for(.c)); // tag 2 → [2]i64 → 2 d := Drawer(i64).{}; print("{}\n", d.area(.circle(2.0))); // 1 print("{}\n", d.area(.point)); // 0 }