comptime VM arc: abi(.compiler) ABI, out as sx fn, VM-native diagnostics, BuildConfig threaded
Lands the full VM/compiler-API arc on branch reify (701/0 both gates): - abi(.compiler) ABI replaces abi(.zig) extern compiler + the fake #library "compiler"; bodiless decl = compiler-API surface, bodied = user compiler-domain fn (lowered for VM eval, emit-skipped). - out is a plain sx fn (libc write) — the out builtin deleted; the VM handles it via host-FFI. trace_resolve + interp_print_frames ported. - 4B VM-native diagnostics: 1179/1180 render proper comptime type construction failed: under strict. - S5a: build_options/set_post_link_callback on abi(.compiler) with BuildConfig threaded into the VM (green intermediate). - 0522 fixed (describe(args: []Type)); regression 0638. Strict deletion-gate down to 4 compiler_call bails (1609/1614/1615/1616) + 1654 (legitimate unresolvable-symbol diagnostic).
This commit is contained in:
@@ -499,6 +499,12 @@ pub fn detectContextDecl(decls: []const *const Node) bool {
|
||||
pub fn funcWantsImplicitCtx(self: *const Lowering, fd: *const ast.FnDecl) bool {
|
||||
if (!self.implicit_ctx_enabled) return false;
|
||||
if (fd.abi == .c) return false;
|
||||
// A BODILESS `abi(.compiler)` decl (compiler-API surface) is dispatched by name
|
||||
// to a Zig/VM handler with exactly the declared args; an implicit `__sx_ctx`
|
||||
// prepend would shift every arg (breaking the handler's arity check). No sx
|
||||
// context, like an extern import. (A BODIED `abi(.compiler)` function is a real
|
||||
// sx function the VM runs — it gets the normal implicit-ctx treatment.)
|
||||
if (fnIsBodilessCompiler(fd)) return false;
|
||||
// `extern` imports and `export` defines are external C symbols —
|
||||
// C ABI, no sx context (Phase 2, gap iv).
|
||||
if (fd.extern_export != .none) return false;
|
||||
@@ -2229,7 +2235,13 @@ pub fn declareFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8)
|
||||
// declareExtern routing below; the optional `extern LIB "csym"` lib/rename
|
||||
// axis is extern_lib/extern_name. (`export` defines take the beginFunction
|
||||
// path, not here.) The `#import c` auto-synthesis also produces this shape.
|
||||
const is_extern_decl = fd.extern_export == .extern_;
|
||||
// A bodiless `abi(.compiler)` decl (the compiler-API surface) has no runtime
|
||||
// body — the Zig/VM handler is the impl — so it lowers exactly like an `extern`
|
||||
// import (declared, never defined; the comptime evaluator dispatches it via
|
||||
// `compiler_welded`). A BODIED `abi(.compiler)` function (a compiler-domain
|
||||
// callback) is NOT extern — it has a body the VM evaluates — and is handled
|
||||
// below (`is_compiler_domain` + `is_comptime`, body lowered, emit-skipped).
|
||||
const is_extern_decl = fd.extern_export == .extern_ or fnIsBodilessCompiler(fd);
|
||||
var is_variadic = false;
|
||||
var effective_params = fd.params;
|
||||
// A lib-less C-import with a C-variadic `...` tail: drop the trailing slice
|
||||
@@ -2298,6 +2310,15 @@ pub fn declareFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8)
|
||||
func.is_variadic = is_variadic;
|
||||
func.has_implicit_ctx = wants_ctx;
|
||||
if (weldedCompilerFn(self, fd, name)) func.compiler_welded = true;
|
||||
// A BODIED `abi(.compiler)` function is a user compiler-domain function (e.g. a
|
||||
// post-link callback): the VM runs its sx body, but it NEVER runs in the binary
|
||||
// so the backend skips it (emit_llvm Pass 2). Flag `is_compiler_domain` (the
|
||||
// emit-skip) + `is_comptime` (so any compiler-API calls inside it are permitted
|
||||
// by the `emitCall` gate, and its dead LLVM decl is treated like a #run wrapper).
|
||||
if (fd.abi == .compiler and !fnIsBodilessCompiler(fd)) {
|
||||
func.is_compiler_domain = true;
|
||||
func.is_comptime = true;
|
||||
}
|
||||
// A non-generic `-> Type` builder is a comptime type constructor — only ever
|
||||
// evaluated at lowering time (`runComptimeTypeFunc`) to mint a type, never
|
||||
// called at runtime. Flag it `is_comptime` so its emitted body is dead: the
|
||||
@@ -2309,20 +2330,25 @@ pub fn declareFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8)
|
||||
self.fn_decl_fids.put(fd, fid) catch {};
|
||||
}
|
||||
|
||||
/// A `fn abi(.zig) extern <lib>` binds the comptime `compiler` library. Validate
|
||||
/// it (the bound lib must be `compiler`; the name must be on the function-export
|
||||
/// list) and return whether it is a welded compiler function — the interpreter
|
||||
/// dispatches such a call to its registered Zig handler instead of dlsym. Any
|
||||
/// failure is a build-gating `.err` (never a silent fall-through to dlsym).
|
||||
/// A BODILESS `abi(.compiler)` decl (ends in `;`, no sx body) — the compiler-API
|
||||
/// surface (`intern`/`find_type`/`build_options`/…), whose Zig/VM handler is the
|
||||
/// impl. Distinguished from a BODIED `abi(.compiler)` function (a user
|
||||
/// compiler-domain function, e.g. a post-link callback) by its synthesized
|
||||
/// empty-block body. The two lower differently: bodiless = declared-not-defined
|
||||
/// (extern-like); bodied = body lowered for VM eval but emit-skipped (S3).
|
||||
fn fnIsBodilessCompiler(fd: *const ast.FnDecl) bool {
|
||||
return fd.abi == .compiler and fd.body.data == .block and fd.body.data.block.stmts.len == 0;
|
||||
}
|
||||
|
||||
/// A bodiless `abi(.compiler)` decl is a compiler-API function: the comptime
|
||||
/// evaluator dispatches the call to its registered Zig/VM handler instead of dlsym.
|
||||
/// The ABI alone marks it (no `extern <lib>`, no fake `#library`). Validate the name
|
||||
/// is on the function-export list; failure is a build-gating `.err` (never a silent
|
||||
/// fall-through to dlsym).
|
||||
fn weldedCompilerFn(self: *Lowering, fd: *const ast.FnDecl, name: []const u8) bool {
|
||||
if (fd.abi != .zig) return false;
|
||||
const diags = self.diagnostics;
|
||||
if (fd.extern_lib == null or !std.mem.eql(u8, fd.extern_lib.?, compiler_lib.lib_name)) {
|
||||
if (diags) |d| d.addFmt(.err, fd.name_span, "abi(.zig) function '{s}' must bind the compiler library — write `extern {s}`", .{ name, compiler_lib.lib_name });
|
||||
return false;
|
||||
}
|
||||
if (!fnIsBodilessCompiler(fd)) return false;
|
||||
if (compiler_lib.findFn(name) == null) {
|
||||
if (diags) |d| d.addFmt(.err, fd.name_span, "'{s}' is not a function exported by the '{s}' library", .{ name, compiler_lib.lib_name });
|
||||
if (self.diagnostics) |d| d.addFmt(.err, fd.name_span, "'{s}' is not a function exported by the compiler", .{name});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -2570,8 +2596,11 @@ pub fn lowerFunctionBodyInto(self: *Lowering, fd: *const ast.FnDecl, fid: FuncId
|
||||
|
||||
// `extern` imports are pure declarations — never promote the stub to a real
|
||||
// function or lower the (empty placeholder) body. Mirrors the declare-only
|
||||
// handling in lowerFunction / lazyLowerFunction.
|
||||
if (fd.extern_export == .extern_) return;
|
||||
// handling in lowerFunction / lazyLowerFunction. A bodiless `abi(.compiler)`
|
||||
// decl (the compiler-API surface) is declare-only too — the Zig/VM handler is
|
||||
// the impl. A BODIED `abi(.compiler)` function DOES lower its body (for VM eval);
|
||||
// it is emit-skipped later via `is_compiler_domain`, not here.
|
||||
if (fd.extern_export == .extern_ or fnIsBodilessCompiler(fd)) return;
|
||||
|
||||
const ret_ty = self.resolveReturnType(fd);
|
||||
|
||||
@@ -2681,7 +2710,13 @@ pub fn lowerFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8, i
|
||||
|
||||
// Check if the function body is a builtin or extern declaration (no body
|
||||
// needed). `extern` imports are declare-only too (empty placeholder body).
|
||||
if (fd.body.data == .builtin_expr or fd.body.data == .compiler_expr or fd.extern_export == .extern_) {
|
||||
// A bodiless `abi(.compiler)` decl (the compiler-API surface) is likewise
|
||||
// declare-only — its Zig/VM handler is the impl. A BODIED `abi(.compiler)`
|
||||
// function DOES need its body lowered for VM eval (emit-skipped later via
|
||||
// `is_compiler_domain`), so it falls through to normal lowering below.
|
||||
if (fd.body.data == .builtin_expr or fd.body.data == .compiler_expr or
|
||||
fd.extern_export == .extern_ or fnIsBodilessCompiler(fd))
|
||||
{
|
||||
// Already declared by scanDecls/declareFunction (which handles #extern renames)
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user