authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-20 21:48:18-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-20 21:48:18-07:00
loga1ac2b95bb9d6b98c6ae862bda31c84721b92bf3
treecd9950e6537f8538df8126f6c826309d1d99a5db
parent971f3d95f907fe438b0531df2f0c9f2a5471271d

AstGen: implement union decls


3 files changed, 409 insertions(+), 22 deletions(-)

src/AstGen.zig+260-7
...@@ -1703,6 +1703,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner...@@ -1703,6 +1703,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
1703 .struct_decl_packed,1703 .struct_decl_packed,
1704 .struct_decl_extern,1704 .struct_decl_extern,
1705 .union_decl,1705 .union_decl,
1706 .union_decl_packed,
1707 .union_decl_extern,
1706 .enum_decl,1708 .enum_decl,
1707 .enum_decl_nonexhaustive,1709 .enum_decl_nonexhaustive,
1708 .opaque_decl,1710 .opaque_decl,
...@@ -2897,7 +2899,7 @@ fn structDeclInner(...@@ -2897,7 +2899,7 @@ fn structDeclInner(
2897 if (member.comptime_token) |comptime_token| {2899 if (member.comptime_token) |comptime_token| {
2898 return astgen.failTok(comptime_token, "TODO implement comptime struct fields", .{});2900 return astgen.failTok(comptime_token, "TODO implement comptime struct fields", .{});
2899 }2901 }
2900 try fields_data.ensureCapacity(gpa, fields_data.items.len + 4);2902 try fields_data.ensureUnusedCapacity(gpa, 4);
29012903
2902 const field_name = try gz.identAsString(member.ast.name_token);2904 const field_name = try gz.identAsString(member.ast.name_token);
2903 fields_data.appendAssumeCapacity(field_name);2905 fields_data.appendAssumeCapacity(field_name);
...@@ -2969,6 +2971,229 @@ fn structDeclInner(...@@ -2969,6 +2971,229 @@ fn structDeclInner(
2969 return gz.indexToRef(decl_inst);2971 return gz.indexToRef(decl_inst);
2970}2972}
29712973
2974fn unionDeclInner(
2975 gz: *GenZir,
2976 scope: *Scope,
2977 node: ast.Node.Index,
2978 members: []const ast.Node.Index,
2979 tag: Zir.Inst.Tag,
2980 arg_inst: Zir.Inst.Ref,
2981 have_auto_enum: bool,
2982) InnerError!Zir.Inst.Ref {
2983 const astgen = gz.astgen;
2984 const gpa = astgen.gpa;
2985 const tree = &astgen.file.tree;
2986 const node_tags = tree.nodes.items(.tag);
2987 const node_datas = tree.nodes.items(.data);
2988
2989 // The union_decl instruction introduces a scope in which the decls of the union
2990 // are in scope, so that field types, alignments, and default value expressions
2991 // can refer to decls within the union itself.
2992 var block_scope: GenZir = .{
2993 .parent = scope,
2994 .decl_node_index = node,
2995 .astgen = astgen,
2996 .force_comptime = true,
2997 .ref_start_index = gz.ref_start_index,
2998 };
2999 defer block_scope.instructions.deinit(gpa);
3000
3001 var wip_decls: WipDecls = .{};
3002 defer wip_decls.deinit(gpa);
3003
3004 // We don't know which members are fields until we iterate, so cannot do
3005 // an accurate ensureCapacity yet.
3006 var fields_data = ArrayListUnmanaged(u32){};
3007 defer fields_data.deinit(gpa);
3008
3009 const bits_per_field = 4;
3010 const fields_per_u32 = 32 / bits_per_field;
3011 // We only need this if there are greater than fields_per_u32 fields.
3012 var bit_bag = ArrayListUnmanaged(u32){};
3013 defer bit_bag.deinit(gpa);
3014
3015 var cur_bit_bag: u32 = 0;
3016 var field_index: usize = 0;
3017 for (members) |member_node| {
3018 const member = switch (node_tags[member_node]) {
3019 .container_field_init => tree.containerFieldInit(member_node),
3020 .container_field_align => tree.containerFieldAlign(member_node),
3021 .container_field => tree.containerField(member_node),
3022
3023 .fn_decl => {
3024 const fn_proto = node_datas[member_node].lhs;
3025 const body = node_datas[member_node].rhs;
3026 switch (node_tags[fn_proto]) {
3027 .fn_proto_simple => {
3028 var params: [1]ast.Node.Index = undefined;
3029 try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoSimple(&params, fn_proto));
3030 continue;
3031 },
3032 .fn_proto_multi => {
3033 try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoMulti(fn_proto));
3034 continue;
3035 },
3036 .fn_proto_one => {
3037 var params: [1]ast.Node.Index = undefined;
3038 try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoOne(&params, fn_proto));
3039 continue;
3040 },
3041 .fn_proto => {
3042 try astgen.fnDecl(gz, &wip_decls, body, tree.fnProto(fn_proto));
3043 continue;
3044 },
3045 else => unreachable,
3046 }
3047 },
3048 .fn_proto_simple => {
3049 var params: [1]ast.Node.Index = undefined;
3050 try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoSimple(&params, member_node));
3051 continue;
3052 },
3053 .fn_proto_multi => {
3054 try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoMulti(member_node));
3055 continue;
3056 },
3057 .fn_proto_one => {
3058 var params: [1]ast.Node.Index = undefined;
3059 try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoOne(&params, member_node));
3060 continue;
3061 },
3062 .fn_proto => {
3063 try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProto(member_node));
3064 continue;
3065 },
3066
3067 .global_var_decl => {
3068 try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.globalVarDecl(member_node));
3069 continue;
3070 },
3071 .local_var_decl => {
3072 try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.localVarDecl(member_node));
3073 continue;
3074 },
3075 .simple_var_decl => {
3076 try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.simpleVarDecl(member_node));
3077 continue;
3078 },
3079 .aligned_var_decl => {
3080 try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.alignedVarDecl(member_node));
3081 continue;
3082 },
3083
3084 .@"comptime" => {
3085 try astgen.comptimeDecl(gz, scope, member_node);
3086 continue;
3087 },
3088 .@"usingnamespace" => {
3089 try astgen.usingnamespaceDecl(gz, scope, member_node);
3090 continue;
3091 },
3092 .test_decl => {
3093 try astgen.testDecl(gz, scope, member_node);
3094 continue;
3095 },
3096 else => unreachable,
3097 };
3098 if (field_index % fields_per_u32 == 0 and field_index != 0) {
3099 try bit_bag.append(gpa, cur_bit_bag);
3100 cur_bit_bag = 0;
3101 }
3102 if (member.comptime_token) |comptime_token| {
3103 return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{});
3104 }
3105 try fields_data.ensureUnusedCapacity(gpa, 4);
3106
3107 const field_name = try gz.identAsString(member.ast.name_token);
3108 fields_data.appendAssumeCapacity(field_name);
3109
3110 const have_type = member.ast.type_expr != 0;
3111 const have_align = member.ast.align_expr != 0;
3112 const have_value = member.ast.value_expr != 0;
3113 cur_bit_bag = (cur_bit_bag >> bits_per_field) |
3114 (@as(u32, @boolToInt(have_type)) << 28) |
3115 (@as(u32, @boolToInt(have_align)) << 29) |
3116 (@as(u32, @boolToInt(have_value)) << 30) |
3117 (@as(u32, @boolToInt(have_auto_enum)) << 31);
3118
3119 if (have_type) {
3120 const field_type = try typeExpr(&block_scope, &block_scope.base, member.ast.type_expr);
3121 fields_data.appendAssumeCapacity(@enumToInt(field_type));
3122 }
3123 if (have_align) {
3124 const align_inst = try expr(&block_scope, &block_scope.base, .{ .ty = .u32_type }, member.ast.align_expr);
3125 fields_data.appendAssumeCapacity(@enumToInt(align_inst));
3126 }
3127 if (have_value) {
3128 if (arg_inst == .none) {
3129 return astgen.failNodeNotes(
3130 node,
3131 "explicitly valued tagged union missing integer tag type",
3132 .{},
3133 &[_]u32{
3134 try astgen.errNoteNode(
3135 member.ast.value_expr,
3136 "tag value specified here",
3137 .{},
3138 ),
3139 },
3140 );
3141 }
3142 const tag_value = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr);
3143 fields_data.appendAssumeCapacity(@enumToInt(tag_value));
3144 }
3145
3146 field_index += 1;
3147 }
3148 if (field_index == 0) {
3149 return astgen.failNode(node, "union declarations must have at least one tag", .{});
3150 }
3151 {
3152 const empty_slot_count = fields_per_u32 - (field_index % fields_per_u32);
3153 if (empty_slot_count < fields_per_u32) {
3154 cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_field);
3155 }
3156 }
3157 {
3158 const empty_slot_count = 16 - (wip_decls.decl_index % 16);
3159 if (empty_slot_count < 16) {
3160 wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
3161 }
3162 }
3163
3164 const decl_inst = try gz.addBlock(tag, node);
3165 try gz.instructions.append(gpa, decl_inst);
3166 if (block_scope.instructions.items.len != 0) {
3167 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
3168 }
3169
3170 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len +
3171 bit_bag.items.len + 1 + fields_data.items.len +
3172 block_scope.instructions.items.len +
3173 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
3174 wip_decls.name_and_value.items.len);
3175 const zir_datas = astgen.instructions.items(.data);
3176 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{
3177 .tag_type = arg_inst,
3178 .body_len = @intCast(u32, block_scope.instructions.items.len),
3179 .fields_len = @intCast(u32, field_index),
3180 .decls_len = @intCast(u32, wip_decls.decl_index),
3181 });
3182 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
3183
3184 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
3185 astgen.extra.appendAssumeCapacity(cur_bit_bag);
3186 astgen.extra.appendSliceAssumeCapacity(fields_data.items);
3187
3188 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
3189 if (wip_decls.decl_index != 0) {
3190 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
3191 }
3192 astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items);
3193
3194 return gz.indexToRef(decl_inst);
3195}
3196
2972fn containerDecl(3197fn containerDecl(
2973 gz: *GenZir,3198 gz: *GenZir,
2974 scope: *Scope,3199 scope: *Scope,
...@@ -3005,7 +3230,18 @@ fn containerDecl(...@@ -3005,7 +3230,18 @@ fn containerDecl(
3005 return rvalue(gz, scope, rl, result, node);3230 return rvalue(gz, scope, rl, result, node);
3006 },3231 },
3007 .keyword_union => {3232 .keyword_union => {
3008 return astgen.failTok(container_decl.ast.main_token, "TODO AstGen for union decl", .{});3233 const tag = if (container_decl.layout_token) |t| switch (token_tags[t]) {
3234 .keyword_packed => Zir.Inst.Tag.union_decl_packed,
3235 .keyword_extern => Zir.Inst.Tag.union_decl_extern,
3236 else => unreachable,
3237 } else Zir.Inst.Tag.union_decl;
3238
3239 // See `Zir.Inst.UnionDecl` doc comments for why this is stored along
3240 // with fields instead of separately.
3241 const have_auto_enum = container_decl.ast.enum_token != null;
3242
3243 const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, tag, arg_inst, have_auto_enum);
3244 return rvalue(gz, scope, rl, result, node);
3009 },3245 },
3010 .keyword_enum => {3246 .keyword_enum => {
3011 if (container_decl.layout_token) |t| {3247 if (container_decl.layout_token) |t| {
...@@ -3224,6 +3460,20 @@ fn containerDecl(...@@ -3224,6 +3460,20 @@ fn containerDecl(
3224 (@as(u32, @boolToInt(have_value)) << 31);3460 (@as(u32, @boolToInt(have_value)) << 31);
32253461
3226 if (have_value) {3462 if (have_value) {
3463 if (arg_inst == .none) {
3464 return astgen.failNodeNotes(
3465 node,
3466 "explicitly valued enum missing integer tag type",
3467 .{},
3468 &[_]u32{
3469 try astgen.errNoteNode(
3470 member.ast.value_expr,
3471 "tag value specified here",
3472 .{},
3473 ),
3474 },
3475 );
3476 }
3227 const tag_value_inst = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr);3477 const tag_value_inst = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr);
3228 fields_data.appendAssumeCapacity(@enumToInt(tag_value_inst));3478 fields_data.appendAssumeCapacity(@enumToInt(tag_value_inst));
3229 }3479 }
...@@ -3232,12 +3482,15 @@ fn containerDecl(...@@ -3232,12 +3482,15 @@ fn containerDecl(
3232 }3482 }
3233 {3483 {
3234 const empty_slot_count = 32 - (field_index % 32);3484 const empty_slot_count = 32 - (field_index % 32);
3235 cur_bit_bag >>= @intCast(u5, empty_slot_count);3485 if (empty_slot_count < 32) {
3486 cur_bit_bag >>= @intCast(u5, empty_slot_count);
3487 }
3236 }3488 }
32373489 {
3238 if (wip_decls.decl_index != 0) {
3239 const empty_slot_count = 16 - (wip_decls.decl_index % 16);3490 const empty_slot_count = 16 - (wip_decls.decl_index % 16);
3240 wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);3491 if (empty_slot_count < 16) {
3492 wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
3493 }
3241 }3494 }
32423495
3243 const decl_inst = try gz.addBlock(tag, node);3496 const decl_inst = try gz.addBlock(tag, node);
...@@ -4789,7 +5042,7 @@ fn switchExpr(...@@ -4789,7 +5042,7 @@ fn switchExpr(
4789 .prong_index = capture_index,5042 .prong_index = capture_index,
4790 } },5043 } },
4791 });5044 });
4792 const capture_name = try astgen.identifierTokenString(payload_token);5045 const capture_name = try astgen.identifierTokenString(ident);
4793 capture_val_scope = .{5046 capture_val_scope = .{
4794 .parent = &case_scope.base,5047 .parent = &case_scope.base,
4795 .gen_zir = &case_scope,5048 .gen_zir = &case_scope,
src/Sema.zig+9-2
...@@ -338,7 +338,9 @@ pub fn analyzeBody(...@@ -338,7 +338,9 @@ pub fn analyzeBody(
338 .struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern),338 .struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern),
339 .enum_decl => try sema.zirEnumDecl(block, inst, false),339 .enum_decl => try sema.zirEnumDecl(block, inst, false),
340 .enum_decl_nonexhaustive => try sema.zirEnumDecl(block, inst, true),340 .enum_decl_nonexhaustive => try sema.zirEnumDecl(block, inst, true),
341 .union_decl => try sema.zirUnionDecl(block, inst),341 .union_decl => try sema.zirUnionDecl(block, inst, .Auto),
342 .union_decl_packed => try sema.zirUnionDecl(block, inst, .Packed),
343 .union_decl_extern => try sema.zirUnionDecl(block, inst, .Extern),
342 .opaque_decl => try sema.zirOpaqueDecl(block, inst),344 .opaque_decl => try sema.zirOpaqueDecl(block, inst),
343 .error_set_decl => try sema.zirErrorSetDecl(block, inst),345 .error_set_decl => try sema.zirErrorSetDecl(block, inst),
344346
...@@ -980,7 +982,12 @@ fn zirEnumDecl(...@@ -980,7 +982,12 @@ fn zirEnumDecl(
980 return sema.analyzeDeclVal(block, src, new_decl);982 return sema.analyzeDeclVal(block, src, new_decl);
981}983}
982984
983fn zirUnionDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {985fn zirUnionDecl(
986 sema: *Sema,
987 block: *Scope.Block,
988 inst: Zir.Inst.Index,
989 layout: std.builtin.TypeInfo.ContainerLayout,
990) InnerError!*Inst {
984 const tracy = trace(@src());991 const tracy = trace(@src());
985 defer tracy.end();992 defer tracy.end();
986993
src/Zir.zig+140-13
...@@ -301,6 +301,10 @@ pub const Inst = struct {...@@ -301,6 +301,10 @@ pub const Inst = struct {
301 /// the field types and optional type tag expression.301 /// the field types and optional type tag expression.
302 /// Uses the `pl_node` union field. Payload is `UnionDecl`.302 /// Uses the `pl_node` union field. Payload is `UnionDecl`.
303 union_decl,303 union_decl,
304 /// Same as `union_decl`, except has the `packed` layout.
305 union_decl_packed,
306 /// Same as `union_decl`, except has the `extern` layout.
307 union_decl_extern,
304 /// An enum type definition. Contains references to ZIR instructions for308 /// An enum type definition. Contains references to ZIR instructions for
305 /// the field value expressions and optional type tag expression.309 /// the field value expressions and optional type tag expression.
306 /// Uses the `pl_node` union field. Payload is `EnumDecl`.310 /// Uses the `pl_node` union field. Payload is `EnumDecl`.
...@@ -988,6 +992,8 @@ pub const Inst = struct {...@@ -988,6 +992,8 @@ pub const Inst = struct {
988 .struct_decl_packed,992 .struct_decl_packed,
989 .struct_decl_extern,993 .struct_decl_extern,
990 .union_decl,994 .union_decl,
995 .union_decl_packed,
996 .union_decl_extern,
991 .enum_decl,997 .enum_decl,
992 .enum_decl_nonexhaustive,998 .enum_decl_nonexhaustive,
993 .opaque_decl,999 .opaque_decl,
...@@ -2022,19 +2028,37 @@ pub const Inst = struct {...@@ -2022,19 +2028,37 @@ pub const Inst = struct {
2022 };2028 };
20232029
2024 /// Trailing:2030 /// Trailing:
2025 /// 0. has_bits: u32 // for every 10 fields (+1)2031 /// 0. inst: Index // for every body_len
2026 /// - first bit is special: set if and only if auto enum tag is enabled.2032 /// 1. has_bits: u32 // for every 8 fields
2027 /// - sets of 3 bits:2033 /// - sets of 4 bits:
2028 /// 0b00X: whether corresponding field has a type expression2034 /// 0b000X: whether corresponding field has a type expression
2029 /// 0b0X0: whether corresponding field has a align expression2035 /// 0b00X0: whether corresponding field has a align expression
2030 /// 0bX00: whether corresponding field has a tag value expression2036 /// 0b0X00: whether corresponding field has a tag value expression
2031 /// 1. field_name: u32 // for every field: null terminated string index2037 /// 0bX000: unused(*)
2032 /// 2. opt_exprs // Ref for every field for which corresponding bit is set2038 /// * the first unused bit (the unused bit of the first field) is used
2033 /// - interleaved. type if present, align if present, tag value if present.2039 /// to indicate whether auto enum tag is enabled.
2040 /// 0 = union(tag_type)
2041 /// 1 = union(enum(tag_type))
2042 /// 2. fields: { // for every fields_len
2043 /// field_name: u32, // null terminated string index
2044 /// field_type: Ref, // if corresponding bit is set
2045 /// align: Ref, // if corresponding bit is set
2046 /// tag_value: Ref, // if corresponding bit is set
2047 /// }
2048 /// 3. decl_bits: u32 // for every 16 decls
2049 /// - sets of 2 bits:
2050 /// 0b0X: whether corresponding decl is pub
2051 /// 0bX0: whether corresponding decl is exported
2052 /// 4. decl: { // for every decls_len
2053 /// name: u32, // null terminated string index
2054 /// value: Index,
2055 /// }
2034 pub const UnionDecl = struct {2056 pub const UnionDecl = struct {
2035 /// Can be `Ref.none`.2057 /// Can be `Ref.none`.
2036 tag_type: Ref,2058 tag_type: Ref,
2059 body_len: u32,
2037 fields_len: u32,2060 fields_len: u32,
2061 decls_len: u32,
2038 };2062 };
20392063
2040 /// Trailing: field_name: u32 // for every field: null terminated string index2064 /// Trailing: field_name: u32 // for every field: null terminated string index
...@@ -2339,7 +2363,6 @@ const Writer = struct {...@@ -2339,7 +2363,6 @@ const Writer = struct {
2339 .slice_start,2363 .slice_start,
2340 .slice_end,2364 .slice_end,
2341 .slice_sentinel,2365 .slice_sentinel,
2342 .union_decl,
2343 .struct_init,2366 .struct_init,
2344 .struct_init_anon,2367 .struct_init_anon,
2345 .array_init,2368 .array_init,
...@@ -2452,6 +2475,11 @@ const Writer = struct {...@@ -2452,6 +2475,11 @@ const Writer = struct {
2452 .struct_decl_extern,2475 .struct_decl_extern,
2453 => try self.writeStructDecl(stream, inst),2476 => try self.writeStructDecl(stream, inst),
24542477
2478 .union_decl,
2479 .union_decl_packed,
2480 .union_decl_extern,
2481 => try self.writeUnionDecl(stream, inst),
2482
2455 .enum_decl,2483 .enum_decl,
2456 .enum_decl_nonexhaustive,2484 .enum_decl_nonexhaustive,
2457 => try self.writeEnumDecl(stream, inst),2485 => try self.writeEnumDecl(stream, inst),
...@@ -2884,6 +2912,105 @@ const Writer = struct {...@@ -2884,6 +2912,105 @@ const Writer = struct {
2884 try self.writeSrc(stream, inst_data.src());2912 try self.writeSrc(stream, inst_data.src());
2885 }2913 }
28862914
2915 fn writeUnionDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2916 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2917 const extra = self.code.extraData(Inst.UnionDecl, inst_data.payload_index);
2918 const body = self.code.extra[extra.end..][0..extra.data.body_len];
2919 const fields_len = extra.data.fields_len;
2920 const decls_len = extra.data.decls_len;
2921 const tag_type_ref = extra.data.tag_type;
2922
2923 assert(fields_len != 0);
2924 var first_has_auto_enum: ?bool = null;
2925
2926 if (tag_type_ref != .none) {
2927 try self.writeInstRef(stream, tag_type_ref);
2928 try stream.writeAll(", ");
2929 }
2930
2931 var extra_index: usize = undefined;
2932
2933 try stream.writeAll("{\n");
2934 self.indent += 2;
2935 try self.writeBody(stream, body);
2936
2937 try stream.writeByteNTimes(' ', self.indent - 2);
2938 try stream.writeAll("}, {\n");
2939
2940 const bits_per_field = 4;
2941 const fields_per_u32 = 32 / bits_per_field;
2942 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
2943 const body_end = extra.end + body.len;
2944 extra_index = body_end + bit_bags_count;
2945 var bit_bag_index: usize = body_end;
2946 var cur_bit_bag: u32 = undefined;
2947 var field_i: u32 = 0;
2948 while (field_i < fields_len) : (field_i += 1) {
2949 if (field_i % fields_per_u32 == 0) {
2950 cur_bit_bag = self.code.extra[bit_bag_index];
2951 bit_bag_index += 1;
2952 }
2953 const has_type = @truncate(u1, cur_bit_bag) != 0;
2954 cur_bit_bag >>= 1;
2955 const has_align = @truncate(u1, cur_bit_bag) != 0;
2956 cur_bit_bag >>= 1;
2957 const has_value = @truncate(u1, cur_bit_bag) != 0;
2958 cur_bit_bag >>= 1;
2959 const has_auto_enum = @truncate(u1, cur_bit_bag) != 0;
2960 cur_bit_bag >>= 1;
2961
2962 if (first_has_auto_enum == null) {
2963 first_has_auto_enum = has_auto_enum;
2964 }
2965
2966 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
2967 extra_index += 1;
2968 try stream.writeByteNTimes(' ', self.indent);
2969 try stream.print("{}", .{std.zig.fmtId(field_name)});
2970
2971 if (has_type) {
2972 const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2973 extra_index += 1;
2974
2975 try stream.writeAll(": ");
2976 try self.writeInstRef(stream, field_type);
2977 }
2978 if (has_align) {
2979 const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2980 extra_index += 1;
2981
2982 try stream.writeAll(" align(");
2983 try self.writeInstRef(stream, align_ref);
2984 try stream.writeAll(")");
2985 }
2986 if (has_value) {
2987 const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2988 extra_index += 1;
2989
2990 try stream.writeAll(" = ");
2991 try self.writeInstRef(stream, default_ref);
2992 }
2993 try stream.writeAll(",\n");
2994 }
2995
2996 self.indent -= 2;
2997 try stream.writeByteNTimes(' ', self.indent);
2998 try stream.writeAll("}, {");
2999 if (decls_len == 0) {
3000 try stream.writeAll("}");
3001 } else {
3002 try stream.writeAll("\n");
3003 self.indent += 2;
3004 try self.writeDecls(stream, decls_len, extra_index);
3005 self.indent -= 2;
3006 try stream.writeByteNTimes(' ', self.indent);
3007 try stream.writeAll("}");
3008 }
3009 try self.writeFlag(stream, ", autoenum", first_has_auto_enum.?);
3010 try stream.writeAll(") ");
3011 try self.writeSrc(stream, inst_data.src());
3012 }
3013
2887 fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !void {3014 fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !void {
2888 const parent_decl_node = self.parent_decl_node;3015 const parent_decl_node = self.parent_decl_node;
2889 const bit_bags_count = std.math.divCeil(usize, decls_len, 16) catch unreachable;3016 const bit_bags_count = std.math.divCeil(usize, decls_len, 16) catch unreachable;
...@@ -2930,10 +3057,10 @@ const Writer = struct {...@@ -2930,10 +3057,10 @@ const Writer = struct {
2930 const body = self.code.extra[extra.end..][0..extra.data.body_len];3057 const body = self.code.extra[extra.end..][0..extra.data.body_len];
2931 const fields_len = extra.data.fields_len;3058 const fields_len = extra.data.fields_len;
2932 const decls_len = extra.data.decls_len;3059 const decls_len = extra.data.decls_len;
2933 const tag_ty_ref = extra.data.tag_type;3060 const tag_type_ref = extra.data.tag_type;
29343061
2935 if (tag_ty_ref != .none) {3062 if (tag_type_ref != .none) {
2936 try self.writeInstRef(stream, tag_ty_ref);3063 try self.writeInstRef(stream, tag_type_ref);
2937 try stream.writeAll(", ");3064 try stream.writeAll(", ");
2938 }3065 }
29393066