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>
This commit is contained in:
2026-02-12 20:35:58 +00:00
parent 906c271284
commit ea599150cd
2 changed files with 51 additions and 4 deletions

View File

@@ -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:

View File

@@ -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"));