comptime VM: real lowering-time Context — allocating + List-building type-fns run on the VM (issue 0141)
The VM can now evaluate a comptime type-fn that allocates at lowering time (the 0141 family) — the legacy interp cannot. Four changes: - runComptimeTypeFunc (lower/comptime.zig): force the CAllocator->Allocator thunks to exist (getOrCreateThunks, idempotent, guarded) BEFORE eval. A type-fn const runs at scanDecls (Pass 1), before Pass 1c builds the default-context global + thunks, so the comptime allocator was otherwise null. - materializeDefaultContext: build a REAL context at lowering time when the global is absent — find the two thunks by name and lay their func-refs into the inline Allocator value at the head of Context, so context.allocator.alloc_bytes dispatches call_indirect -> thunk -> native VM malloc. - aggType: deref a pointer base_type (the List write path emits struct_gep with base_type = *Struct; fieldOffset panicked on the pointer — now derefs, no panic). - subslice: handle a [*]T many-pointer / *T base (a List's items field — the base IS the data pointer). Verified end-to-end (manual probe): a compiler-API type-fn building its []Member in a List(Member) runs HANDLED on the VM and mints (green=7) — the 0141 List-growth pattern. Can't be a corpus test yet (gate-OFF/legacy can't allocate at lowering time — the dual-path bind), so locked in via VM unit tests (many-pointer subslice; struct_gep with a pointer base_type). 697/0 both gates + all unit tests.
This commit is contained in:
@@ -488,6 +488,24 @@ fn preludeBeforeReturn(body: *const Node) []const *const Node {
|
||||
/// `declare()` never completed by `define()` (a zero-field nominal slot that
|
||||
/// would otherwise panic at codegen). `span` locates both diagnostics.
|
||||
pub fn runComptimeTypeFunc(self: *Lowering, func_id: FuncId, span: ast.Span) ?TypeId {
|
||||
// Force the CAllocator→Allocator thunks to exist BEFORE the type-fn evaluates.
|
||||
// A type-fn const runs at scanDecls time (Pass 1), BEFORE `emitDefaultContextGlobal`
|
||||
// (Pass 1c) builds the default context + those thunks — so the comptime
|
||||
// `context.allocator` is otherwise null and any allocation bails (issue 0141).
|
||||
// `getOrCreateThunks` is idempotent (cached in `protocol_thunk_map`), so the
|
||||
// later Pass-1c call reuses these. Guarded exactly like `emitDefaultContextGlobal`
|
||||
// (skip when the std allocator types aren't registered). This lets the
|
||||
// flat-memory VM materialize a REAL lowering-time context (the func-refs are
|
||||
// dispatchable on the VM via `call_indirect` → thunk → native malloc).
|
||||
{
|
||||
const tbl = &self.module.types;
|
||||
if (tbl.findByName(tbl.internString("Allocator")) != null and
|
||||
tbl.findByName(tbl.internString("CAllocator")) != null)
|
||||
{
|
||||
_ = self.getOrCreateThunks("Allocator", "CAllocator");
|
||||
}
|
||||
}
|
||||
|
||||
var interp = interp_mod.Interpreter.init(self.module, self.alloc);
|
||||
defer interp.deinit();
|
||||
if (self.diagnostics) |d| if (d.import_sources) |sm| interp.setSourceMap(sm);
|
||||
|
||||
Reference in New Issue
Block a user