| author | |
| committer | |
| log | 0e50a0c1e53a062e7c68ceeb1cfab9597a9caa23 |
| tree | c156e6679c354c74c1ef2d18ef374441a3689c00 |
| parent | bcfebb4b2b17dcac445fc5dedbbd259cc8c2f306 |
3 files changed, 337 insertions(+), 29 deletions(-)
src/AstGen.zig+89-2| ... | @@ -1932,7 +1932,7 @@ fn containerDecl( | ... | @@ -1932,7 +1932,7 @@ fn containerDecl( |
| 1932 | // ZIR for all the field types, alignments, and default value expressions. | 1932 | // ZIR for all the field types, alignments, and default value expressions. |
| 1933 | 1933 | ||
| 1934 | const arg_inst: zir.Inst.Ref = if (container_decl.ast.arg != 0) | 1934 | const arg_inst: zir.Inst.Ref = if (container_decl.ast.arg != 0) |
| 1935 | try comptimeExpr(gz, scope, .none, container_decl.ast.arg) | 1935 | try comptimeExpr(gz, scope, .{ .ty = .type_type }, container_decl.ast.arg) |
| 1936 | else | 1936 | else |
| 1937 | .none; | 1937 | .none; |
| 1938 | 1938 | ||
| ... | @@ -2006,6 +2006,9 @@ fn containerDecl( | ... | @@ -2006,6 +2006,9 @@ fn containerDecl( |
| 2006 | } | 2006 | } |
| 2007 | total_fields += 1; | 2007 | total_fields += 1; |
| 2008 | if (member.ast.value_expr != 0) { | 2008 | if (member.ast.value_expr != 0) { |
| 2009 | if (arg_inst == .none) { | ||
| 2010 | return mod.failNode(scope, member.ast.value_expr, "value assigned to enum tag with inferred tag type", .{}); | ||
| 2011 | } | ||
| 2009 | values += 1; | 2012 | values += 1; |
| 2010 | } | 2013 | } |
| 2011 | } | 2014 | } |
| ... | @@ -2118,7 +2121,91 @@ fn containerDecl( | ... | @@ -2118,7 +2121,91 @@ fn containerDecl( |
| 2118 | // In this case we must generate ZIR code for the tag values, similar to | 2121 | // In this case we must generate ZIR code for the tag values, similar to |
| 2119 | // how structs are handled above. The new anonymous Decl will be created in | 2122 | // how structs are handled above. The new anonymous Decl will be created in |
| 2120 | // Sema, not AstGen. | 2123 | // Sema, not AstGen. |
| 2121 | return mod.failNode(scope, node, "TODO AstGen for enum decl with decls or explicitly provided field values", .{}); | 2124 | const tag: zir.Inst.Tag = if (counts.nonexhaustive_node == 0) |
| 2125 | .enum_decl | ||
| 2126 | else | ||
| 2127 | .enum_decl_nonexhaustive; | ||
| 2128 | if (counts.total_fields == 0) { | ||
| 2129 | return gz.addPlNode(tag, node, zir.Inst.EnumDecl{ | ||
| 2130 | .tag_type = arg_inst, | ||
| 2131 | .fields_len = 0, | ||
| 2132 | .body_len = 0, | ||
| 2133 | }); | ||
| 2134 | } | ||
| 2135 | |||
| 2136 | // The enum_decl instruction introduces a scope in which the decls of the enum | ||
| 2137 | // are in scope, so that tag values can refer to decls within the enum itself. | ||
| 2138 | var block_scope: GenZir = .{ | ||
| 2139 | .parent = scope, | ||
| 2140 | .astgen = astgen, | ||
| 2141 | .force_comptime = true, | ||
| 2142 | }; | ||
| 2143 | defer block_scope.instructions.deinit(gpa); | ||
| 2144 | |||
| 2145 | var fields_data = ArrayListUnmanaged(u32){}; | ||
| 2146 | defer fields_data.deinit(gpa); | ||
| 2147 | |||
| 2148 | try fields_data.ensureCapacity(gpa, counts.total_fields + counts.values); | ||
| 2149 | |||
| 2150 | // We only need this if there are greater than 32 fields. | ||
| 2151 | var bit_bag = ArrayListUnmanaged(u32){}; | ||
| 2152 | defer bit_bag.deinit(gpa); | ||
| 2153 | |||
| 2154 | var cur_bit_bag: u32 = 0; | ||
| 2155 | var field_index: usize = 0; | ||
| 2156 | for (container_decl.ast.members) |member_node| { | ||
| 2157 | if (member_node == counts.nonexhaustive_node) | ||
| 2158 | continue; | ||
| 2159 | const member = switch (node_tags[member_node]) { | ||
| 2160 | .container_field_init => tree.containerFieldInit(member_node), | ||
| 2161 | .container_field_align => tree.containerFieldAlign(member_node), | ||
| 2162 | .container_field => tree.containerField(member_node), | ||
| 2163 | else => continue, | ||
| 2164 | }; | ||
| 2165 | if (field_index % 32 == 0 and field_index != 0) { | ||
| 2166 | try bit_bag.append(gpa, cur_bit_bag); | ||
| 2167 | cur_bit_bag = 0; | ||
| 2168 | } | ||
| 2169 | assert(member.comptime_token == null); | ||
| 2170 | assert(member.ast.type_expr == 0); | ||
| 2171 | assert(member.ast.align_expr == 0); | ||
| 2172 | |||
| 2173 | const field_name = try gz.identAsString(member.ast.name_token); | ||
| 2174 | fields_data.appendAssumeCapacity(field_name); | ||
| 2175 | |||
| 2176 | const have_value = member.ast.value_expr != 0; | ||
| 2177 | cur_bit_bag = (cur_bit_bag >> 1) | | ||
| 2178 | (@as(u32, @boolToInt(have_value)) << 31); | ||
| 2179 | |||
| 2180 | if (have_value) { | ||
| 2181 | const tag_value_inst = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr); | ||
| 2182 | fields_data.appendAssumeCapacity(@enumToInt(tag_value_inst)); | ||
| 2183 | } | ||
| 2184 | |||
| 2185 | field_index += 1; | ||
| 2186 | } | ||
| 2187 | const empty_slot_count = 32 - (field_index % 32); | ||
| 2188 | cur_bit_bag >>= @intCast(u5, empty_slot_count); | ||
| 2189 | |||
| 2190 | const decl_inst = try gz.addBlock(tag, node); | ||
| 2191 | try gz.instructions.append(gpa, decl_inst); | ||
| 2192 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); | ||
| 2193 | |||
| 2194 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + | ||
| 2195 | @typeInfo(zir.Inst.EnumDecl).Struct.fields.len + | ||
| 2196 | bit_bag.items.len + 1 + fields_data.items.len + | ||
| 2197 | block_scope.instructions.items.len); | ||
| 2198 | const zir_datas = astgen.instructions.items(.data); | ||
| 2199 | zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(zir.Inst.EnumDecl{ | ||
| 2200 | .tag_type = arg_inst, | ||
| 2201 | .body_len = @intCast(u32, block_scope.instructions.items.len), | ||
| 2202 | .fields_len = @intCast(u32, field_index), | ||
| 2203 | }); | ||
| 2204 | astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); | ||
| 2205 | astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. | ||
| 2206 | astgen.extra.appendAssumeCapacity(cur_bit_bag); | ||
| 2207 | astgen.extra.appendSliceAssumeCapacity(fields_data.items); | ||
| 2208 | return rvalue(gz, scope, rl, astgen.indexToRef(decl_inst), node); | ||
| 2122 | }, | 2209 | }, |
| 2123 | .keyword_opaque => { | 2210 | .keyword_opaque => { |
| 2124 | const result = try gz.addNode(.opaque_decl, node); | 2211 | const result = try gz.addNode(.opaque_decl, node); |
src/Sema.zig+166-13| ... | @@ -542,7 +542,7 @@ fn zirStructDecl( | ... | @@ -542,7 +542,7 @@ fn zirStructDecl( |
| 542 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; | 542 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 543 | const fields_len = extra.data.fields_len; | 543 | const fields_len = extra.data.fields_len; |
| 544 | 544 | ||
| 545 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | 545 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); |
| 546 | 546 | ||
| 547 | const struct_obj = try new_decl_arena.allocator.create(Module.Struct); | 547 | const struct_obj = try new_decl_arena.allocator.create(Module.Struct); |
| 548 | const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj); | 548 | const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj); |
| ... | @@ -602,7 +602,7 @@ fn zirStructDecl( | ... | @@ -602,7 +602,7 @@ fn zirStructDecl( |
| 602 | // should be the struct itself. Thus we need a new Sema. | 602 | // should be the struct itself. Thus we need a new Sema. |
| 603 | var struct_sema: Sema = .{ | 603 | var struct_sema: Sema = .{ |
| 604 | .mod = sema.mod, | 604 | .mod = sema.mod, |
| 605 | .gpa = sema.mod.gpa, | 605 | .gpa = gpa, |
| 606 | .arena = &new_decl_arena.allocator, | 606 | .arena = &new_decl_arena.allocator, |
| 607 | .code = sema.code, | 607 | .code = sema.code, |
| 608 | .inst_map = sema.inst_map, | 608 | .inst_map = sema.inst_map, |
| ... | @@ -632,7 +632,7 @@ fn zirStructDecl( | ... | @@ -632,7 +632,7 @@ fn zirStructDecl( |
| 632 | } | 632 | } |
| 633 | const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable; | 633 | const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable; |
| 634 | const body_end = extra.end + body.len; | 634 | const body_end = extra.end + body.len; |
| 635 | var field_index: usize = body_end + bit_bags_count; | 635 | var extra_index: usize = body_end + bit_bags_count; |
| 636 | var bit_bag_index: usize = body_end; | 636 | var bit_bag_index: usize = body_end; |
| 637 | var cur_bit_bag: u32 = undefined; | 637 | var cur_bit_bag: u32 = undefined; |
| 638 | var field_i: u32 = 0; | 638 | var field_i: u32 = 0; |
| ... | @@ -646,10 +646,10 @@ fn zirStructDecl( | ... | @@ -646,10 +646,10 @@ fn zirStructDecl( |
| 646 | const has_default = @truncate(u1, cur_bit_bag) != 0; | 646 | const has_default = @truncate(u1, cur_bit_bag) != 0; |
| 647 | cur_bit_bag >>= 1; | 647 | cur_bit_bag >>= 1; |
| 648 | 648 | ||
| 649 | const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[field_index]); | 649 | const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[extra_index]); |
| 650 | field_index += 1; | 650 | extra_index += 1; |
| 651 | const field_type_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[field_index]); | 651 | const field_type_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); |
| 652 | field_index += 1; | 652 | extra_index += 1; |
| 653 | 653 | ||
| 654 | // This string needs to outlive the ZIR code. | 654 | // This string needs to outlive the ZIR code. |
| 655 | const field_name = try new_decl_arena.allocator.dupe(u8, field_name_zir); | 655 | const field_name = try new_decl_arena.allocator.dupe(u8, field_name_zir); |
| ... | @@ -667,16 +667,16 @@ fn zirStructDecl( | ... | @@ -667,16 +667,16 @@ fn zirStructDecl( |
| 667 | }; | 667 | }; |
| 668 | 668 | ||
| 669 | if (has_align) { | 669 | if (has_align) { |
| 670 | const align_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[field_index]); | 670 | const align_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); |
| 671 | field_index += 1; | 671 | extra_index += 1; |
| 672 | // TODO: if we need to report an error here, use a source location | 672 | // TODO: if we need to report an error here, use a source location |
| 673 | // that points to this alignment expression rather than the struct. | 673 | // that points to this alignment expression rather than the struct. |
| 674 | // But only resolve the source location if we need to emit a compile error. | 674 | // But only resolve the source location if we need to emit a compile error. |
| 675 | gop.entry.value.abi_align = (try sema.resolveInstConst(block, src, align_ref)).val; | 675 | gop.entry.value.abi_align = (try sema.resolveInstConst(block, src, align_ref)).val; |
| 676 | } | 676 | } |
| 677 | if (has_default) { | 677 | if (has_default) { |
| 678 | const default_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[field_index]); | 678 | const default_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); |
| 679 | field_index += 1; | 679 | extra_index += 1; |
| 680 | // TODO: if we need to report an error here, use a source location | 680 | // TODO: if we need to report an error here, use a source location |
| 681 | // that points to this default value expression rather than the struct. | 681 | // that points to this default value expression rather than the struct. |
| 682 | // But only resolve the source location if we need to emit a compile error. | 682 | // But only resolve the source location if we need to emit a compile error. |
| ... | @@ -696,11 +696,164 @@ fn zirEnumDecl( | ... | @@ -696,11 +696,164 @@ fn zirEnumDecl( |
| 696 | const tracy = trace(@src()); | 696 | const tracy = trace(@src()); |
| 697 | defer tracy.end(); | 697 | defer tracy.end(); |
| 698 | 698 | ||
| 699 | const gpa = sema.gpa; | ||
| 699 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 700 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 700 | const src = inst_data.src(); | 701 | const src = inst_data.src(); |
| 701 | const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index); | 702 | const extra = sema.code.extraData(zir.Inst.EnumDecl, inst_data.payload_index); |
| 703 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; | ||
| 704 | const fields_len = extra.data.fields_len; | ||
| 705 | |||
| 706 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | ||
| 707 | |||
| 708 | const tag_ty = blk: { | ||
| 709 | if (extra.data.tag_type != .none) { | ||
| 710 | // TODO better source location | ||
| 711 | // TODO (needs AstGen fix too) move this eval to the block so it gets allocated | ||
| 712 | // in the new decl arena. | ||
| 713 | break :blk try sema.resolveType(block, src, extra.data.tag_type); | ||
| 714 | } | ||
| 715 | const bits = std.math.log2_int_ceil(usize, fields_len); | ||
| 716 | break :blk try Type.Tag.int_unsigned.create(&new_decl_arena.allocator, bits); | ||
| 717 | }; | ||
| 718 | |||
| 719 | const enum_obj = try new_decl_arena.allocator.create(Module.EnumFull); | ||
| 720 | const enum_ty_payload = try gpa.create(Type.Payload.EnumFull); | ||
| 721 | enum_ty_payload.* = .{ | ||
| 722 | .base = .{ .tag = if (nonexhaustive) .enum_nonexhaustive else .enum_full }, | ||
| 723 | .data = enum_obj, | ||
| 724 | }; | ||
| 725 | const enum_ty = Type.initPayload(&enum_ty_payload.base); | ||
| 726 | const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty); | ||
| 727 | const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{ | ||
| 728 | .ty = Type.initTag(.type), | ||
| 729 | .val = enum_val, | ||
| 730 | }); | ||
| 731 | enum_obj.* = .{ | ||
| 732 | .owner_decl = sema.owner_decl, | ||
| 733 | .tag_ty = tag_ty, | ||
| 734 | .fields = .{}, | ||
| 735 | .values = .{}, | ||
| 736 | .node_offset = inst_data.src_node, | ||
| 737 | .namespace = .{ | ||
| 738 | .parent = sema.owner_decl.namespace, | ||
| 739 | .parent_name_hash = new_decl.fullyQualifiedNameHash(), | ||
| 740 | .ty = enum_ty, | ||
| 741 | .file_scope = block.getFileScope(), | ||
| 742 | }, | ||
| 743 | }; | ||
| 744 | |||
| 745 | { | ||
| 746 | const ast = std.zig.ast; | ||
| 747 | const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node); | ||
| 748 | const tree: *const ast.Tree = &enum_obj.namespace.file_scope.tree; | ||
| 749 | const node_tags = tree.nodes.items(.tag); | ||
| 750 | var buf: [2]ast.Node.Index = undefined; | ||
| 751 | const members: []const ast.Node.Index = switch (node_tags[node]) { | ||
| 752 | .container_decl, | ||
| 753 | .container_decl_trailing, | ||
| 754 | => tree.containerDecl(node).ast.members, | ||
| 755 | |||
| 756 | .container_decl_two, | ||
| 757 | .container_decl_two_trailing, | ||
| 758 | => tree.containerDeclTwo(&buf, node).ast.members, | ||
| 759 | |||
| 760 | .container_decl_arg, | ||
| 761 | .container_decl_arg_trailing, | ||
| 762 | => tree.containerDeclArg(node).ast.members, | ||
| 763 | |||
| 764 | .root => tree.rootDecls(), | ||
| 765 | else => unreachable, | ||
| 766 | }; | ||
| 767 | try sema.mod.analyzeNamespace(&enum_obj.namespace, members); | ||
| 768 | } | ||
| 769 | |||
| 770 | if (fields_len == 0) { | ||
| 771 | assert(body.len == 0); | ||
| 772 | return sema.analyzeDeclVal(block, src, new_decl); | ||
| 773 | } | ||
| 774 | |||
| 775 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | ||
| 776 | const body_end = extra.end + body.len; | ||
| 777 | |||
| 778 | try enum_obj.fields.ensureCapacity(&new_decl_arena.allocator, fields_len); | ||
| 779 | const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| { | ||
| 780 | if (bag != 0) break true; | ||
| 781 | } else false; | ||
| 782 | if (any_values) { | ||
| 783 | try enum_obj.values.ensureCapacity(&new_decl_arena.allocator, fields_len); | ||
| 784 | } | ||
| 785 | |||
| 786 | { | ||
| 787 | // We create a block for the field type instructions because they | ||
| 788 | // may need to reference Decls from inside the enum namespace. | ||
| 789 | // Within the field type, default value, and alignment expressions, the "owner decl" | ||
| 790 | // should be the enum itself. Thus we need a new Sema. | ||
| 791 | var enum_sema: Sema = .{ | ||
| 792 | .mod = sema.mod, | ||
| 793 | .gpa = gpa, | ||
| 794 | .arena = &new_decl_arena.allocator, | ||
| 795 | .code = sema.code, | ||
| 796 | .inst_map = sema.inst_map, | ||
| 797 | .owner_decl = new_decl, | ||
| 798 | .namespace = &enum_obj.namespace, | ||
| 799 | .owner_func = null, | ||
| 800 | .func = null, | ||
| 801 | .param_inst_list = &.{}, | ||
| 802 | .branch_quota = sema.branch_quota, | ||
| 803 | .branch_count = sema.branch_count, | ||
| 804 | }; | ||
| 805 | |||
| 806 | var enum_block: Scope.Block = .{ | ||
| 807 | .parent = null, | ||
| 808 | .sema = &enum_sema, | ||
| 809 | .src_decl = new_decl, | ||
| 810 | .instructions = .{}, | ||
| 811 | .inlining = null, | ||
| 812 | .is_comptime = true, | ||
| 813 | }; | ||
| 814 | defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions | ||
| 815 | |||
| 816 | _ = try enum_sema.analyzeBody(&enum_block, body); | ||
| 817 | |||
| 818 | sema.branch_count = enum_sema.branch_count; | ||
| 819 | sema.branch_quota = enum_sema.branch_quota; | ||
| 820 | } | ||
| 821 | var extra_index: usize = body_end + bit_bags_count; | ||
| 822 | var bit_bag_index: usize = body_end; | ||
| 823 | var cur_bit_bag: u32 = undefined; | ||
| 824 | var field_i: u32 = 0; | ||
| 825 | while (field_i < fields_len) : (field_i += 1) { | ||
| 826 | if (field_i % 32 == 0) { | ||
| 827 | cur_bit_bag = sema.code.extra[bit_bag_index]; | ||
| 828 | bit_bag_index += 1; | ||
| 829 | } | ||
| 830 | const has_tag_value = @truncate(u1, cur_bit_bag) != 0; | ||
| 831 | cur_bit_bag >>= 1; | ||
| 832 | |||
| 833 | const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[extra_index]); | ||
| 834 | extra_index += 1; | ||
| 702 | 835 | ||
| 703 | return sema.mod.fail(&block.base, sema.src, "TODO implement zirEnumDecl", .{}); | 836 | // This string needs to outlive the ZIR code. |
| 837 | const field_name = try new_decl_arena.allocator.dupe(u8, field_name_zir); | ||
| 838 | |||
| 839 | const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name); | ||
| 840 | assert(!gop.found_existing); | ||
| 841 | |||
| 842 | if (has_tag_value) { | ||
| 843 | const tag_val_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | ||
| 844 | extra_index += 1; | ||
| 845 | // TODO: if we need to report an error here, use a source location | ||
| 846 | // that points to this default value expression rather than the struct. | ||
| 847 | // But only resolve the source location if we need to emit a compile error. | ||
| 848 | const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref)).val; | ||
| 849 | enum_obj.values.putAssumeCapacityNoClobber(tag_val, {}); | ||
| 850 | } else if (any_values) { | ||
| 851 | const tag_val = try Value.Tag.int_u64.create(&new_decl_arena.allocator, field_i); | ||
| 852 | enum_obj.values.putAssumeCapacityNoClobber(tag_val, {}); | ||
| 853 | } | ||
| 854 | } | ||
| 855 | |||
| 856 | return sema.analyzeDeclVal(block, src, new_decl); | ||
| 704 | } | 857 | } |
| 705 | 858 | ||
| 706 | fn zirUnionDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { | 859 | fn zirUnionDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { |
src/zir.zig+82-14| ... | @@ -1532,13 +1532,17 @@ pub const Inst = struct { | ... | @@ -1532,13 +1532,17 @@ pub const Inst = struct { |
| 1532 | }; | 1532 | }; |
| 1533 | 1533 | ||
| 1534 | /// Trailing: | 1534 | /// Trailing: |
| 1535 | /// 0. has_bits: u32 // for every 32 fields | 1535 | /// 0. inst: Index // for every body_len |
| 1536 | /// 1. has_bits: u32 // for every 32 fields | ||
| 1536 | /// - the bit is whether corresponding field has an value expression | 1537 | /// - the bit is whether corresponding field has an value expression |
| 1537 | /// 1. field_name: u32 // for every field: null terminated string index | 1538 | /// 2. fields: { // for every fields_len |
| 1538 | /// 2. value: Ref // for every field for which corresponding bit is set | 1539 | /// field_name: u32, |
| 1540 | /// value: Ref, // if corresponding bit is set | ||
| 1541 | /// } | ||
| 1539 | pub const EnumDecl = struct { | 1542 | pub const EnumDecl = struct { |
| 1540 | /// Can be `Ref.none`. | 1543 | /// Can be `Ref.none`. |
| 1541 | tag_type: Ref, | 1544 | tag_type: Ref, |
| 1545 | body_len: u32, | ||
| 1542 | fields_len: u32, | 1546 | fields_len: u32, |
| 1543 | }; | 1547 | }; |
| 1544 | 1548 | ||
| ... | @@ -1704,8 +1708,6 @@ const Writer = struct { | ... | @@ -1704,8 +1708,6 @@ const Writer = struct { |
| 1704 | .slice_end, | 1708 | .slice_end, |
| 1705 | .slice_sentinel, | 1709 | .slice_sentinel, |
| 1706 | .union_decl, | 1710 | .union_decl, |
| 1707 | .enum_decl, | ||
| 1708 | .enum_decl_nonexhaustive, | ||
| 1709 | .struct_init, | 1711 | .struct_init, |
| 1710 | .field_type, | 1712 | .field_type, |
| 1711 | => try self.writePlNode(stream, inst), | 1713 | => try self.writePlNode(stream, inst), |
| ... | @@ -1761,6 +1763,10 @@ const Writer = struct { | ... | @@ -1761,6 +1763,10 @@ const Writer = struct { |
| 1761 | .struct_decl_extern, | 1763 | .struct_decl_extern, |
| 1762 | => try self.writeStructDecl(stream, inst), | 1764 | => try self.writeStructDecl(stream, inst), |
| 1763 | 1765 | ||
| 1766 | .enum_decl, | ||
| 1767 | .enum_decl_nonexhaustive, | ||
| 1768 | => try self.writeEnumDecl(stream, inst), | ||
| 1769 | |||
| 1764 | .switch_block => try self.writePlNodeSwitchBr(stream, inst, .none), | 1770 | .switch_block => try self.writePlNodeSwitchBr(stream, inst, .none), |
| 1765 | .switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), | 1771 | .switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"), |
| 1766 | .switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under), | 1772 | .switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under), |
| ... | @@ -2031,7 +2037,7 @@ const Writer = struct { | ... | @@ -2031,7 +2037,7 @@ const Writer = struct { |
| 2031 | 2037 | ||
| 2032 | const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable; | 2038 | const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable; |
| 2033 | const body_end = extra.end + body.len; | 2039 | const body_end = extra.end + body.len; |
| 2034 | var field_index: usize = body_end + bit_bags_count; | 2040 | var extra_index: usize = body_end + bit_bags_count; |
| 2035 | var bit_bag_index: usize = body_end; | 2041 | var bit_bag_index: usize = body_end; |
| 2036 | var cur_bit_bag: u32 = undefined; | 2042 | var cur_bit_bag: u32 = undefined; |
| 2037 | var field_i: u32 = 0; | 2043 | var field_i: u32 = 0; |
| ... | @@ -2045,26 +2051,26 @@ const Writer = struct { | ... | @@ -2045,26 +2051,26 @@ const Writer = struct { |
| 2045 | const has_default = @truncate(u1, cur_bit_bag) != 0; | 2051 | const has_default = @truncate(u1, cur_bit_bag) != 0; |
| 2046 | cur_bit_bag >>= 1; | 2052 | cur_bit_bag >>= 1; |
| 2047 | 2053 | ||
| 2048 | const field_name = self.code.nullTerminatedString(self.code.extra[field_index]); | 2054 | const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); |
| 2049 | field_index += 1; | 2055 | extra_index += 1; |
| 2050 | const field_type = @intToEnum(Inst.Ref, self.code.extra[field_index]); | 2056 | const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]); |
| 2051 | field_index += 1; | 2057 | extra_index += 1; |
| 2052 | 2058 | ||
| 2053 | try stream.writeByteNTimes(' ', self.indent); | 2059 | try stream.writeByteNTimes(' ', self.indent); |
| 2054 | try stream.print("{}: ", .{std.zig.fmtId(field_name)}); | 2060 | try stream.print("{}: ", .{std.zig.fmtId(field_name)}); |
| 2055 | try self.writeInstRef(stream, field_type); | 2061 | try self.writeInstRef(stream, field_type); |
| 2056 | 2062 | ||
| 2057 | if (has_align) { | 2063 | if (has_align) { |
| 2058 | const align_ref = @intToEnum(Inst.Ref, self.code.extra[field_index]); | 2064 | const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); |
| 2059 | field_index += 1; | 2065 | extra_index += 1; |
| 2060 | 2066 | ||
| 2061 | try stream.writeAll(" align("); | 2067 | try stream.writeAll(" align("); |
| 2062 | try self.writeInstRef(stream, align_ref); | 2068 | try self.writeInstRef(stream, align_ref); |
| 2063 | try stream.writeAll(")"); | 2069 | try stream.writeAll(")"); |
| 2064 | } | 2070 | } |
| 2065 | if (has_default) { | 2071 | if (has_default) { |
| 2066 | const default_ref = @intToEnum(Inst.Ref, self.code.extra[field_index]); | 2072 | const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); |
| 2067 | field_index += 1; | 2073 | extra_index += 1; |
| 2068 | 2074 | ||
| 2069 | try stream.writeAll(" = "); | 2075 | try stream.writeAll(" = "); |
| 2070 | try self.writeInstRef(stream, default_ref); | 2076 | try self.writeInstRef(stream, default_ref); |
| ... | @@ -2078,6 +2084,68 @@ const Writer = struct { | ... | @@ -2078,6 +2084,68 @@ const Writer = struct { |
| 2078 | try self.writeSrc(stream, inst_data.src()); | 2084 | try self.writeSrc(stream, inst_data.src()); |
| 2079 | } | 2085 | } |
| 2080 | 2086 | ||
| 2087 | fn writeEnumDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void { | ||
| 2088 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | ||
| 2089 | const extra = self.code.extraData(Inst.EnumDecl, inst_data.payload_index); | ||
| 2090 | const body = self.code.extra[extra.end..][0..extra.data.body_len]; | ||
| 2091 | const fields_len = extra.data.fields_len; | ||
| 2092 | const tag_ty_ref = extra.data.tag_type; | ||
| 2093 | |||
| 2094 | if (tag_ty_ref != .none) { | ||
| 2095 | try self.writeInstRef(stream, tag_ty_ref); | ||
| 2096 | try stream.writeAll(", "); | ||
| 2097 | } | ||
| 2098 | |||
| 2099 | if (fields_len == 0) { | ||
| 2100 | assert(body.len == 0); | ||
| 2101 | try stream.writeAll("{}, {}) "); | ||
| 2102 | try self.writeSrc(stream, inst_data.src()); | ||
| 2103 | return; | ||
| 2104 | } | ||
| 2105 | |||
| 2106 | try stream.writeAll("{\n"); | ||
| 2107 | self.indent += 2; | ||
| 2108 | try self.writeBody(stream, body); | ||
| 2109 | |||
| 2110 | try stream.writeByteNTimes(' ', self.indent - 2); | ||
| 2111 | try stream.writeAll("}, {\n"); | ||
| 2112 | |||
| 2113 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | ||
| 2114 | const body_end = extra.end + body.len; | ||
| 2115 | var extra_index: usize = body_end + bit_bags_count; | ||
| 2116 | var bit_bag_index: usize = body_end; | ||
| 2117 | var cur_bit_bag: u32 = undefined; | ||
| 2118 | var field_i: u32 = 0; | ||
| 2119 | while (field_i < fields_len) : (field_i += 1) { | ||
| 2120 | if (field_i % 32 == 0) { | ||
| 2121 | cur_bit_bag = self.code.extra[bit_bag_index]; | ||
| 2122 | bit_bag_index += 1; | ||
| 2123 | } | ||
| 2124 | const has_tag_value = @truncate(u1, cur_bit_bag) != 0; | ||
| 2125 | cur_bit_bag >>= 1; | ||
| 2126 | |||
| 2127 | const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); | ||
| 2128 | extra_index += 1; | ||
| 2129 | |||
| 2130 | try stream.writeByteNTimes(' ', self.indent); | ||
| 2131 | try stream.print("{}", .{std.zig.fmtId(field_name)}); | ||
| 2132 | |||
| 2133 | if (has_tag_value) { | ||
| 2134 | const tag_value_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); | ||
| 2135 | extra_index += 1; | ||
| 2136 | |||
| 2137 | try stream.writeAll(" = "); | ||
| 2138 | try self.writeInstRef(stream, tag_value_ref); | ||
| 2139 | } | ||
| 2140 | try stream.writeAll(",\n"); | ||
| 2141 | } | ||
| 2142 | |||
| 2143 | self.indent -= 2; | ||
| 2144 | try stream.writeByteNTimes(' ', self.indent); | ||
| 2145 | try stream.writeAll("}) "); | ||
| 2146 | try self.writeSrc(stream, inst_data.src()); | ||
| 2147 | } | ||
| 2148 | |||
| 2081 | fn writePlNodeSwitchBr( | 2149 | fn writePlNodeSwitchBr( |
| 2082 | self: *Writer, | 2150 | self: *Writer, |
| 2083 | stream: anytype, | 2151 | stream: anytype, |