Commit 7f931a7522

Andrew Kelley <andrew@ziglang.org>
2021-04-20 01:03:46
AstGen: implement error set decls
1 parent 2083208
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(
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();
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;
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);