docs(metatype): comptime List growth — two-layer root cause documented
Investigated the last deferred enhancement. List(T).append at comptime fails in two independent layers (both reproduce with plain List(i64); List works via #run because that evaluates at emit time, after lowering): 1. null comptime allocator — defaultContextValue looks up the CAllocator->Allocator thunks by name, but they aren't lowered at scanDecls time. Fixable by forcing getOrCreateThunks before the interp runs in runComptimeTypeFunc (tried, works for this layer). 2. struct_get through a *T slot_ptr chain (the *List receiver) — the deep part; comptime pointer/struct/slot resolution, its own session. Speculative fixes reverted (no end-to-end win without layer 2).
This commit is contained in:
@@ -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` +
|
||||
|
||||
Reference in New Issue
Block a user