P5.7 Step B2: remove the #compiler attribute + compiler_expr AST node

The #compiler struct attribute + #compiler-suffixed bodyless methods were
fully superseded by abi(.compiler) (P5.5) — no sx code uses them.

Remove the hash_compiler token (token/lexer/lsp), the is_compiler_struct /
struct_default_compiler parser machinery + the two compiler_expr body-
synthesis branches, the compiler_expr AST variant, and every
.builtin_expr/.compiler_expr switch arm + == .compiler_expr check across
sema/resolver/semantic_diagnostics/generic/decl/call/calls (kept .builtin_expr).
abi(.compiler) is untouched. Delete the obsolete calls.test.zig dispatch test.

500/500 unit + 706/0 corpus.
This commit is contained in:
agra
2026-06-19 17:18:45 +03:00
parent e2971f272c
commit 64eb01918a
14 changed files with 31 additions and 101 deletions

View File

@@ -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 <lib> { … }`.
// `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