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:
agra
2026-06-19 07:04:10 +03:00
parent fdc4ee2331
commit 2060373c16
80 changed files with 12684 additions and 11922 deletions

View File

@@ -1119,13 +1119,23 @@ pub const Ops = struct {
// wrapper, `is_comptime`) is fine — that body is interp-evaluated and its
// LLVM emission is dead, so skip the gate there.
const enclosing = &self.e.ir_mod.functions.items[self.e.current_func_idx];
if (callee_func.compiler_welded and !enclosing.is_comptime) {
if ((callee_func.compiler_welded or callee_func.is_compiler_domain) and !enclosing.is_comptime) {
const fname = self.e.ir_mod.types.getString(callee_func.name);
std.debug.print("error: '{s}' is a comptime-only compiler-library function — it cannot be called at runtime (use it inside #run or a comptime '::')\n", .{fname});
std.debug.print("error: '{s}' is a comptime-only compiler-domain function — it cannot be called at runtime (use it inside #run or a comptime '::')\n", .{fname});
self.e.comptime_failed = true;
self.e.mapRef(c.LLVMGetUndef(self.e.toLLVMType(instruction.ty)));
return;
}
// A comptime-only callee (compiler-API or compiler-domain) reached here from
// a COMPTIME (dead) body — the enclosing `#run`/`::` wrapper whose LLVM is
// never executed. Such a function has no runtime symbol, so emit `undef`
// instead of a real `call` (which would leave an undefined reference for the
// AOT linker). The comptime VALUE is produced by the interp/VM, not this dead
// body. Mirrors the old `compiler_call` → undef.
if (callee_func.compiler_welded or callee_func.is_compiler_domain) {
self.e.mapRef(c.LLVMGetUndef(self.e.toLLVMType(instruction.ty)));
return;
}
if (callee_func.is_comptime and call_op.args.len == 0) {
var interp_inst = Interpreter.init(self.e.ir_mod, self.e.alloc);
@@ -1377,25 +1387,6 @@ pub const Ops = struct {
self.e.mapRef(c.LLVMBuildCall2(self.e.builder, self.e.getMathF64Type(), f, &args, 1, @tagName(bi.builtin)));
}
},
.out => {
// out(str): extract ptr and len from string fat pointer, call write(1, ptr, len)
const str_val = self.e.resolveRef(bi.args[0]);
const raw_ptr = c.LLVMBuildExtractValue(self.e.builder, str_val, 0, "str.ptr");
const str_len = c.LLVMBuildExtractValue(self.e.builder, str_val, 1, "str.len");
// On wasm32, count param is i32 (size_t)
const count = if (self.e.target_config.isWasm32())
c.LLVMBuildTrunc(self.e.builder, str_len, self.e.cached_i32, "len.tr")
else
str_len;
const write_fn = self.e.getOrDeclareWrite();
var write_args = [_]c.LLVMValueRef{
c.LLVMConstInt(self.e.cached_i32, 1, 0), // fd = stdout
raw_ptr,
count,
};
_ = c.LLVMBuildCall2(self.e.builder, self.e.getWriteType(), write_fn, &write_args, 3, "");
self.e.advanceRefCounter();
},
.type_name => {
// Dynamic `type_name(t)` at runtime: resolve the TypeId
// the arg denotes (reading an `Any`'s runtime type-tag,