diff --git a/current/CHECKPOINT-METATYPE.md b/current/CHECKPOINT-METATYPE.md index 32e22189..9387e546 100644 --- a/current/CHECKPOINT-METATYPE.md +++ b/current/CHECKPOINT-METATYPE.md @@ -115,12 +115,34 @@ shifts every `.ir` snapshot. On-demand import keeps the prelude clean. The reflect/construct triad is COMPLETE — `` `enum `` (`0619`), `` `struct `` (`0622`), `` `tuple `` (`0623`) all reflect AND construct + round-trip. Remaining METATYPE work is ONE deferred enhancement, a clean diagnostic rather than a crash: -- **Comptime `List` growth** — `List(EnumVariant).append` at comptime bails - ("struct_get: base has no fields"); the allocator/List protocol path isn't fully - interp-evaluable (heap alloc + protocol dispatch + List internals at comptime — - a deeper, multi-step interp effort). Probe `.sx-tmp/probe_makeenum.sx`. Doesn't - block anything: array-literal locals already work for building variant lists - (`examples/0620`/`0624`). +- **Comptime `List` growth** — `List(T).append` at comptime bails ("struct_get: + base has no fields"). Doesn't block anything: array-literal locals already build + variant lists (`examples/0620`/`0624`). Probe `.sx-tmp/probe_makeenum.sx` / + `probe_li64.sx`. **Investigated — it's TWO layers** (both reproduce with plain + `List(i64)`, not metatype-specific; List works via `#run` because that evaluates + at EMIT time, after everything is lowered, while a metatype `::` const evaluates + at `scanDecls` time): + 1. **Null comptime allocator.** `interp.zig:defaultContextValue` builds the + comptime `context.allocator` by looking up `__thunk_CAllocator_Allocator_alloc_bytes` + by name in the module's functions — but at `scanDecls` time those protocol + thunks aren't lowered yet, so `alloc_fn`/`dealloc_fn` are `.null_val` and any + comptime allocation fails. FIX (tried, works for this layer): call + `self.getOrCreateThunks("Allocator", "CAllocator")` (guarded by the same + Context/Allocator/CAllocator-registered check `emitDefaultContextGlobal` uses) + before the interp runs in `comptime.zig:runComptimeTypeFunc`. + `createProtocolThunk` saves/restores builder state, so calling it mid-lowering + is safe. After this, `alloc_fn=func_ref` — but layer 2 still bails. + 2. **`struct_get` through a `*T` slot_ptr chain.** A `*List` struct receiver + (`vs.append(…)` → `append(self: *List, …)`) lands in the interp as a slot + whose contents are a slot_ptr to the actual value — `self.field` does + `struct_get` on `base=slot_ptr field_index=1` and bails. The auto-deref in + `interp.zig:.struct_get` does a single `loadSlot`; a chain-resolve loop did + NOT fix it (the final loaded value is a field-pointer aggregate that + `resolveFieldLoad` turns back into a slot_ptr — List's comptime representation + uses field-pointers + slot_ptrs the struct_get path doesn't fully resolve). + This is the deep part: comptime pointer/struct/slot resolution for `*T` + receivers, its own focused effort. Both speculative fixes were REVERTED (no + end-to-end testable win without layer 2). The metatype surface (declare/define/type_info/field_type + make_enum) is feature-complete for the locked design; generic type-fn body locals now work too. - ~~**Validation + loud diagnostics**~~ — COMPLETE. duplicate variant names @@ -144,9 +166,11 @@ capabilities would let the variant list be built more freely; both error cleanly an array from a `{ptr,len}` slice, folded open-ended `hi` to a fixed array's static length at lower time (no runtime/.ir change), and added `interp.zig:subsliceElements`. `examples/0621` locks it. -- **Comptime `List` growth.** Building variants via `List(EnumVariant).append` at - comptime bails ("struct_get: base has no fields") — the allocator/List protocol - path isn't fully interp-evaluable. Probe `.sx-tmp/probe_makeenum.sx`. +- **Comptime `List` growth.** `List(T).append` at comptime bails ("struct_get: + base has no fields"). Investigated — two layers (null comptime allocator at + scanDecls + `struct_get` through a `*T` slot_ptr chain); see the detailed writeup + under "Next step". Layer 1 has a known fix; layer 2 is deep. Probe + `.sx-tmp/probe_makeenum.sx`. - ~~Generic type-fn body locals~~ — DONE. A generic `($T) -> Type` now comptime-evaluates its FULL body (prelude statements + return), so a local before the return resolves. `createComptimeFunctionWithPrelude` +