ffi M5.A.next.2b.fu34.B: pack-mono materialises []Any slice for bare args
Fixes follow-ups #3 (bare `args` reference) and #4 (`args[<runtime_int>]`) from step 2b. The pack-mono now materialises an `[]Any` slice value for the pack name at body entry: each pack-param slot is loaded, boxed via `boxAny`, and stored into a stack [N x Any] array; the slice {data_ptr, len} binds to the pack name in scope. Plumbing in src/ir/lower.zig: - `materialisePackSlice(scope, pack_name, slot_refs, arg_types)` — new helper that emits the array alloca + box+store loop + slice alloca + bind. Empty-pack case (N == 0) emits {null, 0} directly. - `monomorphizePackFn` captures the pack-param slot Refs as they bind, then calls `materialisePackSlice` after binding so the slice load can pull each param value. After: `args` (bare) resolves as `[]Any` and forwards to slice-typed helpers; `args[<runtime_int>]` lowers through the standard slice-indexing path, element type `Any`. Per-position type info is lost via Any boxing — that is the inherent cost of treating a heterogeneous pack as a uniform value. Literal- indexed access still routes through `packArgNodeAt` and keeps the concrete per-position types. `examples/162-pack-bare-args.sx` flips from "unresolved 'args'" to `3` (forwarded to `log_count(items: []Any)` which returns `items.len`). `examples/163-pack-runtime-index.sx` flips from the LLVM verifier crash to `4` (while-loop over `args.len`, indexing each `args[i]` runtime). 202/202 example tests + `zig build test` green.
This commit is contained in:
@@ -8103,6 +8103,58 @@ pub const Lowering = struct {
|
||||
return self.builder.constInt(0, .void);
|
||||
}
|
||||
|
||||
/// Build an `[]Any` slice value from the mono's pack params and
|
||||
/// bind it to the pack name in scope. Each pack-param slot is
|
||||
/// loaded, boxed via `boxAny`, and stored into a stack [N x Any]
|
||||
/// array; the slice {data_ptr, len} is then bound. Used by
|
||||
/// `monomorphizePackFn` so bodies that reference `args` bare or
|
||||
/// index it with a runtime int resolve through the slice (with
|
||||
/// element type `Any`). Literal-indexed accesses keep the
|
||||
/// concrete per-position types via `packArgNodeAt`.
|
||||
fn materialisePackSlice(
|
||||
self: *Lowering,
|
||||
scope: *Scope,
|
||||
pack_name: []const u8,
|
||||
slot_refs: []const Ref,
|
||||
arg_types: []const TypeId,
|
||||
) void {
|
||||
const any_slice_ty = self.module.types.sliceOf(.any);
|
||||
const any_ptr_ty = self.module.types.ptrTo(.any);
|
||||
|
||||
if (arg_types.len == 0) {
|
||||
const null_ptr = self.builder.constNull(any_ptr_ty);
|
||||
const zero_len = self.builder.constInt(0, .s64);
|
||||
const slice_slot = self.builder.alloca(any_slice_ty);
|
||||
const ptr_gep = self.builder.structGepTyped(slice_slot, 0, any_ptr_ty, any_slice_ty);
|
||||
self.builder.store(ptr_gep, null_ptr);
|
||||
const len_gep = self.builder.structGepTyped(slice_slot, 1, .s64, any_slice_ty);
|
||||
self.builder.store(len_gep, zero_len);
|
||||
scope.put(pack_name, .{ .ref = slice_slot, .ty = any_slice_ty, .is_alloca = true });
|
||||
return;
|
||||
}
|
||||
|
||||
const array_ty = self.module.types.arrayOf(.any, @intCast(arg_types.len));
|
||||
const array_slot = self.builder.alloca(array_ty);
|
||||
|
||||
for (slot_refs, arg_types, 0..) |slot, ty, i| {
|
||||
const val = self.builder.load(slot, ty);
|
||||
const boxed = if (ty == .any) val else self.builder.boxAny(val, ty);
|
||||
const idx_ref = self.builder.constInt(@intCast(i), .s64);
|
||||
const elem_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = idx_ref } }, any_ptr_ty);
|
||||
self.builder.store(elem_ptr, boxed);
|
||||
}
|
||||
|
||||
const slice_slot = self.builder.alloca(any_slice_ty);
|
||||
const zero = self.builder.constInt(0, .s64);
|
||||
const data_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = zero } }, any_ptr_ty);
|
||||
const len_ref = self.builder.constInt(@intCast(arg_types.len), .s64);
|
||||
const ptr_gep = self.builder.structGepTyped(slice_slot, 0, any_ptr_ty, any_slice_ty);
|
||||
self.builder.store(ptr_gep, data_ptr);
|
||||
const len_gep = self.builder.structGepTyped(slice_slot, 1, .s64, any_slice_ty);
|
||||
self.builder.store(len_gep, len_ref);
|
||||
scope.put(pack_name, .{ .ref = slice_slot, .ty = any_slice_ty, .is_alloca = true });
|
||||
}
|
||||
|
||||
/// Infer the return type of a pack-fn body for the generic-`$R`
|
||||
/// case. Walks the body looking for the first concrete return
|
||||
/// type: a `return X;` statement's value type, or — failing that —
|
||||
@@ -8329,17 +8381,29 @@ pub const Lowering = struct {
|
||||
scope.put(p.name, .{ .ref = slot, .ty = pty, .is_alloca = true });
|
||||
param_idx += 1;
|
||||
}
|
||||
var pack_param_slots = std.ArrayList(Ref).empty;
|
||||
defer pack_param_slots.deinit(self.alloc);
|
||||
for (arg_types, 0..) |ty, i| {
|
||||
const synth_name = pack_synth_names.items[i];
|
||||
const slot = self.builder.alloca(ty);
|
||||
self.builder.store(slot, Ref.fromIndex(param_idx));
|
||||
scope.put(synth_name, .{ .ref = slot, .ty = ty, .is_alloca = true });
|
||||
pack_param_slots.append(self.alloc, slot) catch return;
|
||||
param_idx += 1;
|
||||
}
|
||||
|
||||
// Pack bindings remain installed from the pre-resolution
|
||||
// (generic-`$R`) inference step above. No need to reinstall.
|
||||
|
||||
// Materialise an `[]Any` slice value for the pack name so
|
||||
// bare `args` (forwarding) and `args[<runtime_int>]` (loops)
|
||||
// resolve at runtime. Per-position type info is lost via
|
||||
// Any boxing — that's the inherent cost of treating a
|
||||
// heterogeneous pack as a uniform value. Literal-indexed
|
||||
// access still goes through `packArgNodeAt` and keeps the
|
||||
// concrete per-position types.
|
||||
self.materialisePackSlice(&scope, pack_name, pack_param_slots.items, arg_types);
|
||||
|
||||
if (ret_ty != .void) {
|
||||
const body_val = self.lowerBlockValue(fd.body);
|
||||
if (!self.currentBlockHasTerminator()) {
|
||||
|
||||
@@ -1 +1 @@
|
||||
1
|
||||
0
|
||||
|
||||
@@ -1 +1 @@
|
||||
/Users/agra/projects/sx/examples/162-pack-bare-args.sx:23:22: error: unresolved 'args' (in /Users/agra/projects/sx/examples/162-pack-bare-args.sx fn forward__pack_s64_string_f64)
|
||||
3
|
||||
|
||||
@@ -1 +1 @@
|
||||
1
|
||||
0
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
LLVM verification failed: GEP base pointer is not a vector or a vector of pointers
|
||||
%ig.ptr = getelementptr i64, i64 %ig.data, %load7
|
||||
Load operand must be a pointer.
|
||||
%ig.val = load i64, i64 %ig.ptr, align 8
|
||||
|
||||
4
|
||||
|
||||
Reference in New Issue
Block a user