authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-12 14:47:14+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:06+00:00
log5e8397d5e03269d8a39efb22605ea20102848084
treec3f0fffeff44be63f7c6691737ad0cd6510e6c76
parentcfe5c88ad6081e284d0caf36cf8d7e80fe39b676
signaturelock-open Commit is signed but in an unrecognized format.

Zir: rework container type declarations

Only AstGen and print_zir currently support the new representation, so attempting to build the compiler will emit (many) compile errors.

3 files changed, 1204 insertions(+), 1925 deletions(-)

lib/std/zig/AstGen.zig+530-1122
...@@ -3975,81 +3975,67 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node....@@ -3975,81 +3975,67 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.
3975 return rvalue(gz, ri, result, node);3975 return rvalue(gz, ri, result, node);
3976}3976}
39773977
3978const WipMembers = struct {3978const Scratch = struct {
3979 payload: *ArrayList(u32),3979 astgen: *AstGen,
3980 payload_top: usize,3980 scratch_top: u32,
3981 field_bits_start: u32,3981 fn init(astgen: *AstGen) Scratch {
3982 fields_start: u32,
3983 fields_end: u32,
3984 decl_index: u32 = 0,
3985 field_index: u32 = 0,
3986
3987 const Self = @This();
3988
3989 fn init(gpa: Allocator, payload: *ArrayList(u32), decl_count: u32, field_count: u32, comptime bits_per_field: u32, comptime max_field_size: u32) Allocator.Error!Self {
3990 const payload_top: u32 = @intCast(payload.items.len);
3991 const field_bits_start = payload_top + decl_count;
3992 const fields_start = field_bits_start + if (bits_per_field > 0) blk: {
3993 const fields_per_u32 = 32 / bits_per_field;
3994 break :blk (field_count + fields_per_u32 - 1) / fields_per_u32;
3995 } else 0;
3996 const payload_end = fields_start + field_count * max_field_size;
3997 try payload.resize(gpa, payload_end);
3998 return .{3982 return .{
3999 .payload = payload,3983 .astgen = astgen,
4000 .payload_top = payload_top,3984 .scratch_top = @intCast(astgen.scratch.items.len),
4001 .field_bits_start = field_bits_start,
4002 .fields_start = fields_start,
4003 .fields_end = fields_start,
4004 };3985 };
4005 }3986 }
40063987 fn reset(s: *Scratch) void {
4007 fn nextDecl(self: *Self, decl_inst: Zir.Inst.Index) void {3988 s.astgen.scratch.shrinkRetainingCapacity(s.scratch_top);
4008 self.payload.items[self.payload_top + self.decl_index] = @intFromEnum(decl_inst);3989 s.* = undefined;
4009 self.decl_index += 1;
4010 }3990 }
40113991 fn addSlice(s: *Scratch, len: u32) Allocator.Error!Slice {
4012 fn nextField(self: *Self, comptime bits_per_field: u32, bits: [bits_per_field]bool) void {3992 const start: u32 = @intCast(s.astgen.scratch.items.len);
4013 const fields_per_u32 = 32 / bits_per_field;3993 try s.astgen.scratch.resize(s.astgen.gpa, start + len);
4014 const index = self.field_bits_start + self.field_index / fields_per_u32;3994 return .{ .start = start, .len = len };
4015 assert(index < self.fields_start);
4016 var bit_bag: u32 = if (self.field_index % fields_per_u32 == 0) 0 else self.payload.items[index];
4017 bit_bag >>= bits_per_field;
4018 comptime var i = 0;
4019 inline while (i < bits_per_field) : (i += 1) {
4020 bit_bag |= @as(u32, @intFromBool(bits[i])) << (32 - bits_per_field + i);
4021 }
4022 self.payload.items[index] = bit_bag;
4023 self.field_index += 1;
4024 }3995 }
40253996 fn addOptionalSlice(s: *Scratch, present: bool, len: u32) Allocator.Error!?Slice {
4026 fn appendToField(self: *Self, data: u32) void {3997 if (!present) return null;
4027 assert(self.fields_end < self.payload.items.len);3998 return try addSlice(s, len);
4028 self.payload.items[self.fields_end] = data;
4029 self.fields_end += 1;
4030 }3999 }
40314000 fn appendBodyWithFixups(s: *Scratch, body: []const Zir.Inst.Index) Allocator.Error!u32 {
4032 fn finishBits(self: *Self, comptime bits_per_field: u32) void {4001 const len = countBodyLenAfterFixups(s.astgen, body);
4033 if (bits_per_field > 0) {4002 try s.astgen.scratch.ensureUnusedCapacity(s.astgen.gpa, len);
4034 const fields_per_u32 = 32 / bits_per_field;4003 appendBodyWithFixupsArrayList(s.astgen, &s.astgen.scratch, body);
4035 const empty_field_slots = fields_per_u32 - (self.field_index % fields_per_u32);4004 return len;
4036 if (self.field_index > 0 and empty_field_slots < fields_per_u32) {
4037 const index = self.field_bits_start + self.field_index / fields_per_u32;
4038 self.payload.items[index] >>= @intCast(empty_field_slots * bits_per_field);
4039 }
4040 }
4041 }4005 }
40424006 /// Returns the slice containing all data added to this `Scratch`.
4043 fn declsSlice(self: *Self) []u32 {4007 fn all(s: *Scratch) Slice {
4044 return self.payload.items[self.payload_top..][0..self.decl_index];4008 const len = s.astgen.scratch.items.len - s.scratch_top;
4009 return .{ .start = s.scratch_top, .len = @intCast(len) };
4045 }4010 }
4011 const Slice = struct {
4012 start: u32,
4013 len: u32,
4014 fn get(s: Slice, astgen: *AstGen) []u32 {
4015 return astgen.scratch.items[s.start..][0..s.len];
4016 }
4017 };
4018};
40464019
4047 fn fieldsSlice(self: *Self) []u32 {4020const WipDecls = struct {
4048 return self.payload.items[self.field_bits_start..self.fields_end];4021 astgen: *AstGen,
4049 }4022 slice: Scratch.Slice,
4023 index: u32,
40504024
4051 fn deinit(self: *Self) void {4025 fn init(scratch: *Scratch, decls_len: u32) Allocator.Error!WipDecls {
4052 self.payload.items.len = self.payload_top;4026 return .{
4027 .astgen = scratch.astgen,
4028 .slice = try scratch.addSlice(decls_len),
4029 .index = 0,
4030 };
4031 }
4032 fn finish(wip: *WipDecls) void {
4033 assert(wip.index == wip.slice.len);
4034 wip.* = undefined;
4035 }
4036 fn nextDecl(wip: *WipDecls, decl_inst: Zir.Inst.Index) void {
4037 wip.slice.get(wip.astgen)[wip.index] = @intFromEnum(decl_inst);
4038 wip.index += 1;
4053 }4039 }
4054};4040};
40554041
...@@ -4057,7 +4043,7 @@ fn fnDecl(...@@ -4057,7 +4043,7 @@ fn fnDecl(
4057 astgen: *AstGen,4043 astgen: *AstGen,
4058 gz: *GenZir,4044 gz: *GenZir,
4059 scope: *Scope,4045 scope: *Scope,
4060 wip_members: *WipMembers,4046 wip_decls: *WipDecls,
4061 decl_node: Ast.Node.Index,4047 decl_node: Ast.Node.Index,
4062 body_node: Ast.Node.OptionalIndex,4048 body_node: Ast.Node.OptionalIndex,
4063 fn_proto: Ast.full.FnProto,4049 fn_proto: Ast.full.FnProto,
...@@ -4133,7 +4119,7 @@ fn fnDecl(...@@ -4133,7 +4119,7 @@ fn fnDecl(
4133 assert(!is_extern); // validated by parser (TODO why???)4119 assert(!is_extern); // validated by parser (TODO why???)
4134 }4120 }
41354121
4136 wip_members.nextDecl(decl_inst);4122 wip_decls.nextDecl(decl_inst);
41374123
4138 var type_gz: GenZir = .{4124 var type_gz: GenZir = .{
4139 .is_comptime = true,4125 .is_comptime = true,
...@@ -4488,7 +4474,7 @@ fn globalVarDecl(...@@ -4488,7 +4474,7 @@ fn globalVarDecl(
4488 astgen: *AstGen,4474 astgen: *AstGen,
4489 gz: *GenZir,4475 gz: *GenZir,
4490 scope: *Scope,4476 scope: *Scope,
4491 wip_members: *WipMembers,4477 wip_decls: *WipDecls,
4492 node: Ast.Node.Index,4478 node: Ast.Node.Index,
4493 var_decl: Ast.full.VarDecl,4479 var_decl: Ast.full.VarDecl,
4494) InnerError!void {4480) InnerError!void {
...@@ -4533,7 +4519,7 @@ fn globalVarDecl(...@@ -4533,7 +4519,7 @@ fn globalVarDecl(
4533 const decl_column = astgen.source_column;4519 const decl_column = astgen.source_column;
45344520
4535 const decl_inst = try gz.makeDeclaration(node);4521 const decl_inst = try gz.makeDeclaration(node);
4536 wip_members.nextDecl(decl_inst);4522 wip_decls.nextDecl(decl_inst);
45374523
4538 if (var_decl.ast.init_node.unwrap()) |init_node| {4524 if (var_decl.ast.init_node.unwrap()) |init_node| {
4539 if (is_extern) {4525 if (is_extern) {
...@@ -4635,7 +4621,7 @@ fn comptimeDecl(...@@ -4635,7 +4621,7 @@ fn comptimeDecl(
4635 astgen: *AstGen,4621 astgen: *AstGen,
4636 gz: *GenZir,4622 gz: *GenZir,
4637 scope: *Scope,4623 scope: *Scope,
4638 wip_members: *WipMembers,4624 wip_decls: *WipDecls,
4639 node: Ast.Node.Index,4625 node: Ast.Node.Index,
4640) InnerError!void {4626) InnerError!void {
4641 const tree = astgen.tree;4627 const tree = astgen.tree;
...@@ -4650,7 +4636,7 @@ fn comptimeDecl(...@@ -4650,7 +4636,7 @@ fn comptimeDecl(
4650 // Up top so the ZIR instruction index marks the start range of this4636 // Up top so the ZIR instruction index marks the start range of this
4651 // top-level declaration.4637 // top-level declaration.
4652 const decl_inst = try gz.makeDeclaration(node);4638 const decl_inst = try gz.makeDeclaration(node);
4653 wip_members.nextDecl(decl_inst);4639 wip_decls.nextDecl(decl_inst);
4654 astgen.advanceSourceCursorToNode(node);4640 astgen.advanceSourceCursorToNode(node);
46554641
4656 // This is just needed for the `setDeclaration` call.4642 // This is just needed for the `setDeclaration` call.
...@@ -4698,7 +4684,7 @@ fn testDecl(...@@ -4698,7 +4684,7 @@ fn testDecl(
4698 astgen: *AstGen,4684 astgen: *AstGen,
4699 gz: *GenZir,4685 gz: *GenZir,
4700 scope: *Scope,4686 scope: *Scope,
4701 wip_members: *WipMembers,4687 wip_decls: *WipDecls,
4702 node: Ast.Node.Index,4688 node: Ast.Node.Index,
4703) InnerError!void {4689) InnerError!void {
4704 const tree = astgen.tree;4690 const tree = astgen.tree;
...@@ -4714,7 +4700,7 @@ fn testDecl(...@@ -4714,7 +4700,7 @@ fn testDecl(
4714 // top-level declaration.4700 // top-level declaration.
4715 const decl_inst = try gz.makeDeclaration(node);4701 const decl_inst = try gz.makeDeclaration(node);
47164702
4717 wip_members.nextDecl(decl_inst);4703 wip_decls.nextDecl(decl_inst);
4718 astgen.advanceSourceCursorToNode(node);4704 astgen.advanceSourceCursorToNode(node);
47194705
4720 // This is just needed for the `setDeclaration` call.4706 // This is just needed for the `setDeclaration` call.
...@@ -4914,7 +4900,7 @@ fn structDeclInner(...@@ -4914,7 +4900,7 @@ fn structDeclInner(
4914 node: Ast.Node.Index,4900 node: Ast.Node.Index,
4915 container_decl: Ast.full.ContainerDecl,4901 container_decl: Ast.full.ContainerDecl,
4916 layout: std.builtin.Type.ContainerLayout,4902 layout: std.builtin.Type.ContainerLayout,
4917 backing_int_node: Ast.Node.OptionalIndex,4903 maybe_backing_int_node: Ast.Node.OptionalIndex,
4918 name_strat: Zir.Inst.NameStrategy,4904 name_strat: Zir.Inst.NameStrategy,
4919) InnerError!Zir.Inst.Ref {4905) InnerError!Zir.Inst.Ref {
4920 const astgen = gz.astgen;4906 const astgen = gz.astgen;
...@@ -4930,27 +4916,39 @@ fn structDeclInner(...@@ -4930,27 +4916,39 @@ fn structDeclInner(
4930 if (node == .root) {4916 if (node == .root) {
4931 return astgen.failNode(tuple_field_node, "file cannot be a tuple", .{});4917 return astgen.failNode(tuple_field_node, "file cannot be a tuple", .{});
4932 } else {4918 } else {
4933 return tupleDecl(gz, scope, node, container_decl, layout, backing_int_node);4919 return tupleDecl(gz, scope, node, container_decl, layout, maybe_backing_int_node);
4934 }4920 }
4935 }4921 }
49364922
4923 astgen.advanceSourceCursorToNode(node);
4924
4925 const backing_int_type_ref: Zir.Inst.Ref = ty: {
4926 const backing_int_node = maybe_backing_int_node.unwrap() orelse break :ty .none;
4927 if (layout != .@"packed") return astgen.failNode(
4928 backing_int_node,
4929 "non-packed struct does not support backing integer type",
4930 .{},
4931 );
4932 break :ty try typeExpr(gz, scope, backing_int_node);
4933 };
4934
4937 const decl_inst = try gz.reserveInstructionIndex();4935 const decl_inst = try gz.reserveInstructionIndex();
49384936
4939 if (container_decl.ast.members.len == 0 and backing_int_node == .none) {4937 if (container_decl.ast.members.len == 0 and backing_int_type_ref == .none) {
4940 try gz.setStruct(decl_inst, .{4938 try gz.setStruct(decl_inst, .{
4941 .src_node = node,4939 .src_node = node,
4940 .name_strat = name_strat,
4942 .layout = layout,4941 .layout = layout,
4943 .captures_len = 0,4942 .backing_int_type = .none,
4944 .fields_len = 0,
4945 .decls_len = 0,4943 .decls_len = 0,
4946 .has_backing_int = false,4944 .fields_len = 0,
4947 .known_non_opv = false,4945 .any_field_aligns = false,
4948 .known_comptime_only = false,4946 .any_field_defaults = false,
4949 .any_comptime_fields = false,4947 .any_comptime_fields = false,
4950 .any_default_inits = false,4948 .fields_hash = @splat(0),
4951 .any_aligned_fields = false,4949 .captures = &.{},
4952 .fields_hash = std.zig.hashSrc(@tagName(layout)),4950 .capture_names = &.{},
4953 .name_strat = name_strat,4951 .remaining = &.{},
4954 });4952 });
4955 return decl_inst.toRef();4953 return decl_inst.toRef();
4956 }4954 }
...@@ -4967,7 +4965,6 @@ fn structDeclInner(...@@ -4967,7 +4965,6 @@ fn structDeclInner(
4967 // The struct_decl instruction introduces a scope in which the decls of the struct4965 // The struct_decl instruction introduces a scope in which the decls of the struct
4968 // are in scope, so that field types, alignments, and default value expressions4966 // are in scope, so that field types, alignments, and default value expressions
4969 // can refer to decls within the struct itself.4967 // can refer to decls within the struct itself.
4970 astgen.advanceSourceCursorToNode(node);
4971 var block_scope: GenZir = .{4968 var block_scope: GenZir = .{
4972 .parent = &namespace.base,4969 .parent = &namespace.base,
4973 .decl_node_index = node,4970 .decl_node_index = node,
...@@ -4979,197 +4976,118 @@ fn structDeclInner(...@@ -4979,197 +4976,118 @@ fn structDeclInner(
4979 };4976 };
4980 defer block_scope.unstack();4977 defer block_scope.unstack();
49814978
4982 const scratch_top = astgen.scratch.items.len;4979 const scan_result = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"struct");
4983 defer astgen.scratch.items.len = scratch_top;
4984
4985 var backing_int_body_len: usize = 0;
4986 const backing_int_ref: Zir.Inst.Ref = blk: {
4987 if (backing_int_node.unwrap()) |arg| {
4988 if (layout != .@"packed") {
4989 return astgen.failNode(arg, "non-packed struct does not support backing integer type", .{});
4990 } else {
4991 const backing_int_ref = try typeExpr(&block_scope, &namespace.base, arg);
4992 if (!block_scope.isEmpty()) {
4993 if (!block_scope.endsWithNoReturn()) {
4994 _ = try block_scope.addBreak(.break_inline, decl_inst, backing_int_ref);
4995 }
4996
4997 const body = block_scope.instructionsSlice();
4998 const old_scratch_len = astgen.scratch.items.len;
4999 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
5000 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
5001 backing_int_body_len = astgen.scratch.items.len - old_scratch_len;
5002 block_scope.instructions.items.len = block_scope.instructions_top;
5003 }
5004 break :blk backing_int_ref;
5005 }
5006 } else {
5007 break :blk .none;
5008 }
5009 };
50104980
5011 const decl_count = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"struct");4981 var scratch: Scratch = .init(astgen);
5012 const field_count: u32 = @intCast(container_decl.ast.members.len - decl_count);4982 defer scratch.reset();
50134983
5014 const bits_per_field = 4;4984 // Replicate the structure of the ZIR trailing data in `scratch`
5015 const max_field_size = 5;4985 var wip_decls: WipDecls = try .init(&scratch, scan_result.decls_len);
5016 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);4986 const field_names = try scratch.addSlice(scan_result.fields_len);
5017 defer wip_members.deinit();4987 const field_type_body_lens = try scratch.addSlice(scan_result.fields_len);
50184988 const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len);
5019 // We will use the scratch buffer, starting here, for the bodies:4989 const field_default_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len);
5020 // bodies: { // for every fields_len4990 const field_comptime_bits = try scratch.addOptionalSlice(
5021 // field_type_body_inst: Inst, // for each field_type_body_len4991 scan_result.any_comptime_fields,
5022 // align_body_inst: Inst, // for each align_body_len4992 std.math.divCeil(u32, scan_result.fields_len, 32) catch unreachable,
5023 // init_body_inst: Inst, // for each init_body_len4993 );
5024 // }4994 if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0);
5025 // Note that the scratch buffer is simultaneously being used by WipMembers, however
5026 // it will not access any elements beyond this point in the ArrayList. It also
5027 // accesses via the ArrayList items field so it can handle the scratch buffer being
5028 // reallocated.
5029 // No defer needed here because it is handled by `wip_members.deinit()` above.
5030 const bodies_start = astgen.scratch.items.len;
50314995
5032 const old_hasher = astgen.src_hasher;4996 const old_hasher = astgen.src_hasher;
5033 defer astgen.src_hasher = old_hasher;4997 defer astgen.src_hasher = old_hasher;
5034 astgen.src_hasher = std.zig.SrcHasher.init(.{});4998 astgen.src_hasher = .init(.{});
5035 astgen.src_hasher.update(@tagName(layout));
5036 if (backing_int_node.unwrap()) |arg| {
5037 astgen.src_hasher.update(tree.getNodeSource(arg));
5038 }
50394999
5040 var known_non_opv = false;5000 var next_field_idx: u32 = 0;
5041 var known_comptime_only = false;
5042 var any_comptime_fields = false;
5043 var any_aligned_fields = false;
5044 var any_default_inits = false;
5045 for (container_decl.ast.members) |member_node| {5001 for (container_decl.ast.members) |member_node| {
5046 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {5002 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) {
5047 .decl => continue,5003 .decl => continue,
5048 .field => |field| field,5004 .field => |field| field,
5049 };5005 };
5006 const field_idx = next_field_idx;
5007 next_field_idx += 1;
50505008
5051 astgen.src_hasher.update(tree.getNodeSource(member_node));5009 astgen.src_hasher.update(tree.getNodeSource(member_node));
50525010
5053 const field_name = try astgen.identAsString(member.ast.main_token);
5054 member.convertToNonTupleLike(astgen.tree);5011 member.convertToNonTupleLike(astgen.tree);
5055 assert(!member.ast.tuple_like);5012 assert(!member.ast.tuple_like);
5056 wip_members.appendToField(@intFromEnum(field_name));
5057
5058 const type_expr = member.ast.type_expr.unwrap() orelse {
5059 return astgen.failTok(member.ast.main_token, "struct field missing type", .{});
5060 };
5061
5062 const field_type = try typeExpr(&block_scope, &namespace.base, type_expr);
5063 const have_type_body = !block_scope.isEmpty();
5064 const have_align = member.ast.align_expr != .none;
5065 const have_value = member.ast.value_expr != .none;
5066 const is_comptime = member.comptime_token != null;
50675013
5068 if (is_comptime) {5014 field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token));
5069 switch (layout) {
5070 .@"packed", .@"extern" => return astgen.failTok(member.comptime_token.?, "{s} struct fields cannot be marked comptime", .{@tagName(layout)}),
5071 .auto => any_comptime_fields = true,
5072 }
5073 } else {
5074 known_non_opv = known_non_opv or
5075 nodeImpliesMoreThanOnePossibleValue(tree, type_expr);
5076 known_comptime_only = known_comptime_only or
5077 nodeImpliesComptimeOnly(tree, type_expr);
5078 }
5079 wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, have_type_body });
50805015
5081 if (have_type_body) {5016 {
5017 const type_node = member.ast.type_expr.unwrap() orelse {
5018 return astgen.failTok(member.ast.main_token, "struct field missing type", .{});
5019 };
5020 const type_ref = try typeExpr(&block_scope, &namespace.base, type_node);
5082 if (!block_scope.endsWithNoReturn()) {5021 if (!block_scope.endsWithNoReturn()) {
5083 _ = try block_scope.addBreak(.break_inline, decl_inst, field_type);5022 _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
5084 }5023 }
5085 const body = block_scope.instructionsSlice();5024 const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
5086 const old_scratch_len = astgen.scratch.items.len;5025 field_type_body_lens.get(astgen)[field_idx] = body_len;
5087 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
5088 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
5089 wip_members.appendToField(@intCast(astgen.scratch.items.len - old_scratch_len));
5090 block_scope.instructions.items.len = block_scope.instructions_top;5026 block_scope.instructions.items.len = block_scope.instructions_top;
5091 } else {
5092 wip_members.appendToField(@intFromEnum(field_type));
5093 }5027 }
50945028
5095 if (member.ast.align_expr.unwrap()) |align_expr| {5029 if (member.ast.align_expr.unwrap()) |align_node| {
5096 if (layout == .@"packed") {5030 if (layout == .@"packed") {
5097 return astgen.failNode(align_expr, "unable to override alignment of packed struct fields", .{});5031 return astgen.failNode(align_node, "unable to override alignment of packed struct fields", .{});
5098 }5032 }
5099 any_aligned_fields = true;5033 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, align_node);
5100 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, align_expr);
5101 if (!block_scope.endsWithNoReturn()) {5034 if (!block_scope.endsWithNoReturn()) {
5102 _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);5035 _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);
5103 }5036 }
5104 const body = block_scope.instructionsSlice();5037 const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
5105 const old_scratch_len = astgen.scratch.items.len;5038 field_align_body_lens.?.get(astgen)[field_idx] = body_len;
5106 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
5107 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
5108 wip_members.appendToField(@intCast(astgen.scratch.items.len - old_scratch_len));
5109 block_scope.instructions.items.len = block_scope.instructions_top;5039 block_scope.instructions.items.len = block_scope.instructions_top;
5040 } else if (field_align_body_lens) |lens| {
5041 lens.get(astgen)[field_idx] = 0;
5110 }5042 }
51115043
5112 if (member.ast.value_expr.unwrap()) |value_expr| {5044 if (member.ast.value_expr.unwrap()) |default_node| {
5113 any_default_inits = true;5045 const ri: ResultInfo = .{ .rl = .{ .coerced_ty = decl_inst.toRef() } };
51145046 const default_ref = try expr(&block_scope, &namespace.base, ri, default_node);
5115 // The decl_inst is used as here so that we can easily reconstruct a mapping
5116 // between it and the field type when the fields inits are analyzed.
5117 const ri: ResultInfo = .{ .rl = if (field_type == .none) .none else .{ .coerced_ty = decl_inst.toRef() } };
5118
5119 const default_inst = try expr(&block_scope, &namespace.base, ri, value_expr);
5120 if (!block_scope.endsWithNoReturn()) {5047 if (!block_scope.endsWithNoReturn()) {
5121 _ = try block_scope.addBreak(.break_inline, decl_inst, default_inst);5048 _ = try block_scope.addBreak(.break_inline, decl_inst, default_ref);
5122 }5049 }
5123 const body = block_scope.instructionsSlice();5050 const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
5124 const old_scratch_len = astgen.scratch.items.len;5051 field_default_body_lens.?.get(astgen)[field_idx] = body_len;
5125 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
5126 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
5127 wip_members.appendToField(@intCast(astgen.scratch.items.len - old_scratch_len));
5128 block_scope.instructions.items.len = block_scope.instructions_top;5052 block_scope.instructions.items.len = block_scope.instructions_top;
5129 } else if (member.comptime_token) |comptime_token| {5053 } else if (field_default_body_lens) |lens| {
5130 return astgen.failTok(comptime_token, "comptime field without default initialization value", .{});5054 lens.get(astgen)[field_idx] = 0;
5055 }
5056
5057 if (member.comptime_token) |comptime_token| {
5058 switch (layout) {
5059 .@"packed", .@"extern" => return astgen.failTok(comptime_token, "{s} struct fields cannot be marked comptime", .{@tagName(layout)}),
5060 .auto => {},
5061 }
5062 if (member.ast.value_expr == .none) {
5063 return astgen.failTok(comptime_token, "comptime field without default initialization value", .{});
5064 }
5065 const mask = @as(u32, 1) << @intCast(field_idx % 32);
5066 field_comptime_bits.?.get(astgen)[field_idx / 32] |= mask;
5131 }5067 }
5132 }5068 }
5069 assert(next_field_idx == scan_result.fields_len);
5070 wip_decls.finish();
51335071
5134 var fields_hash: std.zig.SrcHash = undefined;5072 var fields_hash: std.zig.SrcHash = undefined;
5135 astgen.src_hasher.final(&fields_hash);5073 astgen.src_hasher.final(&fields_hash);
51365074
5137 try gz.setStruct(decl_inst, .{5075 try gz.setStruct(decl_inst, .{
5138 .src_node = node,5076 .src_node = node,
5077 .name_strat = name_strat,
5139 .layout = layout,5078 .layout = layout,
5140 .captures_len = @intCast(namespace.captures.count()),5079 .backing_int_type = backing_int_type_ref,
5141 .fields_len = field_count,5080 .decls_len = scan_result.decls_len,
5142 .decls_len = decl_count,5081 .fields_len = scan_result.fields_len,
5143 .has_backing_int = backing_int_ref != .none,5082 .any_field_aligns = scan_result.any_field_aligns,
5144 .known_non_opv = known_non_opv,5083 .any_field_defaults = scan_result.any_field_values,
5145 .known_comptime_only = known_comptime_only,5084 .any_comptime_fields = scan_result.any_comptime_fields,
5146 .any_comptime_fields = any_comptime_fields,
5147 .any_default_inits = any_default_inits,
5148 .any_aligned_fields = any_aligned_fields,
5149 .fields_hash = fields_hash,5085 .fields_hash = fields_hash,
5150 .name_strat = name_strat,5086 .captures = namespace.captures.keys(),
5087 .capture_names = namespace.captures.values(),
5088 .remaining = scratch.all().get(astgen),
5151 });5089 });
51525090
5153 wip_members.finishBits(bits_per_field);
5154 const decls_slice = wip_members.declsSlice();
5155 const fields_slice = wip_members.fieldsSlice();
5156 const bodies_slice = astgen.scratch.items[bodies_start..];
5157 try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len + 2 +
5158 decls_slice.len + namespace.captures.count() * 2 + fields_slice.len + bodies_slice.len);
5159 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5160 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
5161 if (backing_int_ref != .none) {
5162 astgen.extra.appendAssumeCapacity(@intCast(backing_int_body_len));
5163 if (backing_int_body_len == 0) {
5164 astgen.extra.appendAssumeCapacity(@intFromEnum(backing_int_ref));
5165 } else {
5166 astgen.extra.appendSliceAssumeCapacity(astgen.scratch.items[scratch_top..][0..backing_int_body_len]);
5167 }
5168 }
5169 astgen.extra.appendSliceAssumeCapacity(decls_slice);
5170 astgen.extra.appendSliceAssumeCapacity(fields_slice);
5171 astgen.extra.appendSliceAssumeCapacity(bodies_slice);
5172
5173 block_scope.unstack();5091 block_scope.unstack();
5174 return decl_inst.toRef();5092 return decl_inst.toRef();
5175}5093}
...@@ -5281,11 +5199,34 @@ fn unionDeclInner(...@@ -5281,11 +5199,34 @@ fn unionDeclInner(
5281 auto_enum_tok: ?Ast.TokenIndex,5199 auto_enum_tok: ?Ast.TokenIndex,
5282 name_strat: Zir.Inst.NameStrategy,5200 name_strat: Zir.Inst.NameStrategy,
5283) InnerError!Zir.Inst.Ref {5201) InnerError!Zir.Inst.Ref {
5284 const decl_inst = try gz.reserveInstructionIndex();
5285
5286 const astgen = gz.astgen;5202 const astgen = gz.astgen;
5287 const gpa = astgen.gpa;5203 const gpa = astgen.gpa;
52885204
5205 const explicit_int_or_enum_tag = switch (layout) {
5206 .auto => opt_arg_node != .none,
5207 .@"extern" => if (opt_arg_node.unwrap()) |arg_node| {
5208 return astgen.failNode(arg_node, "{s} union does not support enum tag type", .{@tagName(layout)});
5209 } else false,
5210 .@"packed" => false,
5211 };
5212
5213 if (auto_enum_tok) |t| {
5214 if (layout != .auto) {
5215 return astgen.failTok(t, "{s} union does not support enum tag type", .{@tagName(layout)});
5216 }
5217 }
5218
5219 const is_tagged = explicit_int_or_enum_tag or auto_enum_tok != null;
5220
5221 astgen.advanceSourceCursorToNode(node);
5222
5223 const arg_type_ref: Zir.Inst.Ref = ref: {
5224 const arg_node = opt_arg_node.unwrap() orelse break :ref .none;
5225 break :ref try typeExpr(gz, scope, arg_node);
5226 };
5227
5228 const decl_inst = try gz.reserveInstructionIndex();
5229
5289 var namespace: Scope.Namespace = .{5230 var namespace: Scope.Namespace = .{
5290 .parent = scope,5231 .parent = scope,
5291 .node = node,5232 .node = node,
...@@ -5298,7 +5239,6 @@ fn unionDeclInner(...@@ -5298,7 +5239,6 @@ fn unionDeclInner(
5298 // The union_decl instruction introduces a scope in which the decls of the union5239 // The union_decl instruction introduces a scope in which the decls of the union
5299 // are in scope, so that field types, alignments, and default value expressions5240 // are in scope, so that field types, alignments, and default value expressions
5300 // can refer to decls within the union itself.5241 // can refer to decls within the union itself.
5301 astgen.advanceSourceCursorToNode(node);
5302 var block_scope: GenZir = .{5242 var block_scope: GenZir = .{
5303 .parent = &namespace.base,5243 .parent = &namespace.base,
5304 .decl_node_index = node,5244 .decl_node_index = node,
...@@ -5310,42 +5250,31 @@ fn unionDeclInner(...@@ -5310,42 +5250,31 @@ fn unionDeclInner(
5310 };5250 };
5311 defer block_scope.unstack();5251 defer block_scope.unstack();
53125252
5313 const decl_count = try astgen.scanContainer(&namespace, members, .@"union");5253 const scan_result = try astgen.scanContainer(&namespace, members, .@"union");
5314 const field_count: u32 = @intCast(members.len - decl_count);
5315
5316 if (layout != .auto and (auto_enum_tok != null or opt_arg_node != .none)) {
5317 if (opt_arg_node.unwrap()) |arg_node| {
5318 return astgen.failNode(arg_node, "{s} union does not support enum tag type", .{@tagName(layout)});
5319 } else {
5320 return astgen.failTok(auto_enum_tok.?, "{s} union does not support enum tag type", .{@tagName(layout)});
5321 }
5322 }
53235254
5324 const arg_inst: Zir.Inst.Ref = if (opt_arg_node.unwrap()) |arg_node|5255 var scratch: Scratch = .init(astgen);
5325 try typeExpr(&block_scope, &namespace.base, arg_node)5256 defer scratch.reset();
5326 else
5327 .none;
53285257
5329 const bits_per_field = 4;5258 // Replicate the structure of the ZIR trailing data in `scratch`
5330 const max_field_size = 4;5259 var wip_decls: WipDecls = try .init(&scratch, scan_result.decls_len);
5331 var any_aligned_fields = false;5260 const field_names = try scratch.addSlice(scan_result.fields_len);
5332 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);5261 const field_type_body_lens = try scratch.addSlice(scan_result.fields_len);
5333 defer wip_members.deinit();5262 const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len);
5263 const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len);
53345264
5335 const old_hasher = astgen.src_hasher;5265 const old_hasher = astgen.src_hasher;
5336 defer astgen.src_hasher = old_hasher;5266 defer astgen.src_hasher = old_hasher;
5337 astgen.src_hasher = std.zig.SrcHasher.init(.{});5267 astgen.src_hasher = .init(.{});
5338 astgen.src_hasher.update(@tagName(layout));
5339 astgen.src_hasher.update(&.{@intFromBool(auto_enum_tok != null)});
5340 if (opt_arg_node.unwrap()) |arg_node| {
5341 astgen.src_hasher.update(astgen.tree.getNodeSource(arg_node));
5342 }
53435268
5269 var next_field_idx: u32 = 0;
5344 for (members) |member_node| {5270 for (members) |member_node| {
5345 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {5271 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) {
5346 .decl => continue,5272 .decl => continue,
5347 .field => |field| field,5273 .field => |field| field,
5348 };5274 };
5275 const field_idx = next_field_idx;
5276 next_field_idx += 1;
5277
5349 astgen.src_hasher.update(astgen.tree.getNodeSource(member_node));5278 astgen.src_hasher.update(astgen.tree.getNodeSource(member_node));
5350 member.convertToNonTupleLike(astgen.tree);5279 member.convertToNonTupleLike(astgen.tree);
5351 if (member.ast.tuple_like) {5280 if (member.ast.tuple_like) {
...@@ -5355,97 +5284,91 @@ fn unionDeclInner(...@@ -5355,97 +5284,91 @@ fn unionDeclInner(
5355 return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{});5284 return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{});
5356 }5285 }
53575286
5358 const field_name = try astgen.identAsString(member.ast.main_token);5287 field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token));
5359 wip_members.appendToField(@intFromEnum(field_name));
5360
5361 const have_type = member.ast.type_expr != .none;
5362 const have_align = member.ast.align_expr != .none;
5363 const have_value = member.ast.value_expr != .none;
5364 const unused = false;
5365 wip_members.nextField(bits_per_field, .{ have_type, have_align, have_value, unused });
53665288
5367 if (member.ast.type_expr.unwrap()) |type_expr| {5289 if (member.ast.type_expr.unwrap()) |type_node| {
5368 const field_type = try typeExpr(&block_scope, &namespace.base, type_expr);5290 const type_ref = try typeExpr(&block_scope, &namespace.base, type_node);
5369 wip_members.appendToField(@intFromEnum(field_type));5291 if (!block_scope.endsWithNoReturn()) {
5370 } else if (arg_inst == .none and auto_enum_tok == null) {5292 _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
5293 }
5294 const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
5295 field_type_body_lens.get(astgen)[field_idx] = body_len;
5296 block_scope.instructions.items.len = block_scope.instructions_top;
5297 } else if (!is_tagged) {
5371 return astgen.failNode(member_node, "union field missing type", .{});5298 return astgen.failNode(member_node, "union field missing type", .{});
5299 } else {
5300 field_type_body_lens.get(astgen)[field_idx] = 0;
5372 }5301 }
5373 if (member.ast.align_expr.unwrap()) |align_expr| {5302
5303 if (member.ast.align_expr.unwrap()) |align_node| {
5374 if (layout == .@"packed") {5304 if (layout == .@"packed") {
5375 return astgen.failNode(align_expr, "unable to override alignment of packed union fields", .{});5305 return astgen.failNode(align_node, "unable to override alignment of packed union fields", .{});
5376 }5306 }
5377 const align_inst = try expr(&block_scope, &block_scope.base, coerced_align_ri, align_expr);5307 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, align_node);
5378 wip_members.appendToField(@intFromEnum(align_inst));5308 if (!block_scope.endsWithNoReturn()) {
5379 any_aligned_fields = true;5309 _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);
5380 }
5381 if (member.ast.value_expr.unwrap()) |value_expr| {
5382 if (arg_inst == .none) {
5383 return astgen.failNodeNotes(
5384 node,
5385 "explicitly valued tagged union missing integer tag type",
5386 .{},
5387 &[_]u32{
5388 try astgen.errNoteNode(
5389 value_expr,
5390 "tag value specified here",
5391 .{},
5392 ),
5393 },
5394 );
5395 }5310 }
5396 if (auto_enum_tok == null) {5311 const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
5397 return astgen.failNodeNotes(5312 field_align_body_lens.?.get(astgen)[field_idx] = body_len;
5398 node,5313 block_scope.instructions.items.len = block_scope.instructions_top;
5399 "explicitly valued tagged union requires inferred enum tag type",5314 } else if (field_align_body_lens) |lens| {
5400 .{},5315 lens.get(astgen)[field_idx] = 0;
5401 &[_]u32{5316 }
5402 try astgen.errNoteNode(5317
5403 value_expr,5318 if (member.ast.value_expr.unwrap()) |value_node| {
5404 "tag value specified here",5319 if (!explicit_int_or_enum_tag) return astgen.failNodeNotes(
5405 .{},5320 node,
5406 ),5321 "explicitly valued tagged union missing integer tag type",
5407 },5322 .{},
5408 );5323 &.{try astgen.errNoteNode(value_node, "tag value specified here", .{})},
5324 );
5325 if (auto_enum_tok == null) return astgen.failNodeNotes(
5326 node,
5327 "explicitly valued tagged union requires inferred enum tag type",
5328 .{},
5329 &.{try astgen.errNoteNode(value_node, "tag value specified here", .{})},
5330 );
5331 const ri: ResultInfo = .{ .rl = .{ .coerced_ty = decl_inst.toRef() } };
5332 const value_ref = try expr(&block_scope, &namespace.base, ri, value_node);
5333 if (!block_scope.endsWithNoReturn()) {
5334 _ = try block_scope.addBreak(.break_inline, decl_inst, value_ref);
5409 }5335 }
5410 const tag_value = try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = arg_inst } }, value_expr);5336 const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
5411 wip_members.appendToField(@intFromEnum(tag_value));5337 field_value_body_lens.?.get(astgen)[field_idx] = body_len;
5338 block_scope.instructions.items.len = block_scope.instructions_top;
5339 } else if (field_value_body_lens) |lens| {
5340 lens.get(astgen)[field_idx] = 0;
5412 }5341 }
5413 }5342 }
5343 assert(next_field_idx == scan_result.fields_len);
5344 wip_decls.finish();
54145345
5415 var fields_hash: std.zig.SrcHash = undefined;5346 var fields_hash: std.zig.SrcHash = undefined;
5416 astgen.src_hasher.final(&fields_hash);5347 astgen.src_hasher.final(&fields_hash);
54175348
5418 if (!block_scope.isEmpty()) {
5419 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
5420 }
5421
5422 const body = block_scope.instructionsSlice();
5423 const body_len = astgen.countBodyLenAfterFixups(body);
5424
5425 try gz.setUnion(decl_inst, .{5349 try gz.setUnion(decl_inst, .{
5426 .src_node = node,5350 .src_node = node,
5427 .layout = layout,
5428 .tag_type = arg_inst,
5429 .captures_len = @intCast(namespace.captures.count()),
5430 .body_len = body_len,
5431 .fields_len = field_count,
5432 .decls_len = decl_count,
5433 .auto_enum_tag = auto_enum_tok != null,
5434 .any_aligned_fields = any_aligned_fields,
5435 .fields_hash = fields_hash,
5436 .name_strat = name_strat,5351 .name_strat = name_strat,
5352 .kind = switch (layout) {
5353 .auto => if (auto_enum_tok == null) l: {
5354 break :l if (opt_arg_node == .none) .auto else .tagged_explicit;
5355 } else l: {
5356 break :l if (opt_arg_node == .none) .tagged_enum else .tagged_enum_explicit;
5357 },
5358 .@"extern" => .@"extern",
5359 .@"packed" => if (opt_arg_node != .none) .packed_explicit else .@"packed",
5360 },
5361 .arg_type = arg_type_ref,
5362 .decls_len = scan_result.decls_len,
5363 .fields_len = scan_result.fields_len,
5364 .any_field_aligns = scan_result.any_field_aligns,
5365 .any_field_values = scan_result.any_field_values,
5366 .fields_hash = fields_hash,
5367 .captures = namespace.captures.keys(),
5368 .capture_names = namespace.captures.values(),
5369 .remaining = scratch.all().get(astgen),
5437 });5370 });
54385371
5439 wip_members.finishBits(bits_per_field);
5440 const decls_slice = wip_members.declsSlice();
5441 const fields_slice = wip_members.fieldsSlice();
5442 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() * 2 + decls_slice.len + body_len + fields_slice.len);
5443 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5444 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
5445 astgen.extra.appendSliceAssumeCapacity(decls_slice);
5446 astgen.appendBodyWithFixups(body);
5447 astgen.extra.appendSliceAssumeCapacity(fields_slice);
5448
5449 block_scope.unstack();5372 block_scope.unstack();
5450 return decl_inst.toRef();5373 return decl_inst.toRef();
5451}5374}
...@@ -5494,103 +5417,13 @@ fn containerDecl(...@@ -5494,103 +5417,13 @@ fn containerDecl(
5494 if (container_decl.layout_token) |t| {5417 if (container_decl.layout_token) |t| {
5495 return astgen.failTok(t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{});5418 return astgen.failTok(t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{});
5496 }5419 }
5497 // Count total fields as well as how many have explicitly provided tag values.
5498 const counts = blk: {
5499 var values: usize = 0;
5500 var total_fields: usize = 0;
5501 var decls: usize = 0;
5502 var opt_nonexhaustive_node: Ast.Node.OptionalIndex = .none;
5503 var nonfinal_nonexhaustive = false;
5504 for (container_decl.ast.members) |member_node| {
5505 var member = tree.fullContainerField(member_node) orelse {
5506 decls += 1;
5507 continue;
5508 };
5509 member.convertToNonTupleLike(astgen.tree);
5510 if (member.ast.tuple_like) {
5511 return astgen.failTok(member.ast.main_token, "enum field missing name", .{});
5512 }
5513 if (member.comptime_token) |comptime_token| {
5514 return astgen.failTok(comptime_token, "enum fields cannot be marked comptime", .{});
5515 }
5516 if (member.ast.type_expr.unwrap()) |type_expr| {
5517 return astgen.failNodeNotes(
5518 type_expr,
5519 "enum fields do not have types",
5520 .{},
5521 &[_]u32{
5522 try astgen.errNoteNode(
5523 node,
5524 "consider 'union(enum)' here to make it a tagged union",
5525 .{},
5526 ),
5527 },
5528 );
5529 }
5530 if (member.ast.align_expr.unwrap()) |align_expr| {
5531 return astgen.failNode(align_expr, "enum fields cannot be aligned", .{});
5532 }
55335420
5534 const name_token = member.ast.main_token;5421 astgen.advanceSourceCursorToNode(node);
5535 if (mem.eql(u8, tree.tokenSlice(name_token), "_")) {5422
5536 if (opt_nonexhaustive_node.unwrap()) |nonexhaustive_node| {5423 const tag_type_ref: Zir.Inst.Ref = ref: {
5537 return astgen.failNodeNotes(5424 const arg_node = container_decl.ast.arg.unwrap() orelse break :ref .none;
5538 member_node,5425 break :ref try typeExpr(gz, scope, arg_node);
5539 "redundant non-exhaustive enum mark",
5540 .{},
5541 &[_]u32{
5542 try astgen.errNoteNode(
5543 nonexhaustive_node,
5544 "other mark here",
5545 .{},
5546 ),
5547 },
5548 );
5549 }
5550 opt_nonexhaustive_node = member_node.toOptional();
5551 if (member.ast.value_expr.unwrap()) |value_expr| {
5552 return astgen.failNode(value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{});
5553 }
5554 continue;
5555 } else if (opt_nonexhaustive_node != .none) {
5556 nonfinal_nonexhaustive = true;
5557 }
5558 total_fields += 1;
5559 if (member.ast.value_expr.unwrap()) |value_expr| {
5560 if (container_decl.ast.arg == .none) {
5561 return astgen.failNode(value_expr, "value assigned to enum tag with inferred tag type", .{});
5562 }
5563 values += 1;
5564 }
5565 }
5566 if (nonfinal_nonexhaustive) {
5567 return astgen.failNode(opt_nonexhaustive_node.unwrap().?, "'_' field of non-exhaustive enum must be last", .{});
5568 }
5569 break :blk .{
5570 .total_fields = total_fields,
5571 .values = values,
5572 .decls = decls,
5573 .nonexhaustive_node = opt_nonexhaustive_node,
5574 };
5575 };5426 };
5576 if (counts.nonexhaustive_node != .none and container_decl.ast.arg == .none) {
5577 const nonexhaustive_node = counts.nonexhaustive_node.unwrap().?;
5578 return astgen.failNodeNotes(
5579 node,
5580 "non-exhaustive enum missing integer tag type",
5581 .{},
5582 &[_]u32{
5583 try astgen.errNoteNode(
5584 nonexhaustive_node,
5585 "marked non-exhaustive here",
5586 .{},
5587 ),
5588 },
5589 );
5590 }
5591 // In this case we must generate ZIR code for the tag values, similar to
5592 // how structs are handled above.
5593 const nonexhaustive = counts.nonexhaustive_node != .none;
55945427
5595 const decl_inst = try gz.reserveInstructionIndex();5428 const decl_inst = try gz.reserveInstructionIndex();
55965429
...@@ -5605,7 +5438,6 @@ fn containerDecl(...@@ -5605,7 +5438,6 @@ fn containerDecl(
56055438
5606 // The enum_decl instruction introduces a scope in which the decls of the enum5439 // The enum_decl instruction introduces a scope in which the decls of the enum
5607 // are in scope, so that tag values can refer to decls within the enum itself.5440 // are in scope, so that tag values can refer to decls within the enum itself.
5608 astgen.advanceSourceCursorToNode(node);
5609 var block_scope: GenZir = .{5441 var block_scope: GenZir = .{
5610 .parent = &namespace.base,5442 .parent = &namespace.base,
5611 .decl_node_index = node,5443 .decl_node_index = node,
...@@ -5617,104 +5449,111 @@ fn containerDecl(...@@ -5617,104 +5449,111 @@ fn containerDecl(
5617 };5449 };
5618 defer block_scope.unstack();5450 defer block_scope.unstack();
56195451
5620 _ = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"enum");5452 const scan_result = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"enum");
5621 namespace.base.tag = .namespace;5453 // The name `_` is not actually a field; it marks a non-exhaustive enum.
5454 const fields_len: u32 = scan_result.fields_len - @intFromBool(scan_result.has_underscore_field);
56225455
5623 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg.unwrap()) |arg|5456 var scratch: Scratch = .init(astgen);
5624 try comptimeExpr(&block_scope, &namespace.base, coerced_type_ri, arg, .type)5457 defer scratch.reset();
5625 else
5626 .none;
56275458
5628 const bits_per_field = 1;5459 // Replicate the structure of the ZIR trailing data in `scratch`
5629 const max_field_size = 2;5460 var wip_decls: WipDecls = try .init(&scratch, scan_result.decls_len);
5630 var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size);5461 const field_names = try scratch.addSlice(fields_len);
5631 defer wip_members.deinit();5462 const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, fields_len);
56325463
5633 const old_hasher = astgen.src_hasher;5464 const old_hasher = astgen.src_hasher;
5634 defer astgen.src_hasher = old_hasher;5465 defer astgen.src_hasher = old_hasher;
5635 astgen.src_hasher = std.zig.SrcHasher.init(.{});5466 astgen.src_hasher = .init(.{});
5636 if (container_decl.ast.arg.unwrap()) |arg| {
5637 astgen.src_hasher.update(tree.getNodeSource(arg));
5638 }
5639 astgen.src_hasher.update(&.{@intFromBool(nonexhaustive)});
56405467
5468 var next_field_idx: u32 = 0;
5469 var opt_nonexhaustive_node: Ast.Node.OptionalIndex = .none;
5641 for (container_decl.ast.members) |member_node| {5470 for (container_decl.ast.members) |member_node| {
5642 if (member_node.toOptional() == counts.nonexhaustive_node)5471 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) {
5643 continue;
5644 astgen.src_hasher.update(tree.getNodeSource(member_node));
5645 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
5646 .decl => continue,5472 .decl => continue,
5647 .field => |field| field,5473 .field => |field| field,
5648 };5474 };
5649 member.convertToNonTupleLike(astgen.tree);5475 member.convertToNonTupleLike(astgen.tree);
5650 assert(member.comptime_token == null);5476 if (member.ast.tuple_like) return astgen.failTok(member.ast.main_token, "enum field missing name", .{});
5651 assert(member.ast.type_expr == .none);5477 if (member.comptime_token) |t| return astgen.failTok(t, "enum fields cannot be marked comptime", .{});
5652 assert(member.ast.align_expr == .none);5478 if (member.ast.type_expr.unwrap()) |type_node| {
5479 return astgen.failNodeNotes(type_node, "enum fields do not have types", .{}, &.{
5480 try astgen.errNoteNode(node, "consider 'union(enum)' here to make it a tagged union", .{}),
5481 });
5482 }
5483 if (member.ast.align_expr.unwrap()) |n| return astgen.failNode(n, "enum fields cannot be aligned", .{});
5484 if (mem.eql(u8, tree.tokenSlice(member.ast.main_token), "_")) {
5485 // non-exhaustive mark
5486 assert(scan_result.has_underscore_field);
5487 if (opt_nonexhaustive_node.unwrap()) |prev_node| {
5488 return astgen.failNodeNotes(member_node, "redundant non-exhaustive enum mark", .{}, &.{
5489 try astgen.errNoteNode(prev_node, "other mark here", .{}),
5490 });
5491 }
5492 if (member.ast.value_expr.unwrap()) |value_node| {
5493 return astgen.failNode(value_node, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{});
5494 }
5495 if (next_field_idx != fields_len) {
5496 return astgen.failNode(member_node, "'_' field of non-exhaustive enum must be last", .{});
5497 }
5498 opt_nonexhaustive_node = member_node.toOptional();
5499 continue;
5500 }
56535501
5654 const field_name = try astgen.identAsString(member.ast.main_token);5502 // This is a real field rather than a non-exhaustive mark.
5655 wip_members.appendToField(@intFromEnum(field_name));5503 const field_idx = next_field_idx;
5504 next_field_idx += 1;
56565505
5657 const have_value = member.ast.value_expr != .none;5506 astgen.src_hasher.update(tree.getNodeSource(member_node));
5658 wip_members.nextField(bits_per_field, .{have_value});
56595507
5660 if (member.ast.value_expr.unwrap()) |value_expr| {5508 field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token));
5661 if (arg_inst == .none) {5509
5662 return astgen.failNodeNotes(5510 if (member.ast.value_expr.unwrap()) |value_node| {
5663 node,5511 if (tag_type_ref == .none) {
5664 "explicitly valued enum missing integer tag type",5512 return astgen.failNodeNotes(node, "explicitly valued enum missing integer tag type", .{}, &.{
5665 .{},5513 try astgen.errNoteNode(value_node, "tag value specified here", .{}),
5666 &[_]u32{5514 });
5667 try astgen.errNoteNode(5515 }
5668 value_expr,5516 const val_ri: ResultInfo = .{ .rl = .{ .coerced_ty = decl_inst.toRef() } };
5669 "tag value specified here",5517 const value_ref = try expr(&block_scope, &namespace.base, val_ri, value_node);
5670 .{},5518 if (!block_scope.endsWithNoReturn()) {
5671 ),5519 _ = try block_scope.addBreak(.break_inline, decl_inst, value_ref);
5672 },
5673 );
5674 }5520 }
5675 const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .rl = .{ .ty = arg_inst } }, value_expr);5521 const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
5676 wip_members.appendToField(@intFromEnum(tag_value_inst));5522 field_value_body_lens.?.get(astgen)[field_idx] = body_len;
5523 block_scope.instructions.items.len = block_scope.instructions_top;
5524 } else if (field_value_body_lens) |lens| {
5525 lens.get(astgen)[field_idx] = 0;
5677 }5526 }
5678 }5527 }
56795528 assert(scan_result.has_underscore_field == (opt_nonexhaustive_node != .none));
5680 if (!block_scope.isEmpty()) {5529 assert(next_field_idx == fields_len);
5681 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);5530 wip_decls.finish();
5682 }
56835531
5684 var fields_hash: std.zig.SrcHash = undefined;5532 var fields_hash: std.zig.SrcHash = undefined;
5685 astgen.src_hasher.final(&fields_hash);5533 astgen.src_hasher.final(&fields_hash);
56865534
5687 const body = block_scope.instructionsSlice();
5688 const body_len = astgen.countBodyLenAfterFixups(body);
5689
5690 try gz.setEnum(decl_inst, .{5535 try gz.setEnum(decl_inst, .{
5691 .src_node = node,5536 .src_node = node,
5692 .nonexhaustive = nonexhaustive,
5693 .tag_type = arg_inst,
5694 .captures_len = @intCast(namespace.captures.count()),
5695 .body_len = body_len,
5696 .fields_len = @intCast(counts.total_fields),
5697 .decls_len = @intCast(counts.decls),
5698 .fields_hash = fields_hash,
5699 .name_strat = name_strat,5537 .name_strat = name_strat,
5538 .tag_type = tag_type_ref,
5539 .nonexhaustive = scan_result.has_underscore_field,
5540 .decls_len = scan_result.decls_len,
5541 .fields_len = fields_len,
5542 .any_field_values = scan_result.any_field_values,
5543 .fields_hash = fields_hash,
5544 .captures = namespace.captures.keys(),
5545 .capture_names = namespace.captures.values(),
5546 .remaining = scratch.all().get(astgen),
5700 });5547 });
57015548
5702 wip_members.finishBits(bits_per_field);
5703 const decls_slice = wip_members.declsSlice();
5704 const fields_slice = wip_members.fieldsSlice();
5705 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() * 2 + decls_slice.len + body_len + fields_slice.len);
5706 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5707 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
5708 astgen.extra.appendSliceAssumeCapacity(decls_slice);
5709 astgen.appendBodyWithFixups(body);
5710 astgen.extra.appendSliceAssumeCapacity(fields_slice);
5711
5712 block_scope.unstack();5549 block_scope.unstack();
5713 return rvalue(gz, ri, decl_inst.toRef(), node);5550 return rvalue(gz, ri, decl_inst.toRef(), node);
5714 },5551 },
5715 .keyword_opaque => {5552 .keyword_opaque => {
5716 assert(container_decl.ast.arg == .none);5553 assert(container_decl.ast.arg == .none);
57175554
5555 astgen.advanceSourceCursorToNode(node);
5556
5718 const decl_inst = try gz.reserveInstructionIndex();5557 const decl_inst = try gz.reserveInstructionIndex();
57195558
5720 var namespace: Scope.Namespace = .{5559 var namespace: Scope.Namespace = .{
...@@ -5726,7 +5565,6 @@ fn containerDecl(...@@ -5726,7 +5565,6 @@ fn containerDecl(
5726 };5565 };
5727 defer namespace.deinit(gpa);5566 defer namespace.deinit(gpa);
57285567
5729 astgen.advanceSourceCursorToNode(node);
5730 var block_scope: GenZir = .{5568 var block_scope: GenZir = .{
5731 .parent = &namespace.base,5569 .parent = &namespace.base,
5732 .decl_node_index = node,5570 .decl_node_index = node,
...@@ -5738,36 +5576,34 @@ fn containerDecl(...@@ -5738,36 +5576,34 @@ fn containerDecl(
5738 };5576 };
5739 defer block_scope.unstack();5577 defer block_scope.unstack();
57405578
5741 const decl_count = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"opaque");5579 const scan_result = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"opaque");
57425580
5743 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0);5581 var scratch: Scratch = .init(astgen);
5744 defer wip_members.deinit();5582 defer scratch.reset();
5583 var wip_decls: WipDecls = try .init(&scratch, scan_result.decls_len);
57455584
5746 if (container_decl.layout_token) |layout_token| {5585 if (container_decl.layout_token) |layout_token| {
5747 return astgen.failTok(layout_token, "opaque types do not support 'packed' or 'extern'", .{});5586 return astgen.failTok(layout_token, "opaque types do not support 'packed' or 'extern'", .{});
5748 }5587 }
57495588
5750 for (container_decl.ast.members) |member_node| {5589 for (container_decl.ast.members) |member_node| {
5751 const res = try containerMember(&block_scope, &namespace.base, &wip_members, member_node);5590 switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) {
5752 if (res == .field) {5591 .decl => {},
5753 return astgen.failNode(member_node, "opaque types cannot have fields", .{});5592 .field => return astgen.failNode(member_node, "opaque types cannot have fields", .{}),
5754 }5593 }
5755 }5594 }
57565595
5596 wip_decls.finish();
5597
5757 try gz.setOpaque(decl_inst, .{5598 try gz.setOpaque(decl_inst, .{
5758 .src_node = node,5599 .src_node = node,
5759 .captures_len = @intCast(namespace.captures.count()),
5760 .decls_len = decl_count,
5761 .name_strat = name_strat,5600 .name_strat = name_strat,
5601 .decls_len = scan_result.decls_len,
5602 .captures = namespace.captures.keys(),
5603 .capture_names = namespace.captures.values(),
5604 .decls = @ptrCast(scratch.all().get(astgen)),
5762 });5605 });
57635606
5764 wip_members.finishBits(0);
5765 const decls_slice = wip_members.declsSlice();
5766 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() * 2 + decls_slice.len);
5767 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5768 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
5769 astgen.extra.appendSliceAssumeCapacity(decls_slice);
5770
5771 block_scope.unstack();5607 block_scope.unstack();
5772 return rvalue(gz, ri, decl_inst.toRef(), node);5608 return rvalue(gz, ri, decl_inst.toRef(), node);
5773 },5609 },
...@@ -5780,7 +5616,7 @@ const ContainerMemberResult = union(enum) { decl, field: Ast.full.ContainerField...@@ -5780,7 +5616,7 @@ const ContainerMemberResult = union(enum) { decl, field: Ast.full.ContainerField
5780fn containerMember(5616fn containerMember(
5781 gz: *GenZir,5617 gz: *GenZir,
5782 scope: *Scope,5618 scope: *Scope,
5783 wip_members: *WipMembers,5619 wip_decls: *WipDecls,
5784 member_node: Ast.Node.Index,5620 member_node: Ast.Node.Index,
5785) InnerError!ContainerMemberResult {5621) InnerError!ContainerMemberResult {
5786 const astgen = gz.astgen;5622 const astgen = gz.astgen;
...@@ -5805,13 +5641,13 @@ fn containerMember(...@@ -5805,13 +5641,13 @@ fn containerMember(
5805 else5641 else
5806 .none;5642 .none;
58075643
5808 const prev_decl_index = wip_members.decl_index;5644 const prev_decl_index = wip_decls.index;
5809 astgen.fnDecl(gz, scope, wip_members, member_node, body, full) catch |err| switch (err) {5645 astgen.fnDecl(gz, scope, wip_decls, member_node, body, full) catch |err| switch (err) {
5810 error.OutOfMemory => return error.OutOfMemory,5646 error.OutOfMemory => return error.OutOfMemory,
5811 error.AnalysisFail => {5647 error.AnalysisFail => {
5812 wip_members.decl_index = prev_decl_index;5648 wip_decls.index = prev_decl_index;
5813 try addFailedDeclaration(5649 try addFailedDeclaration(
5814 wip_members,5650 wip_decls,
5815 gz,5651 gz,
5816 .@"const",5652 .@"const",
5817 try astgen.identAsString(full.name_token.?),5653 try astgen.identAsString(full.name_token.?),
...@@ -5828,13 +5664,13 @@ fn containerMember(...@@ -5828,13 +5664,13 @@ fn containerMember(
5828 .aligned_var_decl,5664 .aligned_var_decl,
5829 => {5665 => {
5830 const full = tree.fullVarDecl(member_node).?;5666 const full = tree.fullVarDecl(member_node).?;
5831 const prev_decl_index = wip_members.decl_index;5667 const prev_decl_index = wip_decls.index;
5832 astgen.globalVarDecl(gz, scope, wip_members, member_node, full) catch |err| switch (err) {5668 astgen.globalVarDecl(gz, scope, wip_decls, member_node, full) catch |err| switch (err) {
5833 error.OutOfMemory => return error.OutOfMemory,5669 error.OutOfMemory => return error.OutOfMemory,
5834 error.AnalysisFail => {5670 error.AnalysisFail => {
5835 wip_members.decl_index = prev_decl_index;5671 wip_decls.index = prev_decl_index;
5836 try addFailedDeclaration(5672 try addFailedDeclaration(
5837 wip_members,5673 wip_decls,
5838 gz,5674 gz,
5839 .@"const", // doesn't really matter5675 .@"const", // doesn't really matter
5840 try astgen.identAsString(full.ast.mut_token + 1),5676 try astgen.identAsString(full.ast.mut_token + 1),
...@@ -5846,13 +5682,13 @@ fn containerMember(...@@ -5846,13 +5682,13 @@ fn containerMember(
5846 },5682 },
58475683
5848 .@"comptime" => {5684 .@"comptime" => {
5849 const prev_decl_index = wip_members.decl_index;5685 const prev_decl_index = wip_decls.index;
5850 astgen.comptimeDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {5686 astgen.comptimeDecl(gz, scope, wip_decls, member_node) catch |err| switch (err) {
5851 error.OutOfMemory => return error.OutOfMemory,5687 error.OutOfMemory => return error.OutOfMemory,
5852 error.AnalysisFail => {5688 error.AnalysisFail => {
5853 wip_members.decl_index = prev_decl_index;5689 wip_decls.index = prev_decl_index;
5854 try addFailedDeclaration(5690 try addFailedDeclaration(
5855 wip_members,5691 wip_decls,
5856 gz,5692 gz,
5857 .@"comptime",5693 .@"comptime",
5858 .empty,5694 .empty,
...@@ -5863,16 +5699,16 @@ fn containerMember(...@@ -5863,16 +5699,16 @@ fn containerMember(
5863 };5699 };
5864 },5700 },
5865 .test_decl => {5701 .test_decl => {
5866 const prev_decl_index = wip_members.decl_index;5702 const prev_decl_index = wip_decls.index;
5867 // We need to have *some* decl here so that the decl count matches what's expected.5703 // We need to have *some* decl here so that the decl count matches what's expected.
5868 // Since it doesn't strictly matter *what* this is, let's save ourselves the trouble5704 // Since it doesn't strictly matter *what* this is, let's save ourselves the trouble
5869 // of duplicating the test name logic, and just assume this is an unnamed test.5705 // of duplicating the test name logic, and just assume this is an unnamed test.
5870 astgen.testDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {5706 astgen.testDecl(gz, scope, wip_decls, member_node) catch |err| switch (err) {
5871 error.OutOfMemory => return error.OutOfMemory,5707 error.OutOfMemory => return error.OutOfMemory,
5872 error.AnalysisFail => {5708 error.AnalysisFail => {
5873 wip_members.decl_index = prev_decl_index;5709 wip_decls.index = prev_decl_index;
5874 try addFailedDeclaration(5710 try addFailedDeclaration(
5875 wip_members,5711 wip_decls,
5876 gz,5712 gz,
5877 .unnamed_test,5713 .unnamed_test,
5878 .empty,5714 .empty,
...@@ -10619,495 +10455,19 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev...@@ -10619,495 +10455,19 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
10619 }10455 }
10620}10456}
1062110457
10622/// Returns `true` if it is known the type expression has more than one possible value;10458/// Applies `rl` semantics to `result`. Expressions which do not do their own handling of
10623/// `false` otherwise.10459/// result locations must call this function on their result.
10624fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.Index) bool {10460/// As an example, if `ri.rl` is `.ptr`, it will write the result to the pointer.
10625 var node = start_node;10461/// If `ri.rl` is `.ty`, it will coerce the result to the type.
10626 while (true) {10462/// Assumes nothing stacked on `gz`.
10627 switch (tree.nodeTag(node)) {10463fn rvalue(
10628 .root,10464 gz: *GenZir,
10629 .test_decl,10465 ri: ResultInfo,
10630 .switch_case,10466 raw_result: Zir.Inst.Ref,
10631 .switch_case_inline,10467 src_node: Ast.Node.Index,
10632 .switch_case_one,10468) InnerError!Zir.Inst.Ref {
10633 .switch_case_inline_one,10469 return rvalueInner(gz, ri, raw_result, src_node, true);
10634 .container_field_init,10470}
10635 .container_field_align,
10636 .container_field,
10637 .asm_output,
10638 .asm_input,
10639 .global_var_decl,
10640 .local_var_decl,
10641 .simple_var_decl,
10642 .aligned_var_decl,
10643 => unreachable,
10644
10645 .@"return",
10646 .@"break",
10647 .@"continue",
10648 .bit_not,
10649 .bool_not,
10650 .@"defer",
10651 .@"errdefer",
10652 .address_of,
10653 .negation,
10654 .negation_wrap,
10655 .@"resume",
10656 .array_type,
10657 .@"suspend",
10658 .fn_decl,
10659 .anyframe_literal,
10660 .number_literal,
10661 .enum_literal,
10662 .string_literal,
10663 .multiline_string_literal,
10664 .char_literal,
10665 .unreachable_literal,
10666 .error_set_decl,
10667 .container_decl,
10668 .container_decl_trailing,
10669 .container_decl_two,
10670 .container_decl_two_trailing,
10671 .container_decl_arg,
10672 .container_decl_arg_trailing,
10673 .tagged_union,
10674 .tagged_union_trailing,
10675 .tagged_union_two,
10676 .tagged_union_two_trailing,
10677 .tagged_union_enum_tag,
10678 .tagged_union_enum_tag_trailing,
10679 .@"asm",
10680 .asm_simple,
10681 .add,
10682 .add_wrap,
10683 .add_sat,
10684 .array_cat,
10685 .array_mult,
10686 .assign,
10687 .assign_destructure,
10688 .assign_bit_and,
10689 .assign_bit_or,
10690 .assign_shl,
10691 .assign_shl_sat,
10692 .assign_shr,
10693 .assign_bit_xor,
10694 .assign_div,
10695 .assign_sub,
10696 .assign_sub_wrap,
10697 .assign_sub_sat,
10698 .assign_mod,
10699 .assign_add,
10700 .assign_add_wrap,
10701 .assign_add_sat,
10702 .assign_mul,
10703 .assign_mul_wrap,
10704 .assign_mul_sat,
10705 .bang_equal,
10706 .bit_and,
10707 .bit_or,
10708 .shl,
10709 .shl_sat,
10710 .shr,
10711 .bit_xor,
10712 .bool_and,
10713 .bool_or,
10714 .div,
10715 .equal_equal,
10716 .error_union,
10717 .greater_or_equal,
10718 .greater_than,
10719 .less_or_equal,
10720 .less_than,
10721 .merge_error_sets,
10722 .mod,
10723 .mul,
10724 .mul_wrap,
10725 .mul_sat,
10726 .switch_range,
10727 .for_range,
10728 .field_access,
10729 .sub,
10730 .sub_wrap,
10731 .sub_sat,
10732 .slice,
10733 .slice_open,
10734 .slice_sentinel,
10735 .deref,
10736 .array_access,
10737 .error_value,
10738 .while_simple,
10739 .while_cont,
10740 .for_simple,
10741 .if_simple,
10742 .@"catch",
10743 .@"orelse",
10744 .array_init_one,
10745 .array_init_one_comma,
10746 .array_init_dot_two,
10747 .array_init_dot_two_comma,
10748 .array_init_dot,
10749 .array_init_dot_comma,
10750 .array_init,
10751 .array_init_comma,
10752 .struct_init_one,
10753 .struct_init_one_comma,
10754 .struct_init_dot_two,
10755 .struct_init_dot_two_comma,
10756 .struct_init_dot,
10757 .struct_init_dot_comma,
10758 .struct_init,
10759 .struct_init_comma,
10760 .@"while",
10761 .@"if",
10762 .@"for",
10763 .@"switch",
10764 .switch_comma,
10765 .call_one,
10766 .call_one_comma,
10767 .call,
10768 .call_comma,
10769 .block_two,
10770 .block_two_semicolon,
10771 .block,
10772 .block_semicolon,
10773 .builtin_call,
10774 .builtin_call_comma,
10775 .builtin_call_two,
10776 .builtin_call_two_comma,
10777 // these are function bodies, not pointers
10778 .fn_proto_simple,
10779 .fn_proto_multi,
10780 .fn_proto_one,
10781 .fn_proto,
10782 => return false,
10783
10784 // Forward the question to the LHS sub-expression.
10785 .@"try",
10786 .@"comptime",
10787 .@"nosuspend",
10788 => node = tree.nodeData(node).node,
10789 .grouped_expression,
10790 .unwrap_optional,
10791 => node = tree.nodeData(node).node_and_token[0],
10792
10793 .ptr_type_aligned,
10794 .ptr_type_sentinel,
10795 .ptr_type,
10796 .ptr_type_bit_range,
10797 .optional_type,
10798 .anyframe_type,
10799 .array_type_sentinel,
10800 => return true,
10801
10802 .identifier => {
10803 const ident_bytes = tree.tokenSlice(tree.nodeMainToken(node));
10804 if (primitive_instrs.get(ident_bytes)) |primitive| switch (primitive) {
10805 .anyerror_type,
10806 .anyframe_type,
10807 .anyopaque_type,
10808 .bool_type,
10809 .c_int_type,
10810 .c_long_type,
10811 .c_longdouble_type,
10812 .c_longlong_type,
10813 .c_char_type,
10814 .c_short_type,
10815 .c_uint_type,
10816 .c_ulong_type,
10817 .c_ulonglong_type,
10818 .c_ushort_type,
10819 .comptime_float_type,
10820 .comptime_int_type,
10821 .f16_type,
10822 .f32_type,
10823 .f64_type,
10824 .f80_type,
10825 .f128_type,
10826 .i16_type,
10827 .i32_type,
10828 .i64_type,
10829 .i128_type,
10830 .i8_type,
10831 .isize_type,
10832 .type_type,
10833 .u16_type,
10834 .u29_type,
10835 .u32_type,
10836 .u64_type,
10837 .u128_type,
10838 .u1_type,
10839 .u8_type,
10840 .usize_type,
10841 => return true,
10842
10843 .void_type,
10844 .bool_false,
10845 .bool_true,
10846 .null_value,
10847 .undef,
10848 .noreturn_type,
10849 => return false,
10850
10851 else => unreachable, // that's all the values from `primitives`.
10852 } else {
10853 return false;
10854 }
10855 },
10856 }
10857 }
10858}
10859
10860/// Returns `true` if it is known the expression is a type that cannot be used at runtime;
10861/// `false` otherwise.
10862fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
10863 var node = start_node;
10864 while (true) {
10865 switch (tree.nodeTag(node)) {
10866 .root,
10867 .test_decl,
10868 .switch_case,
10869 .switch_case_inline,
10870 .switch_case_one,
10871 .switch_case_inline_one,
10872 .container_field_init,
10873 .container_field_align,
10874 .container_field,
10875 .asm_output,
10876 .asm_input,
10877 .global_var_decl,
10878 .local_var_decl,
10879 .simple_var_decl,
10880 .aligned_var_decl,
10881 => unreachable,
10882
10883 .@"return",
10884 .@"break",
10885 .@"continue",
10886 .bit_not,
10887 .bool_not,
10888 .@"defer",
10889 .@"errdefer",
10890 .address_of,
10891 .negation,
10892 .negation_wrap,
10893 .@"resume",
10894 .array_type,
10895 .@"suspend",
10896 .fn_decl,
10897 .anyframe_literal,
10898 .number_literal,
10899 .enum_literal,
10900 .string_literal,
10901 .multiline_string_literal,
10902 .char_literal,
10903 .unreachable_literal,
10904 .error_set_decl,
10905 .container_decl,
10906 .container_decl_trailing,
10907 .container_decl_two,
10908 .container_decl_two_trailing,
10909 .container_decl_arg,
10910 .container_decl_arg_trailing,
10911 .tagged_union,
10912 .tagged_union_trailing,
10913 .tagged_union_two,
10914 .tagged_union_two_trailing,
10915 .tagged_union_enum_tag,
10916 .tagged_union_enum_tag_trailing,
10917 .@"asm",
10918 .asm_simple,
10919 .add,
10920 .add_wrap,
10921 .add_sat,
10922 .array_cat,
10923 .array_mult,
10924 .assign,
10925 .assign_destructure,
10926 .assign_bit_and,
10927 .assign_bit_or,
10928 .assign_shl,
10929 .assign_shl_sat,
10930 .assign_shr,
10931 .assign_bit_xor,
10932 .assign_div,
10933 .assign_sub,
10934 .assign_sub_wrap,
10935 .assign_sub_sat,
10936 .assign_mod,
10937 .assign_add,
10938 .assign_add_wrap,
10939 .assign_add_sat,
10940 .assign_mul,
10941 .assign_mul_wrap,
10942 .assign_mul_sat,
10943 .bang_equal,
10944 .bit_and,
10945 .bit_or,
10946 .shl,
10947 .shl_sat,
10948 .shr,
10949 .bit_xor,
10950 .bool_and,
10951 .bool_or,
10952 .div,
10953 .equal_equal,
10954 .error_union,
10955 .greater_or_equal,
10956 .greater_than,
10957 .less_or_equal,
10958 .less_than,
10959 .merge_error_sets,
10960 .mod,
10961 .mul,
10962 .mul_wrap,
10963 .mul_sat,
10964 .switch_range,
10965 .for_range,
10966 .field_access,
10967 .sub,
10968 .sub_wrap,
10969 .sub_sat,
10970 .slice,
10971 .slice_open,
10972 .slice_sentinel,
10973 .deref,
10974 .array_access,
10975 .error_value,
10976 .while_simple,
10977 .while_cont,
10978 .for_simple,
10979 .if_simple,
10980 .@"catch",
10981 .@"orelse",
10982 .array_init_one,
10983 .array_init_one_comma,
10984 .array_init_dot_two,
10985 .array_init_dot_two_comma,
10986 .array_init_dot,
10987 .array_init_dot_comma,
10988 .array_init,
10989 .array_init_comma,
10990 .struct_init_one,
10991 .struct_init_one_comma,
10992 .struct_init_dot_two,
10993 .struct_init_dot_two_comma,
10994 .struct_init_dot,
10995 .struct_init_dot_comma,
10996 .struct_init,
10997 .struct_init_comma,
10998 .@"while",
10999 .@"if",
11000 .@"for",
11001 .@"switch",
11002 .switch_comma,
11003 .call_one,
11004 .call_one_comma,
11005 .call,
11006 .call_comma,
11007 .block_two,
11008 .block_two_semicolon,
11009 .block,
11010 .block_semicolon,
11011 .builtin_call,
11012 .builtin_call_comma,
11013 .builtin_call_two,
11014 .builtin_call_two_comma,
11015 .ptr_type_aligned,
11016 .ptr_type_sentinel,
11017 .ptr_type,
11018 .ptr_type_bit_range,
11019 .optional_type,
11020 .anyframe_type,
11021 .array_type_sentinel,
11022 => return false,
11023
11024 // these are function bodies, not pointers
11025 .fn_proto_simple,
11026 .fn_proto_multi,
11027 .fn_proto_one,
11028 .fn_proto,
11029 => return true,
11030
11031 // Forward the question to the LHS sub-expression.
11032 .@"try",
11033 .@"comptime",
11034 .@"nosuspend",
11035 => node = tree.nodeData(node).node,
11036 .grouped_expression,
11037 .unwrap_optional,
11038 => node = tree.nodeData(node).node_and_token[0],
11039
11040 .identifier => {
11041 const ident_bytes = tree.tokenSlice(tree.nodeMainToken(node));
11042 if (primitive_instrs.get(ident_bytes)) |primitive| switch (primitive) {
11043 .anyerror_type,
11044 .anyframe_type,
11045 .anyopaque_type,
11046 .bool_type,
11047 .c_int_type,
11048 .c_long_type,
11049 .c_longdouble_type,
11050 .c_longlong_type,
11051 .c_char_type,
11052 .c_short_type,
11053 .c_uint_type,
11054 .c_ulong_type,
11055 .c_ulonglong_type,
11056 .c_ushort_type,
11057 .f16_type,
11058 .f32_type,
11059 .f64_type,
11060 .f80_type,
11061 .f128_type,
11062 .i16_type,
11063 .i32_type,
11064 .i64_type,
11065 .i128_type,
11066 .i8_type,
11067 .isize_type,
11068 .u16_type,
11069 .u29_type,
11070 .u32_type,
11071 .u64_type,
11072 .u128_type,
11073 .u1_type,
11074 .u8_type,
11075 .usize_type,
11076 .void_type,
11077 .bool_false,
11078 .bool_true,
11079 .null_value,
11080 .undef,
11081 .noreturn_type,
11082 => return false,
11083
11084 .comptime_float_type,
11085 .comptime_int_type,
11086 .type_type,
11087 => return true,
11088
11089 else => unreachable, // that's all the values from `primitives`.
11090 } else {
11091 return false;
11092 }
11093 },
11094 }
11095 }
11096}
11097
11098/// Applies `rl` semantics to `result`. Expressions which do not do their own handling of
11099/// result locations must call this function on their result.
11100/// As an example, if `ri.rl` is `.ptr`, it will write the result to the pointer.
11101/// If `ri.rl` is `.ty`, it will coerce the result to the type.
11102/// Assumes nothing stacked on `gz`.
11103fn rvalue(
11104 gz: *GenZir,
11105 ri: ResultInfo,
11106 raw_result: Zir.Inst.Ref,
11107 src_node: Ast.Node.Index,
11108) InnerError!Zir.Inst.Ref {
11109 return rvalueInner(gz, ri, raw_result, src_node, true);
11110}
1111110471
11112/// Like `rvalue`, but refuses to perform coercions before taking references for10472/// Like `rvalue`, but refuses to perform coercions before taking references for
11113/// the `ref_coerced_ty` result type. This is used for local variables which do10473/// the `ref_coerced_ty` result type. This is used for local variables which do
...@@ -13044,18 +12404,19 @@ const GenZir = struct {...@@ -13044,18 +12404,19 @@ const GenZir = struct {
1304412404
13045 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {12405 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
13046 src_node: Ast.Node.Index,12406 src_node: Ast.Node.Index,
13047 captures_len: u32,12407 name_strat: Zir.Inst.NameStrategy,
13048 fields_len: u32,
13049 decls_len: u32,
13050 has_backing_int: bool,
13051 layout: std.builtin.Type.ContainerLayout,12408 layout: std.builtin.Type.ContainerLayout,
13052 known_non_opv: bool,12409 backing_int_type: Zir.Inst.Ref,
13053 known_comptime_only: bool,12410 decls_len: u32,
12411 fields_len: u32,
12412 any_field_aligns: bool,
12413 any_field_defaults: bool,
13054 any_comptime_fields: bool,12414 any_comptime_fields: bool,
13055 any_default_inits: bool,
13056 any_aligned_fields: bool,
13057 fields_hash: std.zig.SrcHash,12415 fields_hash: std.zig.SrcHash,
13058 name_strat: Zir.Inst.NameStrategy,12416 captures: []const Zir.Inst.Capture,
12417 capture_names: []const Zir.NullTerminatedString,
12418 /// The trailing declaration list, field information, and body instructions.
12419 remaining: []const u32,
13059 }) !void {12420 }) !void {
13060 const astgen = gz.astgen;12421 const astgen = gz.astgen;
13061 const gpa = astgen.gpa;12422 const gpa = astgen.gpa;
...@@ -13063,9 +12424,16 @@ const GenZir = struct {...@@ -13063,9 +12424,16 @@ const GenZir = struct {
13063 // Node .root is valid for the root `struct_decl` of a file!12424 // Node .root is valid for the root `struct_decl` of a file!
13064 assert(args.src_node != .root or gz.parent.tag == .top);12425 assert(args.src_node != .root or gz.parent.tag == .top);
1306512426
12427 const captures_len: u32 = @intCast(args.captures.len);
12428 assert(args.capture_names.len == captures_len);
12429
13066 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);12430 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1306712431
13068 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len + 3);12432 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len +
12433 4 + // `captures_len`, `decls_len`, `fields_len`, `backing_int_type`
12434 captures_len * 2 + // `capture`, `capture_name`
12435 args.remaining.len);
12436
13069 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{12437 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
13070 .fields_hash_0 = fields_hash_arr[0],12438 .fields_hash_0 = fields_hash_arr[0],
13071 .fields_hash_1 = fields_hash_arr[1],12439 .fields_hash_1 = fields_hash_arr[1],
...@@ -13075,31 +12443,28 @@ const GenZir = struct {...@@ -13075,31 +12443,28 @@ const GenZir = struct {
13075 .src_node = args.src_node,12443 .src_node = args.src_node,
13076 });12444 });
1307712445
13078 if (args.captures_len != 0) {12446 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
13079 astgen.extra.appendAssumeCapacity(args.captures_len);12447 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
13080 }12448 if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);
13081 if (args.fields_len != 0) {12449 if (args.backing_int_type != .none) astgen.extra.appendAssumeCapacity(@intFromEnum(args.backing_int_type));
13082 astgen.extra.appendAssumeCapacity(args.fields_len);12450 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
13083 }12451 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
13084 if (args.decls_len != 0) {12452 astgen.extra.appendSliceAssumeCapacity(args.remaining);
13085 astgen.extra.appendAssumeCapacity(args.decls_len);12453
13086 }
13087 astgen.instructions.set(@intFromEnum(inst), .{12454 astgen.instructions.set(@intFromEnum(inst), .{
13088 .tag = .extended,12455 .tag = .extended,
13089 .data = .{ .extended = .{12456 .data = .{ .extended = .{
13090 .opcode = .struct_decl,12457 .opcode = .struct_decl,
13091 .small = @bitCast(Zir.Inst.StructDecl.Small{12458 .small = @bitCast(Zir.Inst.StructDecl.Small{
13092 .has_captures_len = args.captures_len != 0,12459 .has_captures_len = captures_len != 0,
13093 .has_fields_len = args.fields_len != 0,
13094 .has_decls_len = args.decls_len != 0,12460 .has_decls_len = args.decls_len != 0,
13095 .has_backing_int = args.has_backing_int,12461 .has_fields_len = args.fields_len != 0,
13096 .known_non_opv = args.known_non_opv,
13097 .known_comptime_only = args.known_comptime_only,
13098 .name_strategy = args.name_strat,12462 .name_strategy = args.name_strat,
13099 .layout = args.layout,12463 .layout = args.layout,
12464 .has_backing_int_type = args.backing_int_type != .none,
12465 .any_field_aligns = args.any_field_aligns,
12466 .any_field_defaults = args.any_field_defaults,
13100 .any_comptime_fields = args.any_comptime_fields,12467 .any_comptime_fields = args.any_comptime_fields,
13101 .any_default_inits = args.any_default_inits,
13102 .any_aligned_fields = args.any_aligned_fields,
13103 }),12468 }),
13104 .operand = payload_index,12469 .operand = payload_index,
13105 } },12470 } },
...@@ -13108,25 +12473,34 @@ const GenZir = struct {...@@ -13108,25 +12473,34 @@ const GenZir = struct {
1310812473
13109 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct {12474 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
13110 src_node: Ast.Node.Index,12475 src_node: Ast.Node.Index,
13111 tag_type: Zir.Inst.Ref,12476 name_strat: Zir.Inst.NameStrategy,
13112 captures_len: u32,12477 kind: Zir.Inst.UnionDecl.Kind,
13113 body_len: u32,12478 arg_type: Zir.Inst.Ref,
13114 fields_len: u32,
13115 decls_len: u32,12479 decls_len: u32,
13116 layout: std.builtin.Type.ContainerLayout,12480 fields_len: u32,
13117 auto_enum_tag: bool,12481 any_field_aligns: bool,
13118 any_aligned_fields: bool,12482 any_field_values: bool,
13119 fields_hash: std.zig.SrcHash,12483 fields_hash: std.zig.SrcHash,
13120 name_strat: Zir.Inst.NameStrategy,12484 captures: []const Zir.Inst.Capture,
12485 capture_names: []const Zir.NullTerminatedString,
12486 /// The trailing declaration list, field information, and body instructions.
12487 remaining: []const u32,
13121 }) !void {12488 }) !void {
13122 const astgen = gz.astgen;12489 const astgen = gz.astgen;
13123 const gpa = astgen.gpa;12490 const gpa = astgen.gpa;
1312412491
13125 assert(args.src_node != .root);12492 assert(args.src_node != .root);
1312612493
12494 const captures_len: u32 = @intCast(args.captures.len);
12495 assert(args.capture_names.len == captures_len);
12496
13127 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);12497 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1312812498
13129 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).@"struct".fields.len + 5);12499 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).@"struct".fields.len +
12500 4 + // `captures_len`, `decls_len`, `fields_len`, `backing_int_type`
12501 captures_len * 2 + // `capture`, `capture_name`
12502 args.remaining.len);
12503
13130 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{12504 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{
13131 .fields_hash_0 = fields_hash_arr[0],12505 .fields_hash_0 = fields_hash_arr[0],
13132 .fields_hash_1 = fields_hash_arr[1],12506 .fields_hash_1 = fields_hash_arr[1],
...@@ -13136,60 +12510,68 @@ const GenZir = struct {...@@ -13136,60 +12510,68 @@ const GenZir = struct {
13136 .src_node = args.src_node,12510 .src_node = args.src_node,
13137 });12511 });
1313812512
13139 if (args.tag_type != .none) {12513 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
13140 astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));12514 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
13141 }12515 if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);
13142 if (args.captures_len != 0) {12516 if (args.kind.hasArgType()) {
13143 astgen.extra.appendAssumeCapacity(args.captures_len);12517 assert(args.arg_type != .none);
13144 }12518 astgen.extra.appendAssumeCapacity(@intFromEnum(args.arg_type));
13145 if (args.body_len != 0) {12519 } else {
13146 astgen.extra.appendAssumeCapacity(args.body_len);12520 assert(args.arg_type == .none);
13147 }
13148 if (args.fields_len != 0) {
13149 astgen.extra.appendAssumeCapacity(args.fields_len);
13150 }
13151 if (args.decls_len != 0) {
13152 astgen.extra.appendAssumeCapacity(args.decls_len);
13153 }12521 }
12522 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
12523 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
12524 astgen.extra.appendSliceAssumeCapacity(args.remaining);
12525
13154 astgen.instructions.set(@intFromEnum(inst), .{12526 astgen.instructions.set(@intFromEnum(inst), .{
13155 .tag = .extended,12527 .tag = .extended,
13156 .data = .{ .extended = .{12528 .data = .{
13157 .opcode = .union_decl,12529 .extended = .{
13158 .small = @bitCast(Zir.Inst.UnionDecl.Small{12530 .opcode = .union_decl,
13159 .has_tag_type = args.tag_type != .none,12531 .small = @bitCast(Zir.Inst.UnionDecl.Small{
13160 .has_captures_len = args.captures_len != 0,12532 .has_captures_len = captures_len != 0,
13161 .has_body_len = args.body_len != 0,12533 .has_decls_len = args.decls_len != 0,
13162 .has_fields_len = args.fields_len != 0,12534 .has_fields_len = args.fields_len != 0,
13163 .has_decls_len = args.decls_len != 0,12535 .name_strategy = args.name_strat,
13164 .name_strategy = args.name_strat,12536 .kind = args.kind,
13165 .layout = args.layout,12537 .any_field_aligns = args.any_field_aligns,
13166 .auto_enum_tag = args.auto_enum_tag,12538 .any_field_values = args.any_field_values,
13167 .any_aligned_fields = args.any_aligned_fields,12539 }),
13168 }),12540 .operand = payload_index,
13169 .operand = payload_index,12541 },
13170 } },12542 },
13171 });12543 });
13172 }12544 }
1317312545
13174 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {12546 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
13175 src_node: Ast.Node.Index,12547 src_node: Ast.Node.Index,
12548 name_strat: Zir.Inst.NameStrategy,
13176 tag_type: Zir.Inst.Ref,12549 tag_type: Zir.Inst.Ref,
13177 captures_len: u32,
13178 body_len: u32,
13179 fields_len: u32,
13180 decls_len: u32,
13181 nonexhaustive: bool,12550 nonexhaustive: bool,
12551 decls_len: u32,
12552 fields_len: u32,
12553 any_field_values: bool,
13182 fields_hash: std.zig.SrcHash,12554 fields_hash: std.zig.SrcHash,
13183 name_strat: Zir.Inst.NameStrategy,12555 captures: []const Zir.Inst.Capture,
12556 capture_names: []const Zir.NullTerminatedString,
12557 /// The trailing declaration list, field information, and body instructions.
12558 remaining: []const u32,
13184 }) !void {12559 }) !void {
13185 const astgen = gz.astgen;12560 const astgen = gz.astgen;
13186 const gpa = astgen.gpa;12561 const gpa = astgen.gpa;
1318712562
13188 assert(args.src_node != .root);12563 assert(args.src_node != .root);
1318912564
12565 const captures_len: u32 = @intCast(args.captures.len);
12566 assert(args.capture_names.len == captures_len);
12567
13190 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);12568 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1319112569
13192 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).@"struct".fields.len + 5);12570 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).@"struct".fields.len +
12571 4 + // `captures_len`, `decls_len`, `fields_len`, `tag_type`
12572 captures_len * 2 + // `capture`, `capture_name`
12573 args.remaining.len);
12574
13193 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{12575 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{
13194 .fields_hash_0 = fields_hash_arr[0],12576 .fields_hash_0 = fields_hash_arr[0],
13195 .fields_hash_1 = fields_hash_arr[1],12577 .fields_hash_1 = fields_hash_arr[1],
...@@ -13199,33 +12581,26 @@ const GenZir = struct {...@@ -13199,33 +12581,26 @@ const GenZir = struct {
13199 .src_node = args.src_node,12581 .src_node = args.src_node,
13200 });12582 });
1320112583
13202 if (args.tag_type != .none) {12584 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
13203 astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));12585 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
13204 }12586 if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);
13205 if (args.captures_len != 0) {12587 if (args.tag_type != .none) astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));
13206 astgen.extra.appendAssumeCapacity(args.captures_len);12588 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
13207 }12589 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
13208 if (args.body_len != 0) {12590 astgen.extra.appendSliceAssumeCapacity(args.remaining);
13209 astgen.extra.appendAssumeCapacity(args.body_len);12591
13210 }
13211 if (args.fields_len != 0) {
13212 astgen.extra.appendAssumeCapacity(args.fields_len);
13213 }
13214 if (args.decls_len != 0) {
13215 astgen.extra.appendAssumeCapacity(args.decls_len);
13216 }
13217 astgen.instructions.set(@intFromEnum(inst), .{12592 astgen.instructions.set(@intFromEnum(inst), .{
13218 .tag = .extended,12593 .tag = .extended,
13219 .data = .{ .extended = .{12594 .data = .{ .extended = .{
13220 .opcode = .enum_decl,12595 .opcode = .enum_decl,
13221 .small = @bitCast(Zir.Inst.EnumDecl.Small{12596 .small = @bitCast(Zir.Inst.EnumDecl.Small{
13222 .has_tag_type = args.tag_type != .none,12597 .has_captures_len = captures_len != 0,
13223 .has_captures_len = args.captures_len != 0,
13224 .has_body_len = args.body_len != 0,
13225 .has_fields_len = args.fields_len != 0,
13226 .has_decls_len = args.decls_len != 0,12598 .has_decls_len = args.decls_len != 0,
12599 .has_fields_len = args.fields_len != 0,
13227 .name_strategy = args.name_strat,12600 .name_strategy = args.name_strat,
12601 .has_tag_type = args.tag_type != .none,
13228 .nonexhaustive = args.nonexhaustive,12602 .nonexhaustive = args.nonexhaustive,
12603 .any_field_values = args.any_field_values,
13229 }),12604 }),
13230 .operand = payload_index,12605 .operand = payload_index,
13231 } },12606 } },
...@@ -13234,33 +12609,41 @@ const GenZir = struct {...@@ -13234,33 +12609,41 @@ const GenZir = struct {
1323412609
13235 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct {12610 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
13236 src_node: Ast.Node.Index,12611 src_node: Ast.Node.Index,
13237 captures_len: u32,
13238 decls_len: u32,
13239 name_strat: Zir.Inst.NameStrategy,12612 name_strat: Zir.Inst.NameStrategy,
12613 decls_len: u32,
12614 captures: []const Zir.Inst.Capture,
12615 capture_names: []const Zir.NullTerminatedString,
12616 decls: []const Zir.Inst.Index,
13240 }) !void {12617 }) !void {
13241 const astgen = gz.astgen;12618 const astgen = gz.astgen;
13242 const gpa = astgen.gpa;12619 const gpa = astgen.gpa;
1324312620
13244 assert(args.src_node != .root);12621 assert(args.src_node != .root);
1324512622
13246 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).@"struct".fields.len + 2);12623 const captures_len: u32 = @intCast(args.captures.len);
12624 assert(args.capture_names.len == captures_len);
12625
12626 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).@"struct".fields.len +
12627 2 + // `captures_len`, `decls_len`
12628 captures_len * 2 + // `capture`, `capture_name`
12629 args.decls.len);
12630
13247 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{12631 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{
13248 .src_line = astgen.source_line,12632 .src_line = astgen.source_line,
13249 .src_node = args.src_node,12633 .src_node = args.src_node,
13250 });12634 });
12635 if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
12636 if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
12637 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
12638 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
12639 astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.decls));
1325112640
13252 if (args.captures_len != 0) {
13253 astgen.extra.appendAssumeCapacity(args.captures_len);
13254 }
13255 if (args.decls_len != 0) {
13256 astgen.extra.appendAssumeCapacity(args.decls_len);
13257 }
13258 astgen.instructions.set(@intFromEnum(inst), .{12641 astgen.instructions.set(@intFromEnum(inst), .{
13259 .tag = .extended,12642 .tag = .extended,
13260 .data = .{ .extended = .{12643 .data = .{ .extended = .{
13261 .opcode = .opaque_decl,12644 .opcode = .opaque_decl,
13262 .small = @bitCast(Zir.Inst.OpaqueDecl.Small{12645 .small = @bitCast(Zir.Inst.OpaqueDecl.Small{
13263 .has_captures_len = args.captures_len != 0,12646 .has_captures_len = captures_len != 0,
13264 .has_decls_len = args.decls_len != 0,12647 .has_decls_len = args.decls_len != 0,
13265 .name_strategy = args.name_strat,12648 .name_strategy = args.name_strat,
13266 }),12649 }),
...@@ -13484,14 +12867,24 @@ fn restoreSourceCursor(astgen: *AstGen, cursor: SourceCursor) void {...@@ -13484,14 +12867,24 @@ fn restoreSourceCursor(astgen: *AstGen, cursor: SourceCursor) void {
13484 astgen.source_column = cursor.column;12867 astgen.source_column = cursor.column;
13485}12868}
1348612869
12870const ScanContainerResult = struct {
12871 /// Includes unnamed declarations (e.g. `comptime` decls)
12872 decls_len: u32,
12873 fields_len: u32,
12874 any_field_aligns: bool,
12875 any_field_values: bool,
12876 any_comptime_fields: bool,
12877 /// Whether there is a field named `_` (indicating a non-exhaustive enum)
12878 has_underscore_field: bool,
12879};
12880
13487/// Detects name conflicts for decls and fields, and populates `namespace.decls` with all named declarations.12881/// Detects name conflicts for decls and fields, and populates `namespace.decls` with all named declarations.
13488/// Returns the number of declarations in the namespace, including unnamed declarations (e.g. `comptime` decls).
13489fn scanContainer(12882fn scanContainer(
13490 astgen: *AstGen,12883 astgen: *AstGen,
13491 namespace: *Scope.Namespace,12884 namespace: *Scope.Namespace,
13492 members: []const Ast.Node.Index,12885 members: []const Ast.Node.Index,
13493 container_kind: enum { @"struct", @"union", @"enum", @"opaque" },12886 container_kind: enum { @"struct", @"union", @"enum", @"opaque" },
13494) !u32 {12887) !ScanContainerResult {
13495 const gpa = astgen.gpa;12888 const gpa = astgen.gpa;
13496 const tree = astgen.tree;12889 const tree = astgen.tree;
1349712890
...@@ -13521,6 +12914,10 @@ fn scanContainer(...@@ -13521,6 +12914,10 @@ fn scanContainer(
1352112914
13522 var any_duplicates = false;12915 var any_duplicates = false;
13523 var decl_count: u32 = 0;12916 var decl_count: u32 = 0;
12917 var any_field_aligns = false;
12918 var any_field_values = false;
12919 var any_comptime_fields = false;
12920 var has_underscore_field = false;
13524 for (members) |member_node| {12921 for (members) |member_node| {
13525 const Kind = enum { decl, field };12922 const Kind = enum { decl, field };
13526 const kind: Kind, const name_token = switch (tree.nodeTag(member_node)) {12923 const kind: Kind, const name_token = switch (tree.nodeTag(member_node)) {
...@@ -13533,6 +12930,10 @@ fn scanContainer(...@@ -13533,6 +12930,10 @@ fn scanContainer(
13533 .@"struct", .@"opaque" => {},12930 .@"struct", .@"opaque" => {},
13534 .@"union", .@"enum" => full.convertToNonTupleLike(astgen.tree),12931 .@"union", .@"enum" => full.convertToNonTupleLike(astgen.tree),
13535 }12932 }
12933 if (full.ast.align_expr != .none) any_field_aligns = true;
12934 if (full.ast.value_expr != .none) any_field_values = true;
12935 if (full.comptime_token != null) any_comptime_fields = true;
12936 if (mem.eql(u8, tree.tokenSlice(full.ast.main_token), "_")) has_underscore_field = true;
13536 if (full.ast.tuple_like) continue;12937 if (full.ast.tuple_like) continue;
13537 break :blk .{ .field, full.ast.main_token };12938 break :blk .{ .field, full.ast.main_token };
13538 },12939 },
...@@ -13698,7 +13099,14 @@ fn scanContainer(...@@ -13698,7 +13099,14 @@ fn scanContainer(
1369813099
13699 if (!any_duplicates) {13100 if (!any_duplicates) {
13700 if (any_invalid_declarations) return error.AnalysisFail;13101 if (any_invalid_declarations) return error.AnalysisFail;
13701 return decl_count;13102 return .{
13103 .decls_len = decl_count,
13104 .fields_len = @intCast(members.len - decl_count),
13105 .any_field_aligns = any_field_aligns,
13106 .any_field_values = any_field_values,
13107 .any_comptime_fields = any_comptime_fields,
13108 .has_underscore_field = has_underscore_field,
13109 };
13702 }13110 }
1370313111
13704 for (names.keys(), names.values()) |name, first| {13112 for (names.keys(), names.values()) |name, first| {
...@@ -13954,7 +13362,7 @@ const DeclarationName = union(enum) {...@@ -13954,7 +13362,7 @@ const DeclarationName = union(enum) {
13954};13362};
1395513363
13956fn addFailedDeclaration(13364fn addFailedDeclaration(
13957 wip_members: *WipMembers,13365 wip_decls: *WipDecls,
13958 gz: *GenZir,13366 gz: *GenZir,
13959 kind: Zir.Inst.Declaration.Unwrapped.Kind,13367 kind: Zir.Inst.Declaration.Unwrapped.Kind,
13960 name: Zir.NullTerminatedString,13368 name: Zir.NullTerminatedString,
...@@ -13962,7 +13370,7 @@ fn addFailedDeclaration(...@@ -13962,7 +13370,7 @@ fn addFailedDeclaration(
13962 is_pub: bool,13370 is_pub: bool,
13963) !void {13371) !void {
13964 const decl_inst = try gz.makeDeclaration(src_node);13372 const decl_inst = try gz.makeDeclaration(src_node);
13965 wip_members.nextDecl(decl_inst);13373 wip_decls.nextDecl(decl_inst);
1396613374
13967 var dummy_gz = gz.makeSubBlock(&gz.base);13375 var dummy_gz = gz.makeSubBlock(&gz.base);
1396813376
lib/std/zig/Zir.zig+564-378
...@@ -2443,7 +2443,7 @@ pub const Inst = struct {...@@ -2443,7 +2443,7 @@ pub const Inst = struct {
2443 has_align: bool,2443 has_align: bool,
2444 has_addrspace: bool,2444 has_addrspace: bool,
2445 has_bit_range: bool,2445 has_bit_range: bool,
2446 _: u1 = undefined,2446 _: u1 = 0,
2447 },2447 },
2448 size: std.builtin.Type.Pointer.Size,2448 size: std.builtin.Type.Pointer.Size,
2449 /// Index into extra. See `PtrType`.2449 /// Index into extra. See `PtrType`.
...@@ -2668,7 +2668,7 @@ pub const Inst = struct {...@@ -2668,7 +2668,7 @@ pub const Inst = struct {
2668 has_ret_ty_body: bool,2668 has_ret_ty_body: bool,
2669 has_any_noalias: bool,2669 has_any_noalias: bool,
2670 ret_ty_is_generic: bool,2670 ret_ty_is_generic: bool,
2671 _: u23 = undefined,2671 _: u23 = 0,
2672 };2672 };
2673 };2673 };
26742674
...@@ -3134,7 +3134,7 @@ pub const Inst = struct {...@@ -3134,7 +3134,7 @@ pub const Inst = struct {
3134 pub const Flags = packed struct {3134 pub const Flags = packed struct {
3135 is_nosuspend: bool,3135 is_nosuspend: bool,
3136 ensure_result_used: bool,3136 ensure_result_used: bool,
3137 _: u30 = undefined,3137 _: u30 = 0,
31383138
3139 comptime {3139 comptime {
3140 if (@sizeOf(Flags) != 4 or @bitSizeOf(Flags) != 32)3140 if (@sizeOf(Flags) != 4 or @bitSizeOf(Flags) != 32)
...@@ -3462,33 +3462,20 @@ pub const Inst = struct {...@@ -3462,33 +3462,20 @@ pub const Inst = struct {
3462 };3462 };
34633463
3464 /// Trailing:3464 /// Trailing:
3465 /// 0. captures_len: u32 // if has_captures_len3465 /// 0. captures_len: u32 // if `has_captures_len`
3466 /// 1. fields_len: u32, // if has_fields_len3466 /// 1. decls_len: u32, // if `has_decls_len`
3467 /// 2. decls_len: u32, // if has_decls_len3467 /// 2. fields_len: u32, // if `has_fields_len`
3468 /// 3. capture: Capture // for every captures_len3468 /// 3. backing_int_type: Ref // if `has_backing_int`
3469 /// 4. capture_name: NullTerminatedString // for every captures_len3469 /// 4. capture: Capture // for every `captures_len`
3470 /// 5. backing_int_body_len: u32, // if has_backing_int3470 /// 5. capture_name: NullTerminatedString // for every `captures_len`
3471 /// 6. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 03471 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
3472 /// 7. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 03472 /// 7. field_name: NullTerminatedString // for every `fields_len`
3473 /// 8. decl: Index, // for every decls_len; points to a `declaration` instruction3473 /// 8. field_type_body_len: u32 // for every `fields_len`
3474 /// 9. flags: u32 // for every 8 fields3474 /// 9. field_align_body_len: u32 // for every `fields_len` if `any_field_aligns`
3475 /// - sets of 4 bits:3475 /// 10. field_default_body_len: u32 // for every `fields_len` if `any_field_defaults`
3476 /// 0b000X: whether corresponding field has an align expression3476 /// 11. field_comptime_bits: u32 // one bit per `fields_len` if `any_comptime_fields`
3477 /// 0b00X0: whether corresponding field has a default expression3477 /// // LSB is first field, minimum number of `u32` needed
3478 /// 0b0X00: whether corresponding field is comptime3478 /// 12. body_inst: Inst.Index // type body, then align body, then default body, for each field
3479 /// 0bX000: whether corresponding field has a type expression
3480 /// 10. fields: { // for every fields_len
3481 /// field_name: u32,
3482 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
3483 /// field_type_body_len: u32, // if corresponding bit is set
3484 /// align_body_len: u32, // if corresponding bit is set
3485 /// init_body_len: u32, // if corresponding bit is set
3486 /// }
3487 /// 11. bodies: { // for every fields_len
3488 /// field_type_body_inst: Inst, // for each field_type_body_len
3489 /// align_body_inst: Inst, // for each align_body_len
3490 /// init_body_inst: Inst, // for each init_body_len
3491 /// }
3492 pub const StructDecl = struct {3479 pub const StructDecl = struct {
3493 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.3480 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
3494 // This hash contains the source of all fields, and any specified attributes (`extern`, backing type, etc).3481 // This hash contains the source of all fields, and any specified attributes (`extern`, backing type, etc).
...@@ -3500,19 +3487,18 @@ pub const Inst = struct {...@@ -3500,19 +3487,18 @@ pub const Inst = struct {
3500 /// This node provides a new absolute baseline node for all instructions within this struct.3487 /// This node provides a new absolute baseline node for all instructions within this struct.
3501 src_node: Ast.Node.Index,3488 src_node: Ast.Node.Index,
35023489
3503 pub const Small = packed struct {3490 pub const Small = packed struct(u16) {
3504 has_captures_len: bool,3491 has_captures_len: bool,
3505 has_fields_len: bool,
3506 has_decls_len: bool,3492 has_decls_len: bool,
3507 has_backing_int: bool,3493 has_fields_len: bool,
3508 known_non_opv: bool,
3509 known_comptime_only: bool,
3510 name_strategy: NameStrategy,3494 name_strategy: NameStrategy,
3511 layout: std.builtin.Type.ContainerLayout,3495 layout: std.builtin.Type.ContainerLayout,
3512 any_default_inits: bool,3496 /// Always `false` if `layout != .@"packed"`.
3497 has_backing_int_type: bool,
3498 any_field_aligns: bool,
3499 any_field_defaults: bool,
3513 any_comptime_fields: bool,3500 any_comptime_fields: bool,
3514 any_aligned_fields: bool,3501 _: u5 = 0,
3515 _: u3 = undefined,
3516 };3502 };
3517 };3503 };
35183504
...@@ -3633,21 +3619,16 @@ pub const Inst = struct {...@@ -3633,21 +3619,16 @@ pub const Inst = struct {
3633 };3619 };
36343620
3635 /// Trailing:3621 /// Trailing:
3636 /// 0. tag_type: Ref, // if has_tag_type3622 /// 0. captures_len: u32, // if has_captures_len
3637 /// 1. captures_len: u32, // if has_captures_len3623 /// 1. decls_len: u32, // if has_decls_len
3638 /// 2. body_len: u32, // if has_body_len3624 /// 2. fields_len: u32, // if has_fields_len
3639 /// 3. fields_len: u32, // if has_fields_len3625 /// 3. tag_type: Ref, // if has_tag_type
3640 /// 4. decls_len: u32, // if has_decls_len3626 /// 4. capture: Capture // for every `captures_len`
3641 /// 5. capture: Capture // for every captures_len3627 /// 5. capture_name: NullTerminatedString // for every `captures_len`
3642 /// 6. capture_name: NullTerminatedString // for every captures_len3628 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
3643 /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction3629 /// 7. field_name: NullTerminatedString // for every `fields_len`
3644 /// 8. inst: Index // for every body_len3630 /// 8. field_value_body_len: u32 // for every `fields_len` if `any_field_values`
3645 /// 9. has_bits: u32 // for every 32 fields3631 /// 9. body_inst: Inst.Index // value body for each field
3646 /// - the bit is whether corresponding field has an value expression
3647 /// 10. fields: { // for every fields_len
3648 /// field_name: u32,
3649 /// value: Ref, // if corresponding bit is set
3650 /// }
3651 pub const EnumDecl = struct {3632 pub const EnumDecl = struct {
3652 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.3633 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
3653 // This hash contains the source of all fields, and the backing type if specified.3634 // This hash contains the source of all fields, and the backing type if specified.
...@@ -3659,40 +3640,31 @@ pub const Inst = struct {...@@ -3659,40 +3640,31 @@ pub const Inst = struct {
3659 /// This node provides a new absolute baseline node for all instructions within this struct.3640 /// This node provides a new absolute baseline node for all instructions within this struct.
3660 src_node: Ast.Node.Index,3641 src_node: Ast.Node.Index,
36613642
3662 pub const Small = packed struct {3643 pub const Small = packed struct(u16) {
3663 has_tag_type: bool,
3664 has_captures_len: bool,3644 has_captures_len: bool,
3665 has_body_len: bool,
3666 has_fields_len: bool,
3667 has_decls_len: bool,3645 has_decls_len: bool,
3646 has_fields_len: bool,
3668 name_strategy: NameStrategy,3647 name_strategy: NameStrategy,
3648 has_tag_type: bool,
3669 nonexhaustive: bool,3649 nonexhaustive: bool,
3670 _: u8 = undefined,3650 any_field_values: bool,
3651 _: u8 = 0,
3671 };3652 };
3672 };3653 };
36733654
3674 /// Trailing:3655 /// Trailing:
3675 /// 0. tag_type: Ref, // if has_tag_type3656 /// 0. captures_len: u32 // if `has_captures_len`
3676 /// 1. captures_len: u32 // if has_captures_len3657 /// 1. decls_len: u32, // if `has_decls_len`
3677 /// 2. body_len: u32, // if has_body_len3658 /// 2. fields_len: u32, // if `has_fields_len`
3678 /// 3. fields_len: u32, // if has_fields_len3659 /// 3. arg_type: Ref, // if `kind.hasArgType()`
3679 /// 4. decls_len: u32, // if has_decls_len3660 /// 4. capture: Capture // for every `captures_len`
3680 /// 5. capture: Capture // for every captures_len3661 /// 5. capture_name: NullTerminatedString // for every `captures_len`
3681 /// 6. capture_name: NullTerminatedString // for every captures_len3662 /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
3682 /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction3663 /// 7. field_name: NullTerminatedString // for every `fields_len`
3683 /// 8. inst: Index // for every body_len3664 /// 8. field_type_body_len: u32 // for every `fields_len`
3684 /// 9. has_bits: u32 // for every 8 fields3665 /// 9 . field_align_body_len: u32 // for every `fields_len` if `any_field_aligns`
3685 /// - sets of 4 bits:3666 /// 10. field_value_body_len: u32 // for every `fields_len` if `any_field_values`
3686 /// 0b000X: whether corresponding field has a type expression3667 /// 11. body_inst: Inst.Index // type body, then align body, then value body, for each field
3687 /// 0b00X0: whether corresponding field has a align expression
3688 /// 0b0X00: whether corresponding field has a tag value expression
3689 /// 0bX000: unused
3690 /// 10. fields: { // for every fields_len
3691 /// field_name: NullTerminatedString, // null terminated string index
3692 /// field_type: Ref, // if corresponding bit is set
3693 /// align: Ref, // if corresponding bit is set
3694 /// tag_value: Ref, // if corresponding bit is set
3695 /// }
3696 pub const UnionDecl = struct {3668 pub const UnionDecl = struct {
3697 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.3669 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
3698 // This hash contains the source of all fields, and any specified attributes (`extern` etc).3670 // This hash contains the source of all fields, and any specified attributes (`extern` etc).
...@@ -3704,23 +3676,47 @@ pub const Inst = struct {...@@ -3704,23 +3676,47 @@ pub const Inst = struct {
3704 /// This node provides a new absolute baseline node for all instructions within this struct.3676 /// This node provides a new absolute baseline node for all instructions within this struct.
3705 src_node: Ast.Node.Index,3677 src_node: Ast.Node.Index,
37063678
3707 pub const Small = packed struct {3679 pub const Small = packed struct(u16) {
3708 has_tag_type: bool,
3709 has_captures_len: bool,3680 has_captures_len: bool,
3710 has_body_len: bool,
3711 has_fields_len: bool,
3712 has_decls_len: bool,3681 has_decls_len: bool,
3682 has_fields_len: bool,
3713 name_strategy: NameStrategy,3683 name_strategy: NameStrategy,
3714 layout: std.builtin.Type.ContainerLayout,3684 kind: Kind,
3715 /// has_tag_type | auto_enum_tag | result3685 any_field_aligns: bool,
3716 /// -------------------------------------3686 any_field_values: bool,
3717 /// false | false | union { }3687 _: u6 = 0,
3718 /// false | true | union(enum) { }3688 };
3719 /// true | true | union(enum(T)) { }3689
3720 /// true | false | union(T) { }3690 pub const Kind = enum(u3) {
3721 auto_enum_tag: bool,3691 /// `union`
3722 any_aligned_fields: bool,3692 auto,
3723 _: u5 = undefined,3693 /// `union(T)`
3694 tagged_explicit,
3695 /// `union(enum)`
3696 tagged_enum,
3697 /// `union(enum(T))`
3698 tagged_enum_explicit,
3699 /// `extern union`
3700 @"extern",
3701 /// `packed union`
3702 @"packed",
3703 /// `packed union(T)`
3704 packed_explicit,
3705
3706 pub fn hasArgType(k: Kind) bool {
3707 return switch (k) {
3708 .auto, .tagged_enum, .@"extern", .@"packed" => false,
3709 .tagged_explicit, .tagged_enum_explicit, .packed_explicit => true,
3710 };
3711 }
3712
3713 pub fn layout(k: Kind) std.builtin.ContainerLayout {
3714 return switch (k) {
3715 .auto, .tagged_explicit, .tagged_enum, .tagged_enum_explicit => .auto,
3716 .@"extern" => .@"extern",
3717 .@"packed", .packed_explicit => .@"packed",
3718 };
3719 }
3724 };3720 };
3725 };3721 };
37263722
...@@ -3735,11 +3731,11 @@ pub const Inst = struct {...@@ -3735,11 +3731,11 @@ pub const Inst = struct {
3735 /// This node provides a new absolute baseline node for all instructions within this struct.3731 /// This node provides a new absolute baseline node for all instructions within this struct.
3736 src_node: Ast.Node.Index,3732 src_node: Ast.Node.Index,
37373733
3738 pub const Small = packed struct {3734 pub const Small = packed struct(u16) {
3739 has_captures_len: bool,3735 has_captures_len: bool,
3740 has_decls_len: bool,3736 has_decls_len: bool,
3741 name_strategy: NameStrategy,3737 name_strategy: NameStrategy,
3742 _: u12 = undefined,3738 _: u12 = 0,
3743 };3739 };
3744 };3740 };
37453741
...@@ -3904,12 +3900,12 @@ pub const Inst = struct {...@@ -3904,12 +3900,12 @@ pub const Inst = struct {
3904 pub const AllocExtended = struct {3900 pub const AllocExtended = struct {
3905 src_node: Ast.Node.Offset,3901 src_node: Ast.Node.Offset,
39063902
3907 pub const Small = packed struct {3903 pub const Small = packed struct(u16) {
3908 has_type: bool,3904 has_type: bool,
3909 has_align: bool,3905 has_align: bool,
3910 is_const: bool,3906 is_const: bool,
3911 is_comptime: bool,3907 is_comptime: bool,
3912 _: u12 = undefined,3908 _: u12 = 0,
3913 };3909 };
3914 };3910 };
39153911
...@@ -4012,133 +4008,18 @@ pub const Inst = struct {...@@ -4012,133 +4008,18 @@ pub const Inst = struct {
4012 };4008 };
4013};4009};
40144010
4011/// MLUGG TODO: delete this!
4015pub const DeclIterator = struct {4012pub const DeclIterator = struct {
4016 extra_index: u32,4013 decls: []const Inst.Index,
4017 decls_remaining: u32,4014 index: usize,
4018 zir: Zir,
4019
4020 pub fn next(it: *DeclIterator) ?Inst.Index {4015 pub fn next(it: *DeclIterator) ?Inst.Index {
4021 if (it.decls_remaining == 0) return null;4016 if (it.index == it.decls.len) return null;
4022 const decl_inst: Zir.Inst.Index = @enumFromInt(it.zir.extra[it.extra_index]);4017 defer it.index += 1;
4023 it.extra_index += 1;4018 return it.decls[it.index];
4024 it.decls_remaining -= 1;
4025 assert(it.zir.instructions.items(.tag)[@intFromEnum(decl_inst)] == .declaration);
4026 return decl_inst;
4027 }4019 }
4028};4020};
4029
4030pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {4021pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
4031 const inst = zir.instructions.get(@intFromEnum(decl_inst));4022 return .{ .decls = zir.typeDecls(decl_inst), .index = 0 };
4032 assert(inst.tag == .extended);
4033 const extended = inst.data.extended;
4034 switch (extended.opcode) {
4035 .struct_decl => {
4036 const small: Inst.StructDecl.Small = @bitCast(extended.small);
4037 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len);
4038 const captures_len = if (small.has_captures_len) captures_len: {
4039 const captures_len = zir.extra[extra_index];
4040 extra_index += 1;
4041 break :captures_len captures_len;
4042 } else 0;
4043 extra_index += @intFromBool(small.has_fields_len);
4044 const decls_len = if (small.has_decls_len) decls_len: {
4045 const decls_len = zir.extra[extra_index];
4046 extra_index += 1;
4047 break :decls_len decls_len;
4048 } else 0;
4049
4050 extra_index += captures_len * 2;
4051
4052 if (small.has_backing_int) {
4053 const backing_int_body_len = zir.extra[extra_index];
4054 extra_index += 1; // backing_int_body_len
4055 if (backing_int_body_len == 0) {
4056 extra_index += 1; // backing_int_ref
4057 } else {
4058 extra_index += backing_int_body_len; // backing_int_body_inst
4059 }
4060 }
4061
4062 return .{
4063 .extra_index = extra_index,
4064 .decls_remaining = decls_len,
4065 .zir = zir,
4066 };
4067 },
4068 .enum_decl => {
4069 const small: Inst.EnumDecl.Small = @bitCast(extended.small);
4070 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len);
4071 extra_index += @intFromBool(small.has_tag_type);
4072 const captures_len = if (small.has_captures_len) captures_len: {
4073 const captures_len = zir.extra[extra_index];
4074 extra_index += 1;
4075 break :captures_len captures_len;
4076 } else 0;
4077 extra_index += @intFromBool(small.has_body_len);
4078 extra_index += @intFromBool(small.has_fields_len);
4079 const decls_len = if (small.has_decls_len) decls_len: {
4080 const decls_len = zir.extra[extra_index];
4081 extra_index += 1;
4082 break :decls_len decls_len;
4083 } else 0;
4084
4085 extra_index += captures_len * 2;
4086
4087 return .{
4088 .extra_index = extra_index,
4089 .decls_remaining = decls_len,
4090 .zir = zir,
4091 };
4092 },
4093 .union_decl => {
4094 const small: Inst.UnionDecl.Small = @bitCast(extended.small);
4095 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len);
4096 extra_index += @intFromBool(small.has_tag_type);
4097 const captures_len = if (small.has_captures_len) captures_len: {
4098 const captures_len = zir.extra[extra_index];
4099 extra_index += 1;
4100 break :captures_len captures_len;
4101 } else 0;
4102 extra_index += @intFromBool(small.has_body_len);
4103 extra_index += @intFromBool(small.has_fields_len);
4104 const decls_len = if (small.has_decls_len) decls_len: {
4105 const decls_len = zir.extra[extra_index];
4106 extra_index += 1;
4107 break :decls_len decls_len;
4108 } else 0;
4109
4110 extra_index += captures_len * 2;
4111
4112 return .{
4113 .extra_index = extra_index,
4114 .decls_remaining = decls_len,
4115 .zir = zir,
4116 };
4117 },
4118 .opaque_decl => {
4119 const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
4120 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len);
4121 const decls_len = if (small.has_decls_len) decls_len: {
4122 const decls_len = zir.extra[extra_index];
4123 extra_index += 1;
4124 break :decls_len decls_len;
4125 } else 0;
4126 const captures_len = if (small.has_captures_len) captures_len: {
4127 const captures_len = zir.extra[extra_index];
4128 extra_index += 1;
4129 break :captures_len captures_len;
4130 } else 0;
4131
4132 extra_index += captures_len * 2;
4133
4134 return .{
4135 .extra_index = extra_index,
4136 .decls_remaining = decls_len,
4137 .zir = zir,
4138 };
4139 },
4140 else => unreachable,
4141 }
4142}4023}
41434024
4144/// `DeclContents` contains all "interesting" instructions found within a declaration by `findTrackable`.4025/// `DeclContents` contains all "interesting" instructions found within a declaration by `findTrackable`.
...@@ -4524,7 +4405,7 @@ fn findTrackableInner(...@@ -4524,7 +4405,7 @@ fn findTrackableInner(
4524 try zir.findTrackableBody(gpa, contents, defers, body);4405 try zir.findTrackableBody(gpa, contents, defers, body);
4525 },4406 },
45264407
4527 // Reifications and opaque declarations need tracking, but have no body.4408 // Reifications and opaque declarations need tracking, but have no bodies.
4528 .reify_enum,4409 .reify_enum,
4529 .reify_struct,4410 .reify_struct,
4530 .reify_union,4411 .reify_union,
...@@ -4535,150 +4416,37 @@ fn findTrackableInner(...@@ -4535,150 +4416,37 @@ fn findTrackableInner(
4535 .struct_decl => {4416 .struct_decl => {
4536 try contents.explicit_types.append(gpa, inst);4417 try contents.explicit_types.append(gpa, inst);
45374418
4538 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);4419 const struct_decl = zir.getStructDecl(inst);
4539 const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);4420 var it = struct_decl.iterateFields();
4540 var extra_index = extra.end;4421 while (it.next()) |field| {
4541 const captures_len = if (small.has_captures_len) blk: {4422 try zir.findTrackableBody(gpa, contents, defers, field.type_body);
4542 const captures_len = zir.extra[extra_index];4423 if (field.align_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
4543 extra_index += 1;4424 if (field.default_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
4544 break :blk captures_len;
4545 } else 0;
4546 const fields_len = if (small.has_fields_len) blk: {
4547 const fields_len = zir.extra[extra_index];
4548 extra_index += 1;
4549 break :blk fields_len;
4550 } else 0;
4551 const decls_len = if (small.has_decls_len) blk: {
4552 const decls_len = zir.extra[extra_index];
4553 extra_index += 1;
4554 break :blk decls_len;
4555 } else 0;
4556 extra_index += captures_len * 2;
4557 if (small.has_backing_int) {
4558 const backing_int_body_len = zir.extra[extra_index];
4559 extra_index += 1;
4560 if (backing_int_body_len == 0) {
4561 extra_index += 1; // backing_int_ref
4562 } else {
4563 const body = zir.bodySlice(extra_index, backing_int_body_len);
4564 extra_index += backing_int_body_len;
4565 try zir.findTrackableBody(gpa, contents, defers, body);
4566 }
4567 }
4568 extra_index += decls_len;
4569
4570 // This ZIR is structured in a slightly awkward way, so we have to split up the iteration.
4571 // `extra_index` iterates `flags` (bags of bits).
4572 // `fields_extra_index` iterates `fields`.
4573 // We accumulate the total length of bodies into `total_bodies_len`. This is sufficient because
4574 // the bodies are packed together in `extra` and we only need to traverse their instructions (we
4575 // don't really care about the structure).
4576
4577 const bits_per_field = 4;
4578 const fields_per_u32 = 32 / bits_per_field;
4579 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
4580 var cur_bit_bag: u32 = undefined;
4581
4582 var fields_extra_index = extra_index + bit_bags_count;
4583 var total_bodies_len: u32 = 0;
4584
4585 for (0..fields_len) |field_i| {
4586 if (field_i % fields_per_u32 == 0) {
4587 cur_bit_bag = zir.extra[extra_index];
4588 extra_index += 1;
4589 }
4590
4591 const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
4592 cur_bit_bag >>= 1;
4593 const has_init = @as(u1, @truncate(cur_bit_bag)) != 0;
4594 cur_bit_bag >>= 2; // also skip `is_comptime`; we don't care
4595 const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
4596 cur_bit_bag >>= 1;
4597
4598 fields_extra_index += 1; // field_name
4599
4600 if (has_type_body) {
4601 const field_type_body_len = zir.extra[fields_extra_index];
4602 total_bodies_len += field_type_body_len;
4603 }
4604 fields_extra_index += 1; // field_type or field_type_body_len
4605
4606 if (has_align) {
4607 const align_body_len = zir.extra[fields_extra_index];
4608 fields_extra_index += 1;
4609 total_bodies_len += align_body_len;
4610 }
4611
4612 if (has_init) {
4613 const init_body_len = zir.extra[fields_extra_index];
4614 fields_extra_index += 1;
4615 total_bodies_len += init_body_len;
4616 }
4617 }4425 }
4618
4619 // Now, `fields_extra_index` points to `bodies`. Let's treat this as one big body.
4620 const merged_bodies = zir.bodySlice(fields_extra_index, total_bodies_len);
4621 try zir.findTrackableBody(gpa, contents, defers, merged_bodies);
4622 },4426 },
46234427
4624 // Union declarations need tracking and have a body.4428 // Union declarations need tracking and have bodies.
4625 .union_decl => {4429 .union_decl => {
4626 try contents.explicit_types.append(gpa, inst);4430 try contents.explicit_types.append(gpa, inst);
46274431
4628 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);4432 const union_decl = zir.getUnionDecl(inst);
4629 const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);4433 var it = union_decl.iterateFields();
4630 var extra_index = extra.end;4434 while (it.next()) |field| {
4631 extra_index += @intFromBool(small.has_tag_type);4435 if (field.type_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
4632 const captures_len = if (small.has_captures_len) blk: {4436 if (field.align_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
4633 const captures_len = zir.extra[extra_index];4437 if (field.value_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
4634 extra_index += 1;4438 }
4635 break :blk captures_len;
4636 } else 0;
4637 const body_len = if (small.has_body_len) blk: {
4638 const body_len = zir.extra[extra_index];
4639 extra_index += 1;
4640 break :blk body_len;
4641 } else 0;
4642 extra_index += @intFromBool(small.has_fields_len);
4643 const decls_len = if (small.has_decls_len) blk: {
4644 const decls_len = zir.extra[extra_index];
4645 extra_index += 1;
4646 break :blk decls_len;
4647 } else 0;
4648 extra_index += captures_len * 2;
4649 extra_index += decls_len;
4650 const body = zir.bodySlice(extra_index, body_len);
4651 try zir.findTrackableBody(gpa, contents, defers, body);
4652 },4439 },
46534440
4654 // Enum declarations need tracking and have a body.4441 // Enum declarations need tracking and have bodies.
4655 .enum_decl => {4442 .enum_decl => {
4656 try contents.explicit_types.append(gpa, inst);4443 try contents.explicit_types.append(gpa, inst);
46574444
4658 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);4445 const enum_decl = zir.getEnumDecl(inst);
4659 const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);4446 var it = enum_decl.iterateFields();
4660 var extra_index = extra.end;4447 while (it.next()) |field| {
4661 extra_index += @intFromBool(small.has_tag_type);4448 if (field.value_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
4662 const captures_len = if (small.has_captures_len) blk: {4449 }
4663 const captures_len = zir.extra[extra_index];
4664 extra_index += 1;
4665 break :blk captures_len;
4666 } else 0;
4667 const body_len = if (small.has_body_len) blk: {
4668 const body_len = zir.extra[extra_index];
4669 extra_index += 1;
4670 break :blk body_len;
4671 } else 0;
4672 extra_index += @intFromBool(small.has_fields_len);
4673 const decls_len = if (small.has_decls_len) blk: {
4674 const decls_len = zir.extra[extra_index];
4675 extra_index += 1;
4676 break :blk decls_len;
4677 } else 0;
4678 extra_index += captures_len * 2;
4679 extra_index += decls_len;
4680 const body = zir.bodySlice(extra_index, body_len);
4681 try zir.findTrackableBody(gpa, contents, defers, body);
4682 },4450 },
4683 }4451 }
4684 },4452 },
...@@ -5481,34 +5249,452 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void {...@@ -5481,34 +5249,452 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void {
5481 }5249 }
5482}5250}
54835251
5252/// MLUGG TODO: maybe delete these two?
5484pub fn typeCapturesLen(zir: Zir, type_decl: Inst.Index) u32 {5253pub fn typeCapturesLen(zir: Zir, type_decl: Inst.Index) u32 {
5485 const inst = zir.instructions.get(@intFromEnum(type_decl));5254 const inst = zir.instructions.get(@intFromEnum(type_decl));
5486 assert(inst.tag == .extended);5255 assert(inst.tag == .extended);
5487 switch (inst.data.extended.opcode) {5256 return switch (inst.data.extended.opcode) {
5488 .struct_decl => {5257 .struct_decl => @intCast(zir.getStructDecl(type_decl).captures.len),
5489 const small: Inst.StructDecl.Small = @bitCast(inst.data.extended.small);5258 .union_decl => @intCast(zir.getUnionDecl(type_decl).captures.len),
5490 if (!small.has_captures_len) return 0;5259 .enum_decl => @intCast(zir.getEnumDecl(type_decl).captures.len),
5491 const extra = zir.extraData(Inst.StructDecl, inst.data.extended.operand);5260 .opaque_decl => @intCast(zir.getOpaqueDecl(type_decl).captures.len),
5492 return zir.extra[extra.end];
5493 },
5494 .union_decl => {
5495 const small: Inst.UnionDecl.Small = @bitCast(inst.data.extended.small);
5496 if (!small.has_captures_len) return 0;
5497 const extra = zir.extraData(Inst.UnionDecl, inst.data.extended.operand);
5498 return zir.extra[extra.end + @intFromBool(small.has_tag_type)];
5499 },
5500 .enum_decl => {
5501 const small: Inst.EnumDecl.Small = @bitCast(inst.data.extended.small);
5502 if (!small.has_captures_len) return 0;
5503 const extra = zir.extraData(Inst.EnumDecl, inst.data.extended.operand);
5504 return zir.extra[extra.end + @intFromBool(small.has_tag_type)];
5505 },
5506 .opaque_decl => {
5507 const small: Inst.OpaqueDecl.Small = @bitCast(inst.data.extended.small);
5508 if (!small.has_captures_len) return 0;
5509 const extra = zir.extraData(Inst.OpaqueDecl, inst.data.extended.operand);
5510 return zir.extra[extra.end];
5511 },
5512 else => unreachable,5261 else => unreachable,
5262 };
5263}
5264pub fn typeDecls(zir: Zir, type_decl: Inst.Index) []const Zir.Inst.Index {
5265 const inst = zir.instructions.get(@intFromEnum(type_decl));
5266 assert(inst.tag == .extended);
5267 return switch (inst.data.extended.opcode) {
5268 .struct_decl => zir.getStructDecl(type_decl).decls,
5269 .union_decl => zir.getUnionDecl(type_decl).decls,
5270 .enum_decl => zir.getEnumDecl(type_decl).decls,
5271 .opaque_decl => zir.getOpaqueDecl(type_decl).decls,
5272 else => unreachable,
5273 };
5274}
5275
5276pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDecl {
5277 const inst_data = zir.instructions.get(@intFromEnum(struct_decl));
5278 assert(inst_data.tag == .extended);
5279 assert(inst_data.data.extended.opcode == .struct_decl);
5280 const small: Inst.StructDecl.Small = @bitCast(inst_data.data.extended.small);
5281 const extra = zir.extraData(Inst.StructDecl, inst_data.data.extended.operand);
5282 var extra_index = extra.end;
5283 const captures_len: u32 = if (small.has_captures_len) blk: {
5284 const captures_len = zir.extra[extra_index];
5285 extra_index += 1;
5286 break :blk captures_len;
5287 } else 0;
5288 const decls_len: u32 = if (small.has_decls_len) blk: {
5289 const decls_len = zir.extra[extra_index];
5290 extra_index += 1;
5291 break :blk decls_len;
5292 } else 0;
5293 const fields_len: u32 = if (small.has_fields_len) blk: {
5294 const fields_len = zir.extra[extra_index];
5295 extra_index += 1;
5296 break :blk fields_len;
5297 } else 0;
5298 const backing_int_type: Inst.Ref = if (small.has_backing_int_type) ty: {
5299 const ty = zir.extra[extra_index];
5300 extra_index += 1;
5301 break :ty @enumFromInt(ty);
5302 } else .none;
5303 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
5304 extra_index += captures_len;
5305 const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);
5306 extra_index += captures_len;
5307 const decls: []const Inst.Index = @ptrCast(zir.extra[extra_index..][0..decls_len]);
5308 extra_index += decls_len;
5309 const field_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..fields_len]);
5310 extra_index += fields_len;
5311 const field_type_body_lens: []const u32 = @ptrCast(zir.extra[extra_index..][0..fields_len]);
5312 extra_index += fields_len;
5313 const field_align_body_lens: ?[]const u32 = if (small.any_field_aligns) lens: {
5314 const lens = zir.extra[extra_index..][0..fields_len];
5315 extra_index += fields_len;
5316 break :lens @ptrCast(lens);
5317 } else null;
5318 const field_default_body_lens: ?[]const u32 = if (small.any_field_defaults) lens: {
5319 const lens = zir.extra[extra_index..][0..fields_len];
5320 extra_index += fields_len;
5321 break :lens @ptrCast(lens);
5322 } else null;
5323 const field_comptime_bits: ?[]const u32 = if (small.any_comptime_fields) bits: {
5324 const bits_len = std.math.divCeil(u32, fields_len, 32) catch unreachable;
5325 const bits = zir.extra[extra_index..][0..bits_len];
5326 extra_index += bits_len;
5327 break :bits bits;
5328 } else null;
5329 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
5330 return .{
5331 .src_line = extra.data.src_line,
5332 .src_node = extra.data.src_node,
5333 .name_strategy = small.name_strategy,
5334 .captures = captures,
5335 .capture_names = capture_names,
5336 .decls = decls,
5337 .layout = small.layout,
5338 .backing_int_type = backing_int_type,
5339 .field_names = field_names,
5340 .field_type_body_lens = field_type_body_lens,
5341 .field_align_body_lens = field_align_body_lens,
5342 .field_default_body_lens = field_default_body_lens,
5343 .field_comptime_bits = field_comptime_bits,
5344 .field_bodies_overlong = field_bodies_overlong,
5345 };
5346}
5347pub const UnwrappedStructDecl = struct {
5348 src_line: u32,
5349 src_node: Ast.Node.Index,
5350 name_strategy: Inst.NameStrategy,
5351
5352 captures: []const Inst.Capture,
5353 capture_names: []const NullTerminatedString,
5354
5355 decls: []const Inst.Index,
5356
5357 layout: std.builtin.Type.ContainerLayout,
5358 backing_int_type: Inst.Ref,
5359
5360 field_names: []const NullTerminatedString,
5361 field_type_body_lens: []const u32,
5362 field_align_body_lens: ?[]const u32,
5363 field_default_body_lens: ?[]const u32,
5364 field_comptime_bits: ?[]const u32,
5365 field_bodies_overlong: []const Inst.Index,
5366
5367 pub fn iterateFields(struct_decl: UnwrappedStructDecl) FieldIterator {
5368 return .{
5369 .next_idx = 0,
5370 .names = struct_decl.field_names,
5371 .type_body_lens = struct_decl.field_type_body_lens,
5372 .align_body_lens = struct_decl.field_align_body_lens,
5373 .default_body_lens = struct_decl.field_default_body_lens,
5374 .comptime_bits = struct_decl.field_comptime_bits,
5375 .bodies_overlong = struct_decl.field_bodies_overlong,
5376 };
5377 }
5378
5379 pub const FieldIterator = struct {
5380 next_idx: u32,
5381 names: []const NullTerminatedString,
5382 type_body_lens: []const u32,
5383 align_body_lens: ?[]const u32,
5384 default_body_lens: ?[]const u32,
5385 comptime_bits: ?[]const u32,
5386 bodies_overlong: []const Inst.Index,
5387 pub const Field = struct {
5388 idx: u32,
5389 name: NullTerminatedString,
5390 type_body: []const Inst.Index,
5391 align_body: ?[]const Inst.Index,
5392 default_body: ?[]const Inst.Index,
5393 is_comptime: bool,
5394 };
5395 pub fn next(it: *FieldIterator) ?Field {
5396 const idx = it.next_idx;
5397 if (idx == it.names.len) return null;
5398 it.next_idx += 1;
5399 return .{
5400 .idx = idx,
5401 .name = it.names[idx],
5402 .type_body = it.body(it.type_body_lens[idx]).?,
5403 .align_body = it.body(if (it.align_body_lens) |l| l[idx] else 0),
5404 .default_body = it.body(if (it.default_body_lens) |l| l[idx] else 0),
5405 .is_comptime = ct: {
5406 const bits = it.comptime_bits orelse break :ct false;
5407 const big = bits[idx / 32];
5408 const shifted = big >> @intCast(idx % 32);
5409 break :ct @as(u1, @truncate(shifted)) == 1;
5410 },
5411 };
5412 }
5413 fn body(it: *FieldIterator, len: u32) ?[]const Inst.Index {
5414 if (len == 0) return null;
5415 const b = it.bodies_overlong[0..len];
5416 it.bodies_overlong = it.bodies_overlong[len..];
5417 return b;
5418 }
5419 };
5420};
5421
5422pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl {
5423 const inst_data = zir.instructions.get(@intFromEnum(union_decl));
5424 assert(inst_data.tag == .extended);
5425 assert(inst_data.data.extended.opcode == .union_decl);
5426 const small: Inst.UnionDecl.Small = @bitCast(inst_data.data.extended.small);
5427 const extra = zir.extraData(Inst.UnionDecl, inst_data.data.extended.operand);
5428 var extra_index = extra.end;
5429 const captures_len: u32 = if (small.has_captures_len) blk: {
5430 const captures_len = zir.extra[extra_index];
5431 extra_index += 1;
5432 break :blk captures_len;
5433 } else 0;
5434 const decls_len: u32 = if (small.has_decls_len) blk: {
5435 const decls_len = zir.extra[extra_index];
5436 extra_index += 1;
5437 break :blk decls_len;
5438 } else 0;
5439 const fields_len: u32 = if (small.has_fields_len) blk: {
5440 const fields_len = zir.extra[extra_index];
5441 extra_index += 1;
5442 break :blk fields_len;
5443 } else 0;
5444 const arg_type: Inst.Ref = if (small.kind.hasArgType()) ty: {
5445 const ty = zir.extra[extra_index];
5446 extra_index += 1;
5447 break :ty @enumFromInt(ty);
5448 } else .none;
5449 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
5450 extra_index += captures_len;
5451 const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);
5452 extra_index += captures_len;
5453 const decls: []const Inst.Index = @ptrCast(zir.extra[extra_index..][0..decls_len]);
5454 extra_index += decls_len;
5455 const field_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..fields_len]);
5456 extra_index += fields_len;
5457 const field_type_body_lens: []const u32 = @ptrCast(zir.extra[extra_index..][0..fields_len]);
5458 extra_index += fields_len;
5459 const field_align_body_lens: ?[]const u32 = if (small.any_field_aligns) lens: {
5460 const lens = zir.extra[extra_index..][0..fields_len];
5461 extra_index += fields_len;
5462 break :lens @ptrCast(lens);
5463 } else null;
5464 const field_value_body_lens: ?[]const u32 = if (small.any_field_values) lens: {
5465 const lens = zir.extra[extra_index..][0..fields_len];
5466 extra_index += fields_len;
5467 break :lens @ptrCast(lens);
5468 } else null;
5469 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
5470 return .{
5471 .src_line = extra.data.src_line,
5472 .src_node = extra.data.src_node,
5473 .name_strategy = small.name_strategy,
5474 .captures = captures,
5475 .capture_names = capture_names,
5476 .decls = decls,
5477 .kind = small.kind,
5478 .arg_type = arg_type,
5479 .field_names = field_names,
5480 .field_type_body_lens = field_type_body_lens,
5481 .field_align_body_lens = field_align_body_lens,
5482 .field_value_body_lens = field_value_body_lens,
5483 .field_bodies_overlong = field_bodies_overlong,
5484 };
5485}
5486pub const UnwrappedUnionDecl = struct {
5487 src_line: u32,
5488 src_node: Ast.Node.Index,
5489 name_strategy: Inst.NameStrategy,
5490
5491 captures: []const Inst.Capture,
5492 capture_names: []const NullTerminatedString,
5493
5494 decls: []const Inst.Index,
5495
5496 kind: Inst.UnionDecl.Kind,
5497 arg_type: Inst.Ref,
5498
5499 field_names: []const NullTerminatedString,
5500 field_type_body_lens: []const u32,
5501 field_align_body_lens: ?[]const u32,
5502 field_value_body_lens: ?[]const u32,
5503 field_bodies_overlong: []const Inst.Index,
5504
5505 pub fn iterateFields(union_decl: UnwrappedUnionDecl) FieldIterator {
5506 return .{
5507 .next_idx = 0,
5508 .names = union_decl.field_names,
5509 .type_body_lens = union_decl.field_type_body_lens,
5510 .align_body_lens = union_decl.field_align_body_lens,
5511 .value_body_lens = union_decl.field_value_body_lens,
5512 .bodies_overlong = union_decl.field_bodies_overlong,
5513 };
5514 }
5515
5516 pub const FieldIterator = struct {
5517 next_idx: u32,
5518 names: []const NullTerminatedString,
5519 type_body_lens: []const u32,
5520 align_body_lens: ?[]const u32,
5521 value_body_lens: ?[]const u32,
5522 bodies_overlong: []const Inst.Index,
5523 pub const Field = struct {
5524 idx: u32,
5525 name: NullTerminatedString,
5526 type_body: ?[]const Inst.Index,
5527 align_body: ?[]const Inst.Index,
5528 value_body: ?[]const Inst.Index,
5529 };
5530 pub fn next(it: *FieldIterator) ?Field {
5531 const idx = it.next_idx;
5532 if (idx == it.names.len) return null;
5533 it.next_idx += 1;
5534 return .{
5535 .idx = idx,
5536 .name = it.names[idx],
5537 .type_body = it.body(it.type_body_lens[idx]),
5538 .align_body = it.body(if (it.align_body_lens) |l| l[idx] else 0),
5539 .value_body = it.body(if (it.value_body_lens) |l| l[idx] else 0),
5540 };
5541 }
5542 fn body(it: *FieldIterator, len: u32) ?[]const Inst.Index {
5543 if (len == 0) return null;
5544 const b = it.bodies_overlong[0..len];
5545 it.bodies_overlong = it.bodies_overlong[len..];
5546 return b;
5547 }
5548 };
5549};
5550
5551pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
5552 const inst_data = zir.instructions.get(@intFromEnum(enum_decl));
5553 assert(inst_data.tag == .extended);
5554 assert(inst_data.data.extended.opcode == .enum_decl);
5555 const small: Inst.EnumDecl.Small = @bitCast(inst_data.data.extended.small);
5556 const extra = zir.extraData(Inst.EnumDecl, inst_data.data.extended.operand);
5557 var extra_index = extra.end;
5558 const captures_len: u32 = if (small.has_captures_len) blk: {
5559 const captures_len = zir.extra[extra_index];
5560 extra_index += 1;
5561 break :blk captures_len;
5562 } else 0;
5563 const decls_len: u32 = if (small.has_decls_len) blk: {
5564 const decls_len = zir.extra[extra_index];
5565 extra_index += 1;
5566 break :blk decls_len;
5567 } else 0;
5568 const fields_len: u32 = if (small.has_fields_len) blk: {
5569 const fields_len = zir.extra[extra_index];
5570 extra_index += 1;
5571 break :blk fields_len;
5572 } else 0;
5573 const tag_type: Inst.Ref = if (small.has_tag_type) ty: {
5574 const ty = zir.extra[extra_index];
5575 extra_index += 1;
5576 break :ty @enumFromInt(ty);
5577 } else .none;
5578 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
5579 extra_index += captures_len;
5580 const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);
5581 extra_index += captures_len;
5582 const decls: []const Inst.Index = @ptrCast(zir.extra[extra_index..][0..decls_len]);
5583 extra_index += decls_len;
5584 const field_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..fields_len]);
5585 extra_index += fields_len;
5586 const field_value_body_lens: ?[]const u32 = if (small.any_field_values) lens: {
5587 const lens = zir.extra[extra_index..][0..fields_len];
5588 extra_index += fields_len;
5589 break :lens @ptrCast(lens);
5590 } else null;
5591 const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
5592 return .{
5593 .src_line = extra.data.src_line,
5594 .src_node = extra.data.src_node,
5595 .name_strategy = small.name_strategy,
5596 .captures = captures,
5597 .capture_names = capture_names,
5598 .decls = decls,
5599 .tag_type = tag_type,
5600 .nonexhaustive = small.nonexhaustive,
5601 .field_names = field_names,
5602 .field_value_body_lens = field_value_body_lens,
5603 .field_bodies_overlong = field_bodies_overlong,
5604 };
5605}
5606pub const UnwrappedEnumDecl = struct {
5607 src_line: u32,
5608 src_node: Ast.Node.Index,
5609 name_strategy: Inst.NameStrategy,
5610
5611 captures: []const Inst.Capture,
5612 capture_names: []const NullTerminatedString,
5613
5614 decls: []const Inst.Index,
5615
5616 tag_type: Inst.Ref,
5617 nonexhaustive: bool,
5618
5619 field_names: []const NullTerminatedString,
5620 field_value_body_lens: ?[]const u32,
5621 field_bodies_overlong: []const Inst.Index,
5622
5623 pub fn iterateFields(enum_decl: UnwrappedEnumDecl) FieldIterator {
5624 return .{
5625 .next_idx = 0,
5626 .names = enum_decl.field_names,
5627 .value_body_lens = enum_decl.field_value_body_lens,
5628 .bodies_overlong = enum_decl.field_bodies_overlong,
5629 };
5513 }5630 }
5631
5632 pub const FieldIterator = struct {
5633 next_idx: u32,
5634 names: []const NullTerminatedString,
5635 value_body_lens: ?[]const u32,
5636 bodies_overlong: []const Inst.Index,
5637 pub const Field = struct {
5638 idx: u32,
5639 name: NullTerminatedString,
5640 value_body: ?[]const Inst.Index,
5641 };
5642 pub fn next(it: *FieldIterator) ?Field {
5643 const idx = it.next_idx;
5644 if (idx == it.names.len) return null;
5645 it.next_idx += 1;
5646 return .{
5647 .idx = idx,
5648 .name = it.names[idx],
5649 .value_body = it.body(if (it.value_body_lens) |l| l[idx] else 0),
5650 };
5651 }
5652 fn body(it: *FieldIterator, len: u32) ?[]const Inst.Index {
5653 if (len == 0) return null;
5654 const b = it.bodies_overlong[0..len];
5655 it.bodies_overlong = it.bodies_overlong[len..];
5656 return b;
5657 }
5658 };
5659};
5660
5661pub fn getOpaqueDecl(zir: *const Zir, opaque_decl: Inst.Index) UnwrappedOpaqueDecl {
5662 const inst_data = zir.instructions.get(@intFromEnum(opaque_decl));
5663 assert(inst_data.tag == .extended);
5664 assert(inst_data.data.extended.opcode == .opaque_decl);
5665 const small: Inst.OpaqueDecl.Small = @bitCast(inst_data.data.extended.small);
5666 const extra = zir.extraData(Inst.OpaqueDecl, inst_data.data.extended.operand);
5667 var extra_index = extra.end;
5668 const captures_len: u32 = if (small.has_captures_len) blk: {
5669 const captures_len = zir.extra[extra_index];
5670 extra_index += 1;
5671 break :blk captures_len;
5672 } else 0;
5673 const decls_len: u32 = if (small.has_decls_len) blk: {
5674 const decls_len = zir.extra[extra_index];
5675 extra_index += 1;
5676 break :blk decls_len;
5677 } else 0;
5678 const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
5679 extra_index += captures_len;
5680 const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);
5681 extra_index += captures_len;
5682 const decls: []const Inst.Index = @ptrCast(zir.extra[extra_index..][0..decls_len]);
5683 extra_index += decls_len;
5684 return .{
5685 .src_line = extra.data.src_line,
5686 .src_node = extra.data.src_node,
5687 .name_strategy = small.name_strategy,
5688 .captures = captures,
5689 .capture_names = capture_names,
5690 .decls = decls,
5691 };
5514}5692}
5693pub const UnwrappedOpaqueDecl = struct {
5694 src_line: u32,
5695 src_node: Ast.Node.Index,
5696 name_strategy: Inst.NameStrategy,
5697 captures: []const Inst.Capture,
5698 capture_names: []const NullTerminatedString,
5699 decls: []const Inst.Index,
5700};
src/print_zir.zig+110-425
...@@ -548,10 +548,10 @@ const Writer = struct {...@@ -548,10 +548,10 @@ const Writer = struct {
548 .shl_with_overflow,548 .shl_with_overflow,
549 => try self.writeOverflowArithmetic(stream, extended),549 => try self.writeOverflowArithmetic(stream, extended),
550550
551 .struct_decl => try self.writeStructDecl(stream, extended),551 .struct_decl => try self.writeStructDecl(stream, inst),
552 .union_decl => try self.writeUnionDecl(stream, extended),552 .union_decl => try self.writeUnionDecl(stream, inst),
553 .enum_decl => try self.writeEnumDecl(stream, extended),553 .enum_decl => try self.writeEnumDecl(stream, inst),
554 .opaque_decl => try self.writeOpaqueDecl(stream, extended),554 .opaque_decl => try self.writeOpaqueDecl(stream, inst),
555555
556 .tuple_decl => try self.writeTupleDecl(stream, extended),556 .tuple_decl => try self.writeTupleDecl(stream, extended),
557557
...@@ -1427,187 +1427,57 @@ const Writer = struct {...@@ -1427,187 +1427,57 @@ const Writer = struct {
1427 try self.writeSrcNode(stream, inst_data.src_node);1427 try self.writeSrcNode(stream, inst_data.src_node);
1428 }1428 }
14291429
1430 fn writeStructDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {1430 fn writeStructDecl(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
1431 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);1431 const struct_decl = self.code.getStructDecl(inst);
1432
1433 const extra = self.code.extraData(Zir.Inst.StructDecl, extended.operand);
14341432
1435 const prev_parent_decl_node = self.parent_decl_node;1433 const prev_parent_decl_node = self.parent_decl_node;
1436 self.parent_decl_node = extra.data.src_node;1434 self.parent_decl_node = struct_decl.src_node;
1437 defer self.parent_decl_node = prev_parent_decl_node;1435 defer self.parent_decl_node = prev_parent_decl_node;
14381436
1439 const fields_hash: std.zig.SrcHash = @bitCast([4]u32{1437 const fields_hash = self.code.getAssociatedSrcHash(inst).?;
1440 extra.data.fields_hash_0,
1441 extra.data.fields_hash_1,
1442 extra.data.fields_hash_2,
1443 extra.data.fields_hash_3,
1444 });
1445
1446 try stream.print("hash({x}) ", .{&fields_hash});1438 try stream.print("hash({x}) ", .{&fields_hash});
14471439
1448 var extra_index: usize = extra.end;1440 try stream.print("{s}, ", .{@tagName(struct_decl.name_strategy)});
1449
1450 const captures_len = if (small.has_captures_len) blk: {
1451 const captures_len = self.code.extra[extra_index];
1452 extra_index += 1;
1453 break :blk captures_len;
1454 } else 0;
1455
1456 const fields_len = if (small.has_fields_len) blk: {
1457 const fields_len = self.code.extra[extra_index];
1458 extra_index += 1;
1459 break :blk fields_len;
1460 } else 0;
1461
1462 const decls_len = if (small.has_decls_len) blk: {
1463 const decls_len = self.code.extra[extra_index];
1464 extra_index += 1;
1465 break :blk decls_len;
1466 } else 0;
1467
1468 try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv);
1469 try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);
1470
1471 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
14721441
1473 extra_index = try self.writeCaptures(stream, extra_index, captures_len);1442 if (struct_decl.backing_int_type != .none) {
1474 try stream.writeAll(", ");1443 assert(struct_decl.layout == .@"packed");
1475
1476 if (small.has_backing_int) {
1477 const backing_int_body_len = self.code.extra[extra_index];
1478 extra_index += 1;
1479 try stream.writeAll("packed(");1444 try stream.writeAll("packed(");
1480 if (backing_int_body_len == 0) {1445 try self.writeInstRef(stream, struct_decl.backing_int_type);
1481 const backing_int_ref: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
1482 extra_index += 1;
1483 try self.writeInstRef(stream, backing_int_ref);
1484 } else {
1485 const body = self.code.bodySlice(extra_index, backing_int_body_len);
1486 extra_index += backing_int_body_len;
1487 self.indent += 2;
1488 try self.writeBracedDecl(stream, body);
1489 self.indent -= 2;
1490 }
1491 try stream.writeAll("), ");1446 try stream.writeAll("), ");
1492 } else {1447 } else {
1493 try stream.print("{s}, ", .{@tagName(small.layout)});1448 try stream.print("{s}, ", .{@tagName(struct_decl.layout)});
1494 }1449 }
14951450
1496 if (decls_len == 0) {1451 try self.writeCaptures(stream, struct_decl.captures, struct_decl.capture_names);
1497 try stream.writeAll("{}, ");1452 try stream.writeAll(", ");
1498 } else {1453 try self.writeBracedDecl(stream, struct_decl.decls);
1499 try stream.writeAll("{\n");1454 try stream.writeAll(", ");
1500 self.indent += 2;
1501 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
1502 self.indent -= 2;
1503 extra_index += decls_len;
1504 try stream.splatByteAll(' ', self.indent);
1505 try stream.writeAll("}, ");
1506 }
15071455
1508 if (fields_len == 0) {1456 if (struct_decl.field_names.len == 0) {
1509 try stream.writeAll("{}, {}) ");1457 try stream.writeAll("{}) ");
1510 } else {1458 } else {
1511 const bits_per_field = 4;
1512 const fields_per_u32 = 32 / bits_per_field;
1513 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
1514 const Field = struct {
1515 type_len: u32 = 0,
1516 align_len: u32 = 0,
1517 init_len: u32 = 0,
1518 type: Zir.Inst.Ref = .none,
1519 name: Zir.NullTerminatedString,
1520 is_comptime: bool,
1521 };
1522 const fields = try self.arena.alloc(Field, fields_len);
1523 {
1524 var bit_bag_index: usize = extra_index;
1525 extra_index += bit_bags_count;
1526 var cur_bit_bag: u32 = undefined;
1527 var field_i: u32 = 0;
1528 while (field_i < fields_len) : (field_i += 1) {
1529 if (field_i % fields_per_u32 == 0) {
1530 cur_bit_bag = self.code.extra[bit_bag_index];
1531 bit_bag_index += 1;
1532 }
1533 const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
1534 cur_bit_bag >>= 1;
1535 const has_default = @as(u1, @truncate(cur_bit_bag)) != 0;
1536 cur_bit_bag >>= 1;
1537 const is_comptime = @as(u1, @truncate(cur_bit_bag)) != 0;
1538 cur_bit_bag >>= 1;
1539 const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
1540 cur_bit_bag >>= 1;
1541
1542 const field_name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
1543 extra_index += 1;
1544
1545 fields[field_i] = .{
1546 .is_comptime = is_comptime,
1547 .name = field_name_index,
1548 };
1549
1550 if (has_type_body) {
1551 fields[field_i].type_len = self.code.extra[extra_index];
1552 } else {
1553 fields[field_i].type = @enumFromInt(self.code.extra[extra_index]);
1554 }
1555 extra_index += 1;
1556
1557 if (has_align) {
1558 fields[field_i].align_len = self.code.extra[extra_index];
1559 extra_index += 1;
1560 }
1561
1562 if (has_default) {
1563 fields[field_i].init_len = self.code.extra[extra_index];
1564 extra_index += 1;
1565 }
1566 }
1567 }
1568
1569 try stream.writeAll("{\n");1459 try stream.writeAll("{\n");
1570 self.indent += 2;1460 self.indent += 2;
15711461
1572 for (fields, 0..) |field, i| {1462 var it = struct_decl.iterateFields();
1463 while (it.next()) |field| {
1573 try stream.splatByteAll(' ', self.indent);1464 try stream.splatByteAll(' ', self.indent);
1574 try self.writeFlag(stream, "comptime ", field.is_comptime);1465 try self.writeFlag(stream, "comptime ", field.is_comptime);
1575 if (field.name != .empty) {1466 const field_name = self.code.nullTerminatedString(field.name);
1576 const field_name = self.code.nullTerminatedString(field.name);1467 try stream.print("{f}: ", .{std.zig.fmtIdP(field_name)});
1577 try stream.print("{f}: ", .{std.zig.fmtIdP(field_name)});
1578 } else {
1579 try stream.print("@\"{d}\": ", .{i});
1580 }
1581 if (field.type != .none) {
1582 try self.writeInstRef(stream, field.type);
1583 }
1584
1585 if (field.type_len > 0) {
1586 const body = self.code.bodySlice(extra_index, field.type_len);
1587 extra_index += body.len;
1588 self.indent += 2;
1589 try self.writeBracedDecl(stream, body);
1590 self.indent -= 2;
1591 }
15921468
1593 if (field.align_len > 0) {1469 self.indent += 2;
1594 const body = self.code.bodySlice(extra_index, field.align_len);1470 try self.writeBracedDecl(stream, field.type_body);
1595 extra_index += body.len;1471 if (field.align_body) |body| {
1596 self.indent += 2;
1597 try stream.writeAll(" align(");1472 try stream.writeAll(" align(");
1598 try self.writeBracedDecl(stream, body);1473 try self.writeBracedDecl(stream, body);
1599 try stream.writeAll(")");1474 try stream.writeByte(')');
1600 self.indent -= 2;
1601 }1475 }
16021476 if (field.default_body) |body| {
1603 if (field.init_len > 0) {
1604 const body = self.code.bodySlice(extra_index, field.init_len);
1605 extra_index += body.len;
1606 self.indent += 2;
1607 try stream.writeAll(" = ");1477 try stream.writeAll(" = ");
1608 try self.writeBracedDecl(stream, body);1478 try self.writeBracedDecl(stream, body);
1609 self.indent -= 2;
1610 }1479 }
1480 self.indent -= 2;
16111481
1612 try stream.writeAll(",\n");1482 try stream.writeAll(",\n");
1613 }1483 }
...@@ -1619,266 +1489,115 @@ const Writer = struct {...@@ -1619,266 +1489,115 @@ const Writer = struct {
1619 try self.writeSrcNode(stream, .zero);1489 try self.writeSrcNode(stream, .zero);
1620 }1490 }
16211491
1622 fn writeUnionDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {1492 fn writeUnionDecl(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
1623 const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));1493 const union_decl = self.code.getUnionDecl(inst);
1624
1625 const extra = self.code.extraData(Zir.Inst.UnionDecl, extended.operand);
16261494
1627 const prev_parent_decl_node = self.parent_decl_node;1495 const prev_parent_decl_node = self.parent_decl_node;
1628 self.parent_decl_node = extra.data.src_node;1496 self.parent_decl_node = union_decl.src_node;
1629 defer self.parent_decl_node = prev_parent_decl_node;1497 defer self.parent_decl_node = prev_parent_decl_node;
16301498
1631 const fields_hash: std.zig.SrcHash = @bitCast([4]u32{1499 const fields_hash = self.code.getAssociatedSrcHash(inst).?;
1632 extra.data.fields_hash_0,
1633 extra.data.fields_hash_1,
1634 extra.data.fields_hash_2,
1635 extra.data.fields_hash_3,
1636 });
1637
1638 try stream.print("hash({x}) ", .{&fields_hash});1500 try stream.print("hash({x}) ", .{&fields_hash});
16391501
1640 var extra_index: usize = extra.end;1502 try stream.print("{s}, ", .{@tagName(union_decl.name_strategy)});
1641
1642 const tag_type_ref = if (small.has_tag_type) blk: {
1643 const tag_type_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1644 extra_index += 1;
1645 break :blk tag_type_ref;
1646 } else .none;
1647
1648 const captures_len = if (small.has_captures_len) blk: {
1649 const captures_len = self.code.extra[extra_index];
1650 extra_index += 1;
1651 break :blk captures_len;
1652 } else 0;
1653
1654 const body_len = if (small.has_body_len) blk: {
1655 const body_len = self.code.extra[extra_index];
1656 extra_index += 1;
1657 break :blk body_len;
1658 } else 0;
1659
1660 const fields_len = if (small.has_fields_len) blk: {
1661 const fields_len = self.code.extra[extra_index];
1662 extra_index += 1;
1663 break :blk fields_len;
1664 } else 0;
16651503
1666 const decls_len = if (small.has_decls_len) blk: {1504 switch (union_decl.kind) {
1667 const decls_len = self.code.extra[extra_index];1505 .auto => try stream.writeAll("auto, "),
1668 extra_index += 1;1506 .@"extern" => try stream.writeAll("extern, "),
1669 break :blk decls_len;1507 .@"packed" => try stream.writeAll("packed, "),
1670 } else 0;1508 .packed_explicit => {
16711509 try stream.writeAll("packed(");
1672 try stream.print("{s}, {s}, ", .{1510 try self.writeInstRef(stream, union_decl.arg_type);
1673 @tagName(small.name_strategy), @tagName(small.layout),1511 try stream.writeAll("), ");
1674 });1512 },
1675 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);1513 .tagged_explicit => {
1514 try stream.writeAll("auto(");
1515 try self.writeInstRef(stream, union_decl.arg_type);
1516 try stream.writeAll("), ");
1517 },
1518 .tagged_enum => try stream.writeAll("auto(enum)"),
1519 .tagged_enum_explicit => {
1520 try stream.writeAll("auto(enum(");
1521 try self.writeInstRef(stream, union_decl.arg_type);
1522 try stream.writeAll(")), ");
1523 },
1524 }
16761525
1677 extra_index = try self.writeCaptures(stream, extra_index, captures_len);1526 try self.writeCaptures(stream, union_decl.captures, union_decl.capture_names);
1527 try stream.writeAll(", ");
1528 try self.writeBracedDecl(stream, union_decl.decls);
1678 try stream.writeAll(", ");1529 try stream.writeAll(", ");
16791530
1680 if (decls_len == 0) {1531 if (union_decl.field_names.len == 0) {
1681 try stream.writeAll("{}");1532 try stream.writeAll("}) ");
1682 } else {1533 } else {
1683 try stream.writeAll("{\n");1534 try stream.writeAll("{\n");
1684 self.indent += 2;1535 self.indent += 2;
1685 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
1686 self.indent -= 2;
1687 extra_index += decls_len;
1688 try stream.splatByteAll(' ', self.indent);
1689 try stream.writeAll("}");
1690 }
1691
1692 if (tag_type_ref != .none) {
1693 try stream.writeAll(", ");
1694 try self.writeInstRef(stream, tag_type_ref);
1695 }
1696
1697 if (fields_len == 0) {
1698 try stream.writeAll("}) ");
1699 try self.writeSrcNode(stream, .zero);
1700 return;
1701 }
1702 try stream.writeAll(", ");
17031536
1704 const body = self.code.bodySlice(extra_index, body_len);1537 var it = union_decl.iterateFields();
1705 extra_index += body.len;1538 while (it.next()) |field| {
1539 try stream.splatByteAll(' ', self.indent);
1540 const field_name = self.code.nullTerminatedString(field.name);
1541 try stream.print("{f}", .{std.zig.fmtIdP(field_name)});
17061542
1707 try self.writeBracedDecl(stream, body);1543 self.indent += 2;
1708 try stream.writeAll(", {\n");1544 if (field.type_body) |body| {
1545 try stream.writeAll(": ");
1546 try self.writeBracedDecl(stream, body);
1547 }
1548 if (field.align_body) |body| {
1549 try stream.writeAll(" align(");
1550 try self.writeBracedDecl(stream, body);
1551 try stream.writeByte(')');
1552 }
1553 if (field.value_body) |body| {
1554 try stream.writeAll(" = ");
1555 try self.writeBracedDecl(stream, body);
1556 }
1557 self.indent -= 2;
17091558
1710 self.indent += 2;1559 try stream.writeAll(",\n");
1711 const bits_per_field = 4;
1712 const fields_per_u32 = 32 / bits_per_field;
1713 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
1714 const body_end = extra_index;
1715 extra_index += bit_bags_count;
1716 var bit_bag_index: usize = body_end;
1717 var cur_bit_bag: u32 = undefined;
1718 var field_i: u32 = 0;
1719 while (field_i < fields_len) : (field_i += 1) {
1720 if (field_i % fields_per_u32 == 0) {
1721 cur_bit_bag = self.code.extra[bit_bag_index];
1722 bit_bag_index += 1;
1723 }1560 }
1724 const has_type = @as(u1, @truncate(cur_bit_bag)) != 0;1561 self.indent -= 2;
1725 cur_bit_bag >>= 1;
1726 const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
1727 cur_bit_bag >>= 1;
1728 const has_value = @as(u1, @truncate(cur_bit_bag)) != 0;
1729 cur_bit_bag >>= 1;
1730 const unused = @as(u1, @truncate(cur_bit_bag)) != 0;
1731 cur_bit_bag >>= 1;
1732
1733 _ = unused;
1734
1735 const field_name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
1736 const field_name = self.code.nullTerminatedString(field_name_index);
1737 extra_index += 1;
1738
1739 try stream.splatByteAll(' ', self.indent);1562 try stream.splatByteAll(' ', self.indent);
1740 try stream.print("{f}", .{std.zig.fmtIdP(field_name)});1563 try stream.writeAll("}) ");
1741
1742 if (has_type) {
1743 const field_type = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1744 extra_index += 1;
1745
1746 try stream.writeAll(": ");
1747 try self.writeInstRef(stream, field_type);
1748 }
1749 if (has_align) {
1750 const align_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1751 extra_index += 1;
1752
1753 try stream.writeAll(" align(");
1754 try self.writeInstRef(stream, align_ref);
1755 try stream.writeAll(")");
1756 }
1757 if (has_value) {
1758 const default_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1759 extra_index += 1;
1760
1761 try stream.writeAll(" = ");
1762 try self.writeInstRef(stream, default_ref);
1763 }
1764 try stream.writeAll(",\n");
1765 }1564 }
1766
1767 self.indent -= 2;
1768 try stream.splatByteAll(' ', self.indent);
1769 try stream.writeAll("}) ");
1770 try self.writeSrcNode(stream, .zero);1565 try self.writeSrcNode(stream, .zero);
1771 }1566 }
17721567
1773 fn writeEnumDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {1568 fn writeEnumDecl(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
1774 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));1569 const enum_decl = self.code.getEnumDecl(inst);
1775
1776 const extra = self.code.extraData(Zir.Inst.EnumDecl, extended.operand);
17771570
1778 const prev_parent_decl_node = self.parent_decl_node;1571 const prev_parent_decl_node = self.parent_decl_node;
1779 self.parent_decl_node = extra.data.src_node;1572 self.parent_decl_node = enum_decl.src_node;
1780 defer self.parent_decl_node = prev_parent_decl_node;1573 defer self.parent_decl_node = prev_parent_decl_node;
17811574
1782 const fields_hash: std.zig.SrcHash = @bitCast([4]u32{1575 const fields_hash = self.code.getAssociatedSrcHash(inst).?;
1783 extra.data.fields_hash_0,
1784 extra.data.fields_hash_1,
1785 extra.data.fields_hash_2,
1786 extra.data.fields_hash_3,
1787 });
1788
1789 try stream.print("hash({x}) ", .{&fields_hash});1576 try stream.print("hash({x}) ", .{&fields_hash});
17901577
1791 var extra_index: usize = extra.end;1578 try stream.print("{s}, ", .{@tagName(enum_decl.name_strategy)});
17921579 try self.writeFlag(stream, "nonexhaustive, ", enum_decl.nonexhaustive);
1793 const tag_type_ref = if (small.has_tag_type) blk: {1580 try self.writeInstRef(stream, enum_decl.tag_type);
1794 const tag_type_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1795 extra_index += 1;
1796 break :blk tag_type_ref;
1797 } else .none;
1798
1799 const captures_len = if (small.has_captures_len) blk: {
1800 const captures_len = self.code.extra[extra_index];
1801 extra_index += 1;
1802 break :blk captures_len;
1803 } else 0;
1804
1805 const body_len = if (small.has_body_len) blk: {
1806 const body_len = self.code.extra[extra_index];
1807 extra_index += 1;
1808 break :blk body_len;
1809 } else 0;
1810
1811 const fields_len = if (small.has_fields_len) blk: {
1812 const fields_len = self.code.extra[extra_index];
1813 extra_index += 1;
1814 break :blk fields_len;
1815 } else 0;
1816
1817 const decls_len = if (small.has_decls_len) blk: {
1818 const decls_len = self.code.extra[extra_index];
1819 extra_index += 1;
1820 break :blk decls_len;
1821 } else 0;
18221581
1823 try stream.print("{s}, ", .{@tagName(small.name_strategy)});1582 try self.writeCaptures(stream, enum_decl.captures, enum_decl.capture_names);
1824 try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive);1583 try stream.writeAll(", ");
18251584 try self.writeBracedDecl(stream, enum_decl.decls);
1826 extra_index = try self.writeCaptures(stream, extra_index, captures_len);
1827 try stream.writeAll(", ");1585 try stream.writeAll(", ");
18281586
1829 if (decls_len == 0) {1587 if (enum_decl.field_names.len == 0) {
1830 try stream.writeAll("{}, ");
1831 } else {
1832 try stream.writeAll("{\n");
1833 self.indent += 2;
1834 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
1835 self.indent -= 2;
1836 extra_index += decls_len;
1837 try stream.splatByteAll(' ', self.indent);
1838 try stream.writeAll("}, ");
1839 }
1840
1841 if (tag_type_ref != .none) {
1842 try self.writeInstRef(stream, tag_type_ref);
1843 try stream.writeAll(", ");
1844 }
1845
1846 const body = self.code.bodySlice(extra_index, body_len);
1847 extra_index += body.len;
1848
1849 try self.writeBracedDecl(stream, body);
1850 if (fields_len == 0) {
1851 try stream.writeAll(", {}) ");1588 try stream.writeAll(", {}) ");
1852 } else {1589 } else {
1853 try stream.writeAll(", {\n");1590 try stream.writeAll(", {\n");
1854
1855 self.indent += 2;1591 self.indent += 2;
1856 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
1857 const body_end = extra_index;
1858 extra_index += bit_bags_count;
1859 var bit_bag_index: usize = body_end;
1860 var cur_bit_bag: u32 = undefined;
1861 var field_i: u32 = 0;
1862 while (field_i < fields_len) : (field_i += 1) {
1863 if (field_i % 32 == 0) {
1864 cur_bit_bag = self.code.extra[bit_bag_index];
1865 bit_bag_index += 1;
1866 }
1867 const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0;
1868 cur_bit_bag >>= 1;
1869
1870 const field_name = self.code.nullTerminatedString(@enumFromInt(self.code.extra[extra_index]));
1871 extra_index += 1;
18721592
1593 var it = enum_decl.iterateFields();
1594 while (it.next()) |field| {
1873 try stream.splatByteAll(' ', self.indent);1595 try stream.splatByteAll(' ', self.indent);
1596 const field_name = self.code.nullTerminatedString(field.name);
1874 try stream.print("{f}", .{std.zig.fmtIdP(field_name)});1597 try stream.print("{f}", .{std.zig.fmtIdP(field_name)});
18751598 if (field.value_body) |body| {
1876 if (has_tag_value) {
1877 const tag_value_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1878 extra_index += 1;
1879
1880 try stream.writeAll(" = ");1599 try stream.writeAll(" = ");
1881 try self.writeInstRef(stream, tag_value_ref);1600 try self.writeBracedDecl(stream, body);
1882 }1601 }
1883 try stream.writeAll(",\n");1602 try stream.writeAll(",\n");
1884 }1603 }
...@@ -1889,47 +1608,18 @@ const Writer = struct {...@@ -1889,47 +1608,18 @@ const Writer = struct {
1889 try self.writeSrcNode(stream, .zero);1608 try self.writeSrcNode(stream, .zero);
1890 }1609 }
18911610
1892 fn writeOpaqueDecl(1611 fn writeOpaqueDecl(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
1893 self: *Writer,1612 const opaque_decl = self.code.getOpaqueDecl(inst);
1894 stream: *std.Io.Writer,
1895 extended: Zir.Inst.Extended.InstData,
1896 ) !void {
1897 const small = @as(Zir.Inst.OpaqueDecl.Small, @bitCast(extended.small));
1898 const extra = self.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
18991613
1900 const prev_parent_decl_node = self.parent_decl_node;1614 const prev_parent_decl_node = self.parent_decl_node;
1901 self.parent_decl_node = extra.data.src_node;1615 self.parent_decl_node = opaque_decl.src_node;
1902 defer self.parent_decl_node = prev_parent_decl_node;1616 defer self.parent_decl_node = prev_parent_decl_node;
19031617
1904 var extra_index: usize = extra.end;1618 try stream.print("{s}, ", .{@tagName(opaque_decl.name_strategy)});
19051619 try self.writeCaptures(stream, opaque_decl.captures, opaque_decl.capture_names);
1906 const captures_len = if (small.has_captures_len) blk: {
1907 const captures_len = self.code.extra[extra_index];
1908 extra_index += 1;
1909 break :blk captures_len;
1910 } else 0;
1911
1912 const decls_len = if (small.has_decls_len) blk: {
1913 const decls_len = self.code.extra[extra_index];
1914 extra_index += 1;
1915 break :blk decls_len;
1916 } else 0;
1917
1918 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
1919
1920 extra_index = try self.writeCaptures(stream, extra_index, captures_len);
1921 try stream.writeAll(", ");1620 try stream.writeAll(", ");
19221621 try self.writeBracedDecl(stream, opaque_decl.decls);
1923 if (decls_len == 0) {1622 try stream.writeAll(") ");
1924 try stream.writeAll("{}) ");
1925 } else {
1926 try stream.writeAll("{\n");
1927 self.indent += 2;
1928 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
1929 self.indent -= 2;
1930 try stream.splatByteAll(' ', self.indent);
1931 try stream.writeAll("}) ");
1932 }
1933 try self.writeSrcNode(stream, .zero);1623 try self.writeSrcNode(stream, .zero);
1934 }1624 }
19351625
...@@ -2588,14 +2278,11 @@ const Writer = struct {...@@ -2588,14 +2278,11 @@ const Writer = struct {
2588 return stream.print("%{d}", .{@intFromEnum(inst)});2278 return stream.print("%{d}", .{@intFromEnum(inst)});
2589 }2279 }
25902280
2591 fn writeCaptures(self: *Writer, stream: *std.Io.Writer, extra_index: usize, captures_len: u32) !usize {2281 fn writeCaptures(self: *Writer, stream: *std.Io.Writer, captures: []const Zir.Inst.Capture, capture_names: []const Zir.NullTerminatedString) !void {
2592 if (captures_len == 0) {2282 if (captures.len == 0) {
2593 try stream.writeAll("{}");2283 assert(capture_names.len == 0);
2594 return extra_index;2284 return stream.writeAll("{}");
2595 }2285 }
2596
2597 const captures: []const Zir.Inst.Capture = @ptrCast(self.code.extra[extra_index..][0..captures_len]);
2598 const capture_names: []const Zir.NullTerminatedString = @ptrCast(self.code.extra[extra_index + captures_len ..][0..captures_len]);
2599 for (captures, capture_names) |capture, name| {2286 for (captures, capture_names) |capture, name| {
2600 try stream.writeAll("{ ");2287 try stream.writeAll("{ ");
2601 if (name != .empty) {2288 if (name != .empty) {
...@@ -2604,8 +2291,6 @@ const Writer = struct {...@@ -2604,8 +2291,6 @@ const Writer = struct {
2604 }2291 }
2605 try self.writeCapture(stream, capture);2292 try self.writeCapture(stream, capture);
2606 }2293 }
2607
2608 return extra_index + 2 * captures_len;
2609 }2294 }
26102295
2611 fn writeCapture(self: *Writer, stream: *std.Io.Writer, capture: Zir.Inst.Capture) !void {2296 fn writeCapture(self: *Writer, stream: *std.Io.Writer, capture: Zir.Inst.Capture) !void {