diff --git a/current/CHECKPOINT-COMPILER-API.md b/current/CHECKPOINT-COMPILER-API.md index 5196c39e..a42bd292 100644 --- a/current/CHECKPOINT-COMPILER-API.md +++ b/current/CHECKPOINT-COMPILER-API.md @@ -431,6 +431,23 @@ when reached (sentinels or accessor fns; see the design doc Risks). `List` growth; orthogonal, see `current/CHECKPOINT-METATYPE.md`.) ## Log +- **P5.7 Step B — deleted the `#compiler`/`compiler_call`/hook-Registry mechanism end-to-end (2026-06-19).** + All superseded by `abi(.compiler)` VM-native dispatch (P5.5) — no sx code emits any of it. Two green commits: + **B1** (`e2971f2`) removed the `compiler_call` IR op: the op variant + `CompilerCall` struct (`inst.zig`), the + `Builder.compilerCall` emitter (`module.zig`), the two dead producer blocks in `lower/call.zig` (the + `compiler_expr`-bodied free-fn + method dispatch), every consumer arm (`emit_llvm`, `ops.emitCompilerCall`, + `print`, the `interp.zig` hook-dispatch arm), and the `interp.hooks` field + init/deinit. Stripped + `compiler_hooks.zig` to its still-live `BuildConfig` / `BuildHooks` (link/emit vtable, P5.2b) / `AssetDir` — + deleted `HookError`/`HookFn`/`Registry`/`registerDefaults` + all 37 `hookXxx` fns + the now-unused + `interp`/`Value` imports. The two VM unit tests that used `compiler_call` as a sample unported op now use + `vec_splat`. **B2** removed the `#compiler` attribute + `compiler_expr` AST node: the `hash_compiler` token + (`token.zig`/`lexer.zig`/`lsp/server.zig`), the `is_compiler_struct` / `struct_default_compiler` parser + machinery + the two `compiler_expr` body-synthesis branches (`parser.zig`), the `compiler_expr: void` AST + variant (`ast.zig`), and every `.builtin_expr, .compiler_expr =>` arm / `== .compiler_expr` check across + sema/resolver/semantic_diagnostics/generic/decl/call/calls (dropped `.compiler_expr`, kept `.builtin_expr`). + `abi(.compiler)` (the NEW mechanism) is untouched. Deleted the obsolete `calls.test.zig` `#compiler`-dispatch + unit test. **500/500 unit (−1 obsolete test) + 706/0 corpus, no snapshot churn.** NEXT: Step C — delete + `interp.zig` + the `regToValue`/`valueToReg` bridge; move `#insert` (`evalComptimeString`) to the VM. - **P5.7 Step A — the flip: VM is the SOLE comptime evaluator at the emit-time + type-fn sites; NO fallback (2026-06-19).** Removed the `if (self.comptime_flat or need_vm)` gate + the `vm_result orelse fallback` legacy-interp blocks from `emit_llvm.zig` (`runComptimeSideEffects` AND the const-init path in `emitGlobals`) diff --git a/src/ast.zig b/src/ast.zig index 3089179c..7dc1bdd3 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -81,7 +81,6 @@ pub const Node = struct { undef_literal: void, inferred_type: void, builtin_expr: void, - compiler_expr: void, library_decl: LibraryDecl, framework_decl: FrameworkDecl, function_type_expr: FunctionTypeExpr, diff --git a/src/ir/calls.test.zig b/src/ir/calls.test.zig index a69e6785..b52d2e0a 100644 --- a/src/ir/calls.test.zig +++ b/src/ir/calls.test.zig @@ -320,32 +320,6 @@ test "plan: protocol dispatch selects method index + prepends receiver" { try std.testing.expect(p.prepends_receiver); } -test "plan: struct (UFCS) method via #compiler dispatch + prepends receiver" { - var arena = std.heap.ArenaAllocator.init(std.testing.allocator); - defer arena.deinit(); - const alloc = arena.allocator(); - var module = ir_mod.Module.init(alloc); - defer module.deinit(); - var l = Lowering.init(&module); - const cr = CallResolver{ .l = &l }; - - // struct Point, with a `#compiler` method Point.scale(self) -> i64. - _ = module.types.intern(.{ .@"struct" = .{ .name = module.types.internString("Point"), .fields = &.{} } }); - const self_param = ast.Param{ .name = "self", .name_span = .{ .start = 0, .end = 0 }, .type_expr = typeExpr(alloc, "Point") }; - const params = [_]ast.Param{self_param}; - const compiler_body = mk(alloc, .{ .compiler_expr = {} }); - const method_fd = ast.FnDecl{ .name = "Point.scale", .params = ¶ms, .return_type = typeExpr(alloc, "i64"), .body = compiler_body }; - l.program_index.fn_ast_map.put("Point.scale", &method_fd) catch unreachable; - - const recv = callNode(alloc, ident(alloc, "cast"), &[_]*Node{ typeExpr(alloc, "Point"), intLit(alloc, 0) }); - const call = callNode(alloc, fieldAccess(alloc, recv, "scale"), &.{}); - const p = cr.plan(&call.data.call); - try std.testing.expectEqual(CallPlan.Kind.struct_method, p.kind); - try std.testing.expectEqualStrings("Point.scale", p.target.named); - try std.testing.expectEqual(TypeId.i64, p.return_type); - try std.testing.expect(p.prepends_receiver); -} - test "plan: runtime-class instance vs static dispatch" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); diff --git a/src/ir/calls.zig b/src/ir/calls.zig index c01a7129..9a6b249f 100644 --- a/src/ir/calls.zig +++ b/src/ir/calls.zig @@ -282,18 +282,6 @@ pub const CallResolver = struct { if (oi == .@"struct") { const struct_name = self.l.module.types.getString(oi.@"struct".name); const qualified = std.fmt.allocPrint(self.l.alloc, "{s}.{s}", .{ struct_name, cfa.field }) catch cfa.field; - // Generic #compiler method dispatch — return type from declaration. - if (self.l.program_index.fn_ast_map.get(qualified)) |method_fd| { - if (method_fd.body.data == .compiler_expr) { - return .{ - .kind = .struct_method, - .return_type = if (method_fd.return_type) |rt| type_bridge.resolveAstType(rt, &self.l.module.types, &self.l.program_index.type_alias_map, &self.l.program_index.module_const_map) else .void, - .target = .{ .named = qualified }, - .prepends_receiver = true, - .expands_defaults = defaultsFor(method_fd, c.args.len + 1), - }; - } - } if (self.l.resolveFuncByName(qualified)) |fid| { const func = &self.l.module.functions.items[@intFromEnum(fid)]; return .{ diff --git a/src/ir/lower/call.zig b/src/ir/lower/call.zig index 6af51f1f..2c240ff0 100644 --- a/src/ir/lower/call.zig +++ b/src/ir/lower/call.zig @@ -718,7 +718,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref { // literal global symbol — the existing bare-name // machinery below resolves them. switch (fd.body.data) { - .builtin_expr, .compiler_expr => break :gate, + .builtin_expr => break :gate, else => {}, } if (hasComptimeParams(fd)) return self.lowerComptimeCall(fd, c); @@ -919,7 +919,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref { // Generic method on a non-template struct: `obj.method($T, ...)` // or inferred form `obj.method(val)` where val's type pins $T. if (self.program_index.fn_ast_map.get(qualified)) |gen_fd| { - if (gen_fd.type_params.len > 0 and gen_fd.body.data != .compiler_expr) { + if (gen_fd.type_params.len > 0) { // Effective AST args: prepend receiver so positions // line up with fd.params (which has self at index 0). var eff_args = std.ArrayList(*const Node).empty; @@ -2090,7 +2090,7 @@ pub fn checkCallArity(self: *Lowering, fd: *const ast.FnDecl, callee_name: []con if (fd.type_params.len > 0 or hasComptimeParams(fd) or isPackFn(fd)) return false; switch (fd.body.data) { - .compiler_expr, .builtin_expr => return false, + .builtin_expr => return false, else => {}, } var min: usize = 0; diff --git a/src/ir/lower/decl.zig b/src/ir/lower/decl.zig index 9d0c7eb1..92eaeea1 100644 --- a/src/ir/lower/decl.zig +++ b/src/ir/lower/decl.zig @@ -523,7 +523,7 @@ pub fn funcWantsImplicitCtx(self: *const Lowering, fd: *const ast.FnDecl) bool { // C ABI, no sx context (Phase 2, gap iv). if (fd.extern_export != .none) return false; return switch (fd.body.data) { - .builtin_expr, .compiler_expr => false, + .builtin_expr => false, else => !isExportedEntryName(fd.name), }; } @@ -2402,10 +2402,10 @@ pub fn registerQualifiedFn(self: *Lowering, ns_name: []const u8, fd: *const ast. // collision assert; registering a qualified alias for them // would divert that machinery and strand a per-call type binding. if (fd.type_params.len > 0 or hasComptimeParams(fd) or isPackFn(fd)) return; - // Extern / builtin / #compiler bodies keep their literal name; a - // qualified alias has no distinct symbol to resolve to. + // Extern / builtin bodies keep their literal name; a qualified alias has + // no distinct symbol to resolve to. switch (fd.body.data) { - .builtin_expr, .compiler_expr => return, + .builtin_expr => return, else => {}, } const qualified = std.fmt.allocPrint(self.alloc, "{s}.{s}", .{ ns_name, short }) catch return; @@ -2521,8 +2521,8 @@ pub fn lazyLowerFunction(self: *Lowering, name: []const u8) void { } return; } - // Builtins / #compiler bodies stay as compiler-handled — no extern stub needed. - if (fd.body.data == .builtin_expr or fd.body.data == .compiler_expr) return; + // Builtin bodies stay as compiler-handled — no extern stub needed. + if (fd.body.data == .builtin_expr) return; if (fd.type_params.len > 0) return; // generics handled by monomorphization (Step 3.13) // Defer functions with type-category matches until all types are registered. @@ -2728,7 +2728,7 @@ pub fn lowerFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8, i // 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 + if (fd.body.data == .builtin_expr or fd.extern_export == .extern_ or fnIsBodilessCompiler(fd)) { // Already declared by scanDecls/declareFunction (which handles #extern renames) diff --git a/src/ir/lower/generic.zig b/src/ir/lower/generic.zig index af9868c1..c59832a1 100644 --- a/src/ir/lower/generic.zig +++ b/src/ir/lower/generic.zig @@ -822,7 +822,7 @@ pub fn isPlainFreeFn(fd: *const ast.FnDecl) bool { // fn. `export` DEFINES a real body, so it stays plain-free. if (fd.extern_export == .extern_) return false; return switch (fd.body.data) { - .builtin_expr, .compiler_expr => false, + .builtin_expr => false, else => true, }; } diff --git a/src/ir/resolver.zig b/src/ir/resolver.zig index 0e10e31a..88c19379 100644 --- a/src/ir/resolver.zig +++ b/src/ir/resolver.zig @@ -184,7 +184,7 @@ pub fn isPlainFreeFnDecl(fd: *const ast.FnDecl) bool { // body, so it stays plain-free. if (fd.extern_export == .extern_) return false; return switch (fd.body.data) { - .builtin_expr, .compiler_expr => false, + .builtin_expr => false, else => true, }; } diff --git a/src/ir/semantic_diagnostics.zig b/src/ir/semantic_diagnostics.zig index daae609a..a7e14063 100644 --- a/src/ir/semantic_diagnostics.zig +++ b/src/ir/semantic_diagnostics.zig @@ -355,7 +355,6 @@ pub const UnknownTypeChecker = struct { .undef_literal, .inferred_type, .builtin_expr, - .compiler_expr, .framework_decl, .function_type_expr, .closure_type_expr, diff --git a/src/lexer.zig b/src/lexer.zig index b86f1c2a..31057439 100644 --- a/src/lexer.zig +++ b/src/lexer.zig @@ -87,7 +87,6 @@ pub const Lexer = struct { .{ "#insert", Tag.hash_insert }, .{ "#run", Tag.hash_run }, .{ "#builtin", Tag.hash_builtin }, - .{ "#compiler", Tag.hash_compiler }, .{ "#library", Tag.hash_library }, .{ "#framework", Tag.hash_framework }, .{ "#using", Tag.hash_using }, diff --git a/src/lsp/server.zig b/src/lsp/server.zig index dda5e0b8..f85ed695 100644 --- a/src/lsp/server.zig +++ b/src/lsp/server.zig @@ -1690,7 +1690,6 @@ pub const Server = struct { .hash_import, .hash_insert, .hash_builtin, - .hash_compiler, .hash_library, .hash_framework, .hash_using, diff --git a/src/parser.zig b/src/parser.zig index 1e67c039..0b791b6d 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -21,11 +21,6 @@ pub const Parser = struct { diagnostics: ?*errors.DiagnosticList = null, /// Type param names from enclosing generic struct (set while parsing methods) struct_type_params: []const []const u8 = &.{}, - /// When true (set while parsing methods inside `struct #compiler { ... }`), - /// a missing function body (just `name :: (params);`) is synthesized as - /// a `.compiler_expr` body so the per-method `#compiler` suffix can be - /// omitted. - struct_default_compiler: bool = false, /// When true (set while parsing a `for` header's iterable expressions), /// a top-level `(` group immediately followed by `{` or `=>` is the loop /// CAPTURE, never call arguments — `for xs (x) { }` reads `(x)` as the @@ -950,15 +945,6 @@ pub const Parser = struct { fn parseStructDecl(self: *Parser, name: []const u8, start_pos: u32, name_is_raw: bool) anyerror!*Node { self.advance(); // skip 'struct' - // Optional `#compiler` attribute: all methods inside this struct are - // implicitly compiler hooks (no per-method `#compiler` suffix needed). - // Mirrors `protocol #inline { ... }` shape. - var is_compiler_struct = false; - if (self.current.tag == .hash_compiler) { - is_compiler_struct = true; - self.advance(); - } - // Optional welded-binding annotation: `struct abi(.zig) extern { … }`. // `abi(...)` (the ABI/layout selector) sits before the `extern` linkage // keyword, mirroring the fn-decl slot order; the library handle follows. @@ -1023,13 +1009,6 @@ pub const Parser = struct { self.struct_type_params = tp_names.items; defer self.struct_type_params = saved_struct_type_params; - // Propagate the struct-level `#compiler` flag to nested method - // parsing so a bodyless `name :: (params);` synthesizes a - // `.compiler_expr` body. - const saved_struct_default_compiler = self.struct_default_compiler; - self.struct_default_compiler = is_compiler_struct; - defer self.struct_default_compiler = saved_struct_default_compiler; - var field_names = std.ArrayList([]const u8).empty; var field_types = std.ArrayList(*Node).empty; var field_defaults = std.ArrayList(?*Node).empty; @@ -2014,17 +1993,6 @@ pub const Parser = struct { self.advance(); try self.expect(.semicolon); break :blk try self.createNode(bi_start, .{ .builtin_expr = {} }); - } else if (self.current.tag == .hash_compiler) blk: { - const ci_start = self.current.loc.start; - self.advance(); - try self.expect(.semicolon); - break :blk try self.createNode(ci_start, .{ .compiler_expr = {} }); - } else if (self.struct_default_compiler and self.current.tag == .semicolon) blk: { - // Inside `struct #compiler { ... }`: a bodyless method is - // implicitly a `#compiler` hook. - const ci_start = self.current.loc.start; - self.advance(); - break :blk try self.createNode(ci_start, .{ .compiler_expr = {} }); } else if (self.current.tag == .fat_arrow) blk: { is_arrow = true; self.advance(); @@ -3765,16 +3733,12 @@ pub const Parser = struct { fn isFunctionDef(self: *Parser) bool { const tag = self.peekPastParens() orelse return false; - // Inside `struct #compiler { ... }`, a bodyless method declaration - // ends with `;` directly after the param list — recognise it as a - // function def (not a constant) so it goes through parseFnDecl. - if (self.struct_default_compiler and tag == .semicolon) return true; // `(T1, T2) -> R` without a trailing body (`{`, `=>`, or an extern/ // builtin marker) is a function-type literal, not a function def. if (tag == .arrow) return self.hasFnBodyAfterArrow(); // `kw_extern`/`kw_export`: a postfix linkage modifier (e.g. `f :: () extern;` // with no return type) marks a fn decl just like `abi(...)`. - return tag == .l_brace or tag == .hash_builtin or tag == .hash_compiler or tag == .fat_arrow or tag == .kw_abi or tag == .kw_extern or tag == .kw_export; + return tag == .l_brace or tag == .hash_builtin or tag == .fat_arrow or tag == .kw_abi or tag == .kw_extern or tag == .kw_export; } fn hasFnBodyAfterArrow(self: *Parser) bool { @@ -3800,17 +3764,11 @@ pub const Parser = struct { while (self.current.tag != .eof) { if (self.current.tag == .fat_arrow) return true; if (self.current.tag == .l_brace) return true; - if (self.current.tag == .hash_builtin or self.current.tag == .hash_compiler) return true; + if (self.current.tag == .hash_builtin) return true; if (self.current.tag == .kw_abi) return true; // Postfix linkage modifier after the return type: `-> R extern;` / // `-> R export { … }` (and `-> R abi(.c) extern`). Marks a fn def. if (self.current.tag == .kw_extern or self.current.tag == .kw_export) return true; - // Inside a `struct #compiler` block, a `(...) -> Ret;` ending - // with `;` after the return type is a `#compiler` method - // declaration (body implicit). Outside that context, the same - // shape is a function-type alias (no body) and falls through to - // const-decl parsing. - if (self.struct_default_compiler and self.current.tag == .semicolon) return true; if (self.current.tag == .identifier or self.current.tag.isTypeKeyword() or self.current.tag == .dot or self.current.tag == .dollar or self.current.tag == .l_bracket or self.current.tag == .r_bracket or diff --git a/src/sema.zig b/src/sema.zig index ceaafb70..3f87ac64 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -1294,7 +1294,6 @@ pub const Analyzer = struct { .undef_literal, .inferred_type, .builtin_expr, - .compiler_expr, .library_decl, .framework_decl, .function_type_expr, @@ -1767,7 +1766,6 @@ pub fn findNodeAtOffset(node: *Node, offset: u32) ?*Node { .undef_literal, .inferred_type, .builtin_expr, - .compiler_expr, .library_decl, .framework_decl, .function_type_expr, diff --git a/src/token.zig b/src/token.zig index 29ef3dee..3896817e 100644 --- a/src/token.zig +++ b/src/token.zig @@ -118,7 +118,6 @@ pub const Tag = enum { hash_import, // #import hash_insert, // #insert hash_builtin, // #builtin - hash_compiler, // #compiler hash_library, // #library hash_framework, // #framework hash_using, // #using