lang: slice-of-protocol variadic ..xs: []P erases each arg to the protocol
packVariadicCallArgs stored the raw concrete arg into a [N x P] array when the
element type was a protocol, so an 8-byte struct landed in a 16-byte {ctx,
vtable} slot -> garbage vtable -> Bus error on dispatch. Now, when the slice
element type is a protocol, each arg is xx-erased to the protocol value via
buildProtocolErasure (same impl-driven machinery as the xx cast). This makes
..xs: []P the runtime, protocol-erased counterpart to the comptime
heterogeneous pack ..xs: P (which stays comptime-only): xs[runtime_i].method()
now works in an ordinary loop.
specs.md: full variadic/pack form-comparison table (concrete-vs-erased,
comptime-vs-runtime). Regression: examples/202. Issue 0052 (FIXED). 237 green.
This commit is contained in:
@@ -8341,6 +8341,14 @@ pub const Lowering = struct {
|
||||
|
||||
// Determine if we need to box as Any (for ..Any params) or use raw type
|
||||
const is_any = (elem_ty == .any);
|
||||
// `..xs: []P` (slice of a protocol): each concrete arg must be erased to
|
||||
// a protocol value {ctx, vtable}, not stored raw (which would be a
|
||||
// size/type mismatch — a heap of garbage vtables → crash on dispatch).
|
||||
const elem_is_protocol = blk: {
|
||||
if (elem_ty.isBuiltin()) break :blk false;
|
||||
const ei = self.module.types.get(elem_ty);
|
||||
break :blk ei == .@"struct" and ei.@"struct".is_protocol;
|
||||
};
|
||||
|
||||
// Allocate stack array [N x ElemType]
|
||||
const array_elem = if (is_any) TypeId.any else elem_ty;
|
||||
@@ -8388,6 +8396,16 @@ pub const Lowering = struct {
|
||||
if (source_ty != .any) {
|
||||
val = self.builder.boxAny(val, source_ty);
|
||||
}
|
||||
} else if (elem_is_protocol) {
|
||||
// Erase each concrete arg to the protocol value via the same
|
||||
// impl-driven `xx` machinery, so the runtime `[]P` holds real
|
||||
// {ctx, vtable} values and `xs[i].method()` dispatches.
|
||||
const arg_node = c.args[fixed_count + i];
|
||||
var source_ty = self.inferExprType(arg_node);
|
||||
if (source_ty == .unresolved) source_ty = self.builder.getRefType(val);
|
||||
if (source_ty != elem_ty) {
|
||||
val = self.buildProtocolErasure(val, arg_node, source_ty, elem_ty);
|
||||
}
|
||||
}
|
||||
const idx_ref = self.builder.constInt(@intCast(i), .s64);
|
||||
const elem_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = idx_ref } }, self.module.types.ptrTo(array_elem));
|
||||
|
||||
Reference in New Issue
Block a user