commit ea599150cd8f9c7f8c737160f0165ce5c8e11134 (tree)
parent 906c2712846b7b504bed95372ab72e9c0a0f8383
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Thu, 12 Feb 2026 20:35:58 +0000
astgen: implement error set declarations
Port errorSetDecl from upstream AstGen.zig:5905-5955. Replaces the
SET_ERROR placeholder at the ERROR_SET_DECL case. Loops tokens between
lbrace and rbrace, collecting identifier strings into the ErrorSetDecl
payload.
Also add error_set_decl to the test comparison functions.
Tests added: empty error set, error set with members.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
2 files changed, 51 insertions(+), 4 deletions(-)
diff --git a/astgen.c b/astgen.c
@@ -3476,11 +3476,32 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
return rvalue(gz, rl,
addStrTok(gz, ZIR_INST_ERROR_VALUE, str, error_token), node);
}
- // error_set_decl (AstGen.zig:1131-1140).
+ // error_set_decl (AstGen.zig:5905-5955).
case AST_NODE_ERROR_SET_DECL: {
- // TODO: proper error set, for now just emit a placeholder.
- SET_ERROR(ag);
- return ZIR_REF_VOID_VALUE;
+ AstData esd = ag->tree->nodes.datas[node];
+ uint32_t lbrace = esd.lhs;
+ uint32_t rbrace = esd.rhs;
+ // Reserve 1 extra word for ErrorSetDecl.fields_len.
+ ensureExtraCapacity(ag, 1 + (rbrace - lbrace));
+ uint32_t payload_index = ag->extra_len;
+ ag->extra_len++; // placeholder for fields_len
+ uint32_t fields_len = 0;
+ for (uint32_t tok = lbrace + 1; tok < rbrace; tok++) {
+ TokenizerTag ttag = ag->tree->tokens.tags[tok];
+ if (ttag == TOKEN_DOC_COMMENT || ttag == TOKEN_COMMA)
+ continue;
+ if (ttag == TOKEN_IDENTIFIER) {
+ uint32_t str_index = identAsString(ag, tok);
+ ensureExtraCapacity(ag, 1);
+ ag->extra[ag->extra_len++] = str_index;
+ fields_len++;
+ }
+ }
+ ag->extra[payload_index] = fields_len;
+ return rvalue(gz, rl,
+ addPlNodePayloadIndex(
+ gz, ZIR_INST_ERROR_SET_DECL, node, payload_index),
+ node);
}
// assign in expr context (AstGen.zig:1011-1014).
case AST_NODE_ASSIGN:
diff --git a/astgen_test.zig b/astgen_test.zig
@@ -472,6 +472,7 @@ fn expectEqualData(
.array_cat,
.array_init,
.array_init_ref,
+ .error_set_decl,
=> {
const r = ref.pl_node;
const g = got.pl_node;
@@ -780,6 +781,7 @@ fn dataMatches(tag: Zir.Inst.Tag, ref: Zir.Inst.Data, got: c.ZirInstData) bool {
.array_cat,
.array_init,
.array_init_ref,
+ .error_set_decl,
=> {
return @intFromEnum(ref.pl_node.src_node) == got.pl_node.src_node and
ref.pl_node.payload_index == got.pl_node.payload_index;
@@ -908,6 +910,30 @@ test "astgen: struct comptime field" {
try expectEqualZir(gpa, ref_zir, c_zir);
}
+test "astgen: empty error set" {
+ const gpa = std.testing.allocator;
+ const source: [:0]const u8 = "const E = error{};";
+ var ref_zir = try refZir(gpa, source);
+ defer ref_zir.deinit(gpa);
+ var c_ast = c.astParse(source.ptr, @intCast(source.len));
+ defer c.astDeinit(&c_ast);
+ var c_zir = c.astGen(&c_ast);
+ defer c.zirDeinit(&c_zir);
+ try expectEqualZir(gpa, ref_zir, c_zir);
+}
+
+test "astgen: error set with members" {
+ const gpa = std.testing.allocator;
+ const source: [:0]const u8 = "const E = error{ OutOfMemory, OutOfTime };";
+ var ref_zir = try refZir(gpa, source);
+ defer ref_zir.deinit(gpa);
+ var c_ast = c.astParse(source.ptr, @intCast(source.len));
+ defer c.astDeinit(&c_ast);
+ var c_zir = c.astGen(&c_ast);
+ defer c.zirDeinit(&c_zir);
+ try expectEqualZir(gpa, ref_zir, c_zir);
+}
+
test "astgen: corpus test_all.zig" {
const gpa = std.testing.allocator;
try corpusCheck(gpa, "test_all.zig", @embedFile("test_all.zig"));