comptime VM: wire the VM at the lowering-time site + measure (P3.4)
Route runComptimeTypeFunc (the type-fn fold — the third comptime call site) through comptime_vm.tryEval behind -Dcomptime-flat/SX_COMPTIME_FLAT with legacy fallback, mirroring the two emit-time folds. Extract the shared post-check (checkComptimeTypeResult — the declared-but-never-defined zero-field guard) so the VM and legacy paths share it. Measurement (SX_COMPTIME_FLAT_TRACE): every metatype/compiler-API type-fn bails CLEANLY at "no __sx_default_context global to materialize the implicit context" — at lowering time the default-context global doesn't exist yet (it's built at emit time), so the VM bails at context materialization, before running the body (no partial mint, no crash -> legacy mints). The hardening holds: no crashes across the corpus on the lowering-time VM path. So the first lowering-time blocker is the implicit context, not Type modeling. Both gates 697/0. Near-pure fallback today — permanent scaffolding that lights up as the default-context handling + Type modeling + VM-native write side land.
This commit is contained in:
@@ -7,6 +7,8 @@ const inst_mod = @import("../inst.zig");
|
||||
const unescape = @import("../../unescape.zig");
|
||||
const parser_mod = @import("../../parser.zig");
|
||||
const interp_mod = @import("../interp.zig");
|
||||
const comptime_vm = @import("../comptime_vm.zig");
|
||||
const build_opts = @import("build_opts");
|
||||
const program_index_mod = @import("../program_index.zig");
|
||||
const resolver_mod = @import("../resolver.zig");
|
||||
const ModuleConstInfo = program_index_mod.ModuleConstInfo;
|
||||
@@ -489,6 +491,33 @@ pub fn runComptimeTypeFunc(self: *Lowering, func_id: FuncId, span: ast.Span) ?Ty
|
||||
// Clear the interp's last-bail channel so a bail HERE is attributable to
|
||||
// THIS construction (not a stale message from an earlier comptime eval).
|
||||
interp_mod.Interpreter.last_bail_detail = null;
|
||||
|
||||
// Flat-memory VM fast path (gated by `-Dcomptime-flat` / `SX_COMPTIME_FLAT`),
|
||||
// the THIRD comptime call site after the two emit-time folds. A type-fn runs
|
||||
// on the VM; `null` (any bail) falls through to the legacy interpreter below,
|
||||
// which mints identically. The VM bails BEFORE any table mutation — its
|
||||
// compiler-WRITE fns (declare_type/register_type/pointer_to) aren't ported to
|
||||
// `callCompilerFn`, and it can't yet model a `Type` result — so a minting
|
||||
// type-fn bails at the first write call (no partial mint → no double-mint).
|
||||
// The VM is hardened against malformed lowering-time IR (it BAILS, never
|
||||
// panics; see `comptime_vm.refTy`/`badRef`). Today this is near-pure fallback;
|
||||
// it lights up as `Type` modeling + the VM-native write side land.
|
||||
const comptime_flat = build_opts.comptime_flat or std.c.getenv("SX_COMPTIME_FLAT") != null;
|
||||
const vm_result: ?interp_mod.Value = if (comptime_flat)
|
||||
comptime_vm.tryEval(self.alloc, self.module, func_id)
|
||||
else
|
||||
null;
|
||||
if (comptime_flat and std.c.getenv("SX_COMPTIME_FLAT_TRACE") != null) {
|
||||
if (vm_result != null)
|
||||
std.debug.print("[comptime-vm] HANDLED type-fn\n", .{})
|
||||
else
|
||||
std.debug.print("[comptime-vm] fallback type-fn: {s}\n", .{comptime_vm.last_bail_reason orelse "<unknown>"});
|
||||
}
|
||||
if (vm_result) |v| {
|
||||
const tid_vm = v.asTypeId() orelse return null;
|
||||
return checkComptimeTypeResult(self, tid_vm, span);
|
||||
}
|
||||
|
||||
const result = interp.call(func_id, &.{}) catch |err| {
|
||||
// A comptime type construction (declare/define, reflection) that bails
|
||||
// must surface a build-gating diagnostic naming the reason — NOT poison
|
||||
@@ -506,11 +535,16 @@ pub fn runComptimeTypeFunc(self: *Lowering, func_id: FuncId, span: ast.Span) ?Ty
|
||||
return null;
|
||||
};
|
||||
const tid = result.asTypeId() orelse return null;
|
||||
// A bare `declare("X")` that is never completed by a `define(handle, …)`
|
||||
// leaves a zero-FIELD nominal slot (an undefined enum). Sizing / constructing
|
||||
// / emitting it panics at codegen (`verifySizes`: llvm_size != ir_size).
|
||||
// Reject it loudly here — a zero-variant enum is never a legitimate result
|
||||
// (`defineEnum` rejects an empty variant list too).
|
||||
return checkComptimeTypeResult(self, tid, span);
|
||||
}
|
||||
|
||||
/// Post-check a comptime type-construction result (shared by the VM and legacy
|
||||
/// paths). A bare `declare("X")` never completed by a `define(handle, …)` leaves
|
||||
/// a zero-FIELD nominal slot (an undefined enum); sizing / constructing / emitting
|
||||
/// it panics at codegen (`verifySizes`: llvm_size != ir_size). Reject it loudly
|
||||
/// here — a zero-variant enum is never a legitimate result (`defineEnum` rejects
|
||||
/// an empty variant list too). Returns the type, or null after gating the build.
|
||||
fn checkComptimeTypeResult(self: *Lowering, tid: TypeId, span: ast.Span) ?TypeId {
|
||||
if (!tid.isBuiltin()) {
|
||||
const info = self.module.types.get(tid);
|
||||
if (info == .tagged_union and info.tagged_union.fields.len == 0) {
|
||||
|
||||
Reference in New Issue
Block a user