From 7f931a75229b4d6b9d07a7485bfc1726a92fc591 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 19 Apr 2021 16:03:46 -0700 Subject: [PATCH] AstGen: implement error set decls --- BRANCH_TODO | 84 ++++++++++---------------------------------------- src/AstGen.zig | 29 ++++++++++++++++- src/Sema.zig | 12 ++++++++ src/Zir.zig | 36 +++++++++++++++++++--- 4 files changed, 88 insertions(+), 73 deletions(-) diff --git a/BRANCH_TODO b/BRANCH_TODO index ffaf14fc9e..d944ff9983 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -604,73 +604,6 @@ fn astgenAndSemaVarDecl( } -fn errorSetDecl( - gz: *GenZir, - scope: *Scope, - rl: ResultLoc, - node: ast.Node.Index, -) InnerError!Zir.Inst.Ref { - const astgen = gz.astgen; - const tree = &astgen.file.tree; - const main_tokens = tree.nodes.items(.main_token); - const token_tags = tree.tokens.items(.tag); - - // Count how many fields there are. - const error_token = main_tokens[node]; - const count: usize = count: { - var tok_i = error_token + 2; - var count: usize = 0; - while (true) : (tok_i += 1) { - switch (token_tags[tok_i]) { - .doc_comment, .comma => {}, - .identifier => count += 1, - .r_brace => break :count count, - else => unreachable, - } - } else unreachable; // TODO should not need else unreachable here - }; - - const gpa = astgen.gpa; - var new_decl_arena = std.heap.ArenaAllocator.init(gpa); - errdefer new_decl_arena.deinit(); - const arena = &new_decl_arena.allocator; - - const fields = try arena.alloc([]const u8, count); - { - var tok_i = error_token + 2; - var field_i: usize = 0; - while (true) : (tok_i += 1) { - switch (token_tags[tok_i]) { - .doc_comment, .comma => {}, - .identifier => { - fields[field_i] = try astgen.identifierTokenStringTreeArena(tok_i, tree, arena); - field_i += 1; - }, - .r_brace => break, - else => unreachable, - } - } - } - const error_set = try arena.create(Module.ErrorSet); - error_set.* = .{ - .owner_decl = astgen.decl, - .node_offset = astgen.decl.nodeIndexToRelative(node), - .names_ptr = fields.ptr, - .names_len = @intCast(u32, fields.len), - }; - const error_set_ty = try Type.Tag.error_set.create(arena, error_set); - const error_set_val = try Value.Tag.ty.create(arena, error_set_ty); - const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{ - .ty = Type.initTag(.type), - .val = error_set_val, - }); - const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl); - const result = try gz.addDecl(.decl_val, decl_index, node); - return rvalue(gz, scope, rl, result, node); -} - - - if (mod.lookupIdentifier(scope, ident_name)) |decl| { const msg = msg: { const msg = try mod.errMsg( @@ -761,3 +694,20 @@ fn errorSetDecl( ); } + + const error_set = try arena.create(Module.ErrorSet); + error_set.* = .{ + .owner_decl = astgen.decl, + .node_offset = astgen.decl.nodeIndexToRelative(node), + .names_ptr = fields.ptr, + .names_len = @intCast(u32, fields.len), + }; + const error_set_ty = try Type.Tag.error_set.create(arena, error_set); + const error_set_val = try Value.Tag.ty.create(arena, error_set_ty); + const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{ + .ty = Type.initTag(.type), + .val = error_set_val, + }); + const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl); + const result = try gz.addDecl(.decl_val, decl_index, node); + return rvalue(gz, scope, rl, result, node); diff --git a/src/AstGen.zig b/src/AstGen.zig index 21b38b905e..f9cfd7eeb1 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1463,6 +1463,7 @@ fn blockExprStmts( .enum_decl, .enum_decl_nonexhaustive, .opaque_decl, + .error_set_decl, .int_to_enum, .enum_to_int, .type_info, @@ -2930,11 +2931,37 @@ fn errorSetDecl( node: ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; + const gpa = astgen.gpa; const tree = &astgen.file.tree; const main_tokens = tree.nodes.items(.main_token); const token_tags = tree.tokens.items(.tag); - return astgen.failNode(node, "TODO AstGen errorSetDecl", .{}); + var field_names: std.ArrayListUnmanaged(u32) = .{}; + defer field_names.deinit(gpa); + + { + const error_token = main_tokens[node]; + var tok_i = error_token + 2; + var field_i: usize = 0; + while (true) : (tok_i += 1) { + switch (token_tags[tok_i]) { + .doc_comment, .comma => {}, + .identifier => { + const str_index = try gz.identAsString(tok_i); + try field_names.append(gpa, str_index); + field_i += 1; + }, + .r_brace => break, + else => unreachable, + } + } + } + + const result = try gz.addPlNode(.error_set_decl, node, Zir.Inst.ErrorSetDecl{ + .fields_len = @intCast(u32, field_names.items.len), + }); + try astgen.extra.appendSlice(gpa, field_names.items); + return rvalue(gz, scope, rl, result, node); } fn orelseCatchExpr( diff --git a/src/Sema.zig b/src/Sema.zig index f2a8e798df..dea89ffef7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -343,6 +343,7 @@ pub fn analyzeBody( .enum_decl_nonexhaustive => try sema.zirEnumDecl(block, inst, true), .union_decl => try sema.zirUnionDecl(block, inst), .opaque_decl => try sema.zirOpaqueDecl(block, inst), + .error_set_decl => try sema.zirErrorSetDecl(block, inst), .add => try sema.zirArithmetic(block, inst), .addwrap => try sema.zirArithmetic(block, inst), @@ -978,6 +979,17 @@ fn zirOpaqueDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr return sema.mod.fail(&block.base, sema.src, "TODO implement zirOpaqueDecl", .{}); } +fn zirErrorSetDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const tracy = trace(@src()); + defer tracy.end(); + + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); + + return sema.mod.fail(&block.base, sema.src, "TODO implement zirErrorSetDecl", .{}); +} + fn zirRetPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { const tracy = trace(@src()); defer tracy.end(); diff --git a/src/Zir.zig b/src/Zir.zig index c8d27e870e..554bcf86c2 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -307,6 +307,9 @@ pub const Inst = struct { /// An opaque type definition. Provides an AST node only. /// Uses the `node` union field. opaque_decl, + /// An error set type definition. Contains a list of field names. + /// Uses the `pl_node` union field. Payload is `ErrorSetDecl`. + error_set_decl, /// Declares the beginning of a statement. Used for debug info. /// Uses the `node` union field. dbg_stmt_node, @@ -986,6 +989,7 @@ pub const Inst = struct { .enum_decl, .enum_decl_nonexhaustive, .opaque_decl, + .error_set_decl, .dbg_stmt_node, .decl_ref, .decl_val, @@ -2011,6 +2015,11 @@ pub const Inst = struct { fields_len: u32, }; + /// Trailing: field_name: u32 // for every field: null terminated string index + pub const ErrorSetDecl = struct { + fields_len: u32, + }; + /// A f128 value, broken up into 4 u32 parts. pub const Float128 = struct { piece0: u32, @@ -2328,6 +2337,8 @@ const Writer = struct { .builtin_async_call, => try self.writePlNode(stream, inst), + .error_set_decl => try self.writePlNodeErrorSetDecl(stream, inst), + .add_with_overflow, .sub_with_overflow, .mul_with_overflow, @@ -2596,11 +2607,7 @@ const Writer = struct { try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)}); } - fn writePlNode( - self: *Writer, - stream: anytype, - inst: Inst.Index, - ) (@TypeOf(stream).Error || error{OutOfMemory})!void { + fn writePlNode(self: *Writer, stream: anytype, inst: Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[inst].pl_node; try stream.writeAll("TODO) "); try self.writeSrc(stream, inst_data.src()); @@ -2616,6 +2623,25 @@ const Writer = struct { try self.writeSrc(stream, inst_data.src()); } + fn writePlNodeErrorSetDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Inst.ErrorSetDecl, inst_data.payload_index); + const fields = self.code.extra[extra.end..][0..extra.data.fields_len]; + + try stream.writeAll("{\n"); + self.indent += 2; + for (fields) |str_index| { + const name = self.code.nullTerminatedString(str_index); + try stream.writeByteNTimes(' ', self.indent); + try stream.print("{},\n", .{std.zig.fmtId(name)}); + } + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}) "); + + try self.writeSrc(stream, inst_data.src()); + } + fn writePlNodeOverflowArithmetic(self: *Writer, stream: anytype, inst: Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[inst].pl_node; const extra = self.code.extraData(Inst.OverflowArithmetic, inst_data.payload_index).data;