authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-03-07 18:41:45-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-03-07 18:41:45-08:00
log97aa5f7b8a059f91b78ce7cd70cba0f3aa2c5118
tree4e2dc7d8083a24bb01cf8e94e684e3256b7f0a31
parent377ecc6afb14a112a07c6d2c3570e2b77b12a116
parent38331b1cabf86586bdf70c80ed98f74c60305160
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #19190 from mlugg/struct-equivalence

compiler: namespace type equivalence based on AST node + captures

39 files changed, 4063 insertions(+), 2919 deletions(-)

lib/std/zig/AstGen.zig+226-109
......@@ -44,6 +44,9 @@ compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{},
4444/// The topmost block of the current function.
4545fn_block: ?*GenZir = null,
4646fn_var_args: bool = false,
47/// Whether we are somewhere within a function. If `true`, any container decls may be
48/// generic and thus must be tunneled through closure.
49within_fn: bool = false,
4750/// The return type of the current function. This may be a trivial `Ref`, or
4851/// otherwise it refers to a `ret_type` instruction.
4952fn_ret_ty: Zir.Inst.Ref = .none,
......@@ -2205,7 +2208,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
22052208 },
22062209 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
22072210 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2208 .namespace, .enum_namespace => break,
2211 .namespace => break,
22092212 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
22102213 .top => unreachable,
22112214 }
......@@ -2279,7 +2282,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
22792282 try parent_gz.addDefer(defer_scope.index, defer_scope.len);
22802283 },
22812284 .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2282 .namespace, .enum_namespace => break,
2285 .namespace => break,
22832286 .top => unreachable,
22842287 }
22852288 }
......@@ -2412,7 +2415,7 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.Toke
24122415 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
24132416 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
24142417 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2415 .namespace, .enum_namespace => break,
2418 .namespace => break,
24162419 .top => unreachable,
24172420 }
24182421 }
......@@ -2790,7 +2793,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
27902793 .@"resume",
27912794 .@"await",
27922795 .ret_err_value_code,
2793 .closure_get,
27942796 .ret_ptr,
27952797 .ret_type,
27962798 .for_len,
......@@ -2860,7 +2862,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
28602862 .store_to_inferred_ptr,
28612863 .resolve_inferred_alloc,
28622864 .set_runtime_safety,
2863 .closure_capture,
28642865 .memcpy,
28652866 .memset,
28662867 .validate_deref,
......@@ -2928,7 +2929,7 @@ fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct {
29282929 const have_err_payload = defer_scope.remapped_err_code != .none;
29292930 need_err_code = need_err_code or have_err_payload;
29302931 },
2931 .namespace, .enum_namespace => unreachable,
2932 .namespace => unreachable,
29322933 .top => unreachable,
29332934 }
29342935 }
......@@ -2998,7 +2999,7 @@ fn genDefers(
29982999 .normal_only => continue,
29993000 }
30003001 },
3001 .namespace, .enum_namespace => unreachable,
3002 .namespace => unreachable,
30023003 .top => unreachable,
30033004 }
30043005 }
......@@ -3042,7 +3043,7 @@ fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!v
30423043 scope = s.parent;
30433044 },
30443045 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
3045 .namespace, .enum_namespace => unreachable,
3046 .namespace => unreachable,
30463047 .top => unreachable,
30473048 }
30483049 }
......@@ -4052,6 +4053,11 @@ fn fnDecl(
40524053 };
40534054 defer fn_gz.unstack();
40544055
4056 // Set this now, since parameter types, return type, etc may be generic.
4057 const prev_within_fn = astgen.within_fn;
4058 defer astgen.within_fn = prev_within_fn;
4059 astgen.within_fn = true;
4060
40554061 const is_pub = fn_proto.visib_token != null;
40564062 const is_export = blk: {
40574063 const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false;
......@@ -4313,6 +4319,10 @@ fn fnDecl(
43134319
43144320 const prev_fn_block = astgen.fn_block;
43154321 const prev_fn_ret_ty = astgen.fn_ret_ty;
4322 defer {
4323 astgen.fn_block = prev_fn_block;
4324 astgen.fn_ret_ty = prev_fn_ret_ty;
4325 }
43164326 astgen.fn_block = &fn_gz;
43174327 astgen.fn_ret_ty = if (is_inferred_error or ret_ref.toIndex() != null) r: {
43184328 // We're essentially guaranteed to need the return type at some point,
......@@ -4321,10 +4331,6 @@ fn fnDecl(
43214331 // return type now so the rest of the function can use it.
43224332 break :r try fn_gz.addNode(.ret_type, decl_node);
43234333 } else ret_ref;
4324 defer {
4325 astgen.fn_block = prev_fn_block;
4326 astgen.fn_ret_ty = prev_fn_ret_ty;
4327 }
43284334
43294335 const prev_var_args = astgen.fn_var_args;
43304336 astgen.fn_var_args = is_var_args;
......@@ -4732,7 +4738,7 @@ fn testDecl(
47324738 },
47334739 .gen_zir => s = s.cast(GenZir).?.parent,
47344740 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
4735 .namespace, .enum_namespace => {
4741 .namespace => {
47364742 const ns = s.cast(Scope.Namespace).?;
47374743 if (ns.decls.get(name_str_index)) |i| {
47384744 if (found_already) |f| {
......@@ -4770,11 +4776,14 @@ fn testDecl(
47704776 };
47714777 defer fn_block.unstack();
47724778
4779 const prev_within_fn = astgen.within_fn;
47734780 const prev_fn_block = astgen.fn_block;
47744781 const prev_fn_ret_ty = astgen.fn_ret_ty;
4782 astgen.within_fn = true;
47754783 astgen.fn_block = &fn_block;
47764784 astgen.fn_ret_ty = .anyerror_void_error_union_type;
47774785 defer {
4786 astgen.within_fn = prev_within_fn;
47784787 astgen.fn_block = prev_fn_block;
47794788 astgen.fn_ret_ty = prev_fn_ret_ty;
47804789 }
......@@ -4849,10 +4858,10 @@ fn structDeclInner(
48494858 try gz.setStruct(decl_inst, .{
48504859 .src_node = node,
48514860 .layout = layout,
4861 .captures_len = 0,
48524862 .fields_len = 0,
48534863 .decls_len = 0,
4854 .backing_int_ref = .none,
4855 .backing_int_body_len = 0,
4864 .has_backing_int = false,
48564865 .known_non_opv = false,
48574866 .known_comptime_only = false,
48584867 .is_tuple = false,
......@@ -4873,6 +4882,7 @@ fn structDeclInner(
48734882 .node = node,
48744883 .inst = decl_inst,
48754884 .declaring_gz = gz,
4885 .maybe_generic = astgen.within_fn,
48764886 };
48774887 defer namespace.deinit(gpa);
48784888
......@@ -5142,10 +5152,10 @@ fn structDeclInner(
51425152 try gz.setStruct(decl_inst, .{
51435153 .src_node = node,
51445154 .layout = layout,
5155 .captures_len = @intCast(namespace.captures.count()),
51455156 .fields_len = field_count,
51465157 .decls_len = decl_count,
5147 .backing_int_ref = backing_int_ref,
5148 .backing_int_body_len = @intCast(backing_int_body_len),
5158 .has_backing_int = backing_int_ref != .none,
51495159 .known_non_opv = known_non_opv,
51505160 .known_comptime_only = known_comptime_only,
51515161 .is_tuple = is_tuple,
......@@ -5159,15 +5169,22 @@ fn structDeclInner(
51595169 const decls_slice = wip_members.declsSlice();
51605170 const fields_slice = wip_members.fieldsSlice();
51615171 const bodies_slice = astgen.scratch.items[bodies_start..];
5162 try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len +
5163 decls_slice.len + fields_slice.len + bodies_slice.len);
5164 astgen.extra.appendSliceAssumeCapacity(astgen.scratch.items[scratch_top..][0..backing_int_body_len]);
5172 try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len + 2 +
5173 decls_slice.len + namespace.captures.count() + fields_slice.len + bodies_slice.len);
5174 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
5175 if (backing_int_ref != .none) {
5176 astgen.extra.appendAssumeCapacity(@intCast(backing_int_body_len));
5177 if (backing_int_body_len == 0) {
5178 astgen.extra.appendAssumeCapacity(@intFromEnum(backing_int_ref));
5179 } else {
5180 astgen.extra.appendSliceAssumeCapacity(astgen.scratch.items[scratch_top..][0..backing_int_body_len]);
5181 }
5182 }
51655183 astgen.extra.appendSliceAssumeCapacity(decls_slice);
51665184 astgen.extra.appendSliceAssumeCapacity(fields_slice);
51675185 astgen.extra.appendSliceAssumeCapacity(bodies_slice);
51685186
51695187 block_scope.unstack();
5170 try gz.addNamespaceCaptures(&namespace);
51715188 return decl_inst.toRef();
51725189}
51735190
......@@ -5190,6 +5207,7 @@ fn unionDeclInner(
51905207 .node = node,
51915208 .inst = decl_inst,
51925209 .declaring_gz = gz,
5210 .maybe_generic = astgen.within_fn,
51935211 };
51945212 defer namespace.deinit(gpa);
51955213
......@@ -5368,6 +5386,7 @@ fn unionDeclInner(
53685386 .src_node = node,
53695387 .layout = layout,
53705388 .tag_type = arg_inst,
5389 .captures_len = @intCast(namespace.captures.count()),
53715390 .body_len = body_len,
53725391 .fields_len = field_count,
53735392 .decls_len = decl_count,
......@@ -5379,13 +5398,13 @@ fn unionDeclInner(
53795398 wip_members.finishBits(bits_per_field);
53805399 const decls_slice = wip_members.declsSlice();
53815400 const fields_slice = wip_members.fieldsSlice();
5382 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len);
5401 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() + decls_slice.len + body_len + fields_slice.len);
5402 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
53835403 astgen.extra.appendSliceAssumeCapacity(decls_slice);
53845404 astgen.appendBodyWithFixups(body);
53855405 astgen.extra.appendSliceAssumeCapacity(fields_slice);
53865406
53875407 block_scope.unstack();
5388 try gz.addNamespaceCaptures(&namespace);
53895408 return decl_inst.toRef();
53905409}
53915410
......@@ -5537,6 +5556,7 @@ fn containerDecl(
55375556 .node = node,
55385557 .inst = decl_inst,
55395558 .declaring_gz = gz,
5559 .maybe_generic = astgen.within_fn,
55405560 };
55415561 defer namespace.deinit(gpa);
55425562
......@@ -5555,7 +5575,7 @@ fn containerDecl(
55555575 defer block_scope.unstack();
55565576
55575577 _ = try astgen.scanDecls(&namespace, container_decl.ast.members);
5558 namespace.base.tag = .enum_namespace;
5578 namespace.base.tag = .namespace;
55595579
55605580 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0)
55615581 try comptimeExpr(&block_scope, &namespace.base, coerced_type_ri, container_decl.ast.arg)
......@@ -5586,7 +5606,6 @@ fn containerDecl(
55865606 if (member_node == counts.nonexhaustive_node)
55875607 continue;
55885608 fields_hasher.update(tree.getNodeSource(member_node));
5589 namespace.base.tag = .namespace;
55905609 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
55915610 .decl => continue,
55925611 .field => |field| field,
......@@ -5630,7 +5649,6 @@ fn containerDecl(
56305649 },
56315650 );
56325651 }
5633 namespace.base.tag = .enum_namespace;
56345652 const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .rl = .{ .ty = arg_inst } }, member.ast.value_expr);
56355653 wip_members.appendToField(@intFromEnum(tag_value_inst));
56365654 }
......@@ -5676,6 +5694,7 @@ fn containerDecl(
56765694 .src_node = node,
56775695 .nonexhaustive = nonexhaustive,
56785696 .tag_type = arg_inst,
5697 .captures_len = @intCast(namespace.captures.count()),
56795698 .body_len = body_len,
56805699 .fields_len = @intCast(counts.total_fields),
56815700 .decls_len = @intCast(counts.decls),
......@@ -5685,13 +5704,13 @@ fn containerDecl(
56855704 wip_members.finishBits(bits_per_field);
56865705 const decls_slice = wip_members.declsSlice();
56875706 const fields_slice = wip_members.fieldsSlice();
5688 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len);
5707 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() + decls_slice.len + body_len + fields_slice.len);
5708 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
56895709 astgen.extra.appendSliceAssumeCapacity(decls_slice);
56905710 astgen.appendBodyWithFixups(body);
56915711 astgen.extra.appendSliceAssumeCapacity(fields_slice);
56925712
56935713 block_scope.unstack();
5694 try gz.addNamespaceCaptures(&namespace);
56955714 return rvalue(gz, ri, decl_inst.toRef(), node);
56965715 },
56975716 .keyword_opaque => {
......@@ -5704,6 +5723,7 @@ fn containerDecl(
57045723 .node = node,
57055724 .inst = decl_inst,
57065725 .declaring_gz = gz,
5726 .maybe_generic = astgen.within_fn,
57075727 };
57085728 defer namespace.deinit(gpa);
57095729
......@@ -5733,16 +5753,17 @@ fn containerDecl(
57335753
57345754 try gz.setOpaque(decl_inst, .{
57355755 .src_node = node,
5756 .captures_len = @intCast(namespace.captures.count()),
57365757 .decls_len = decl_count,
57375758 });
57385759
57395760 wip_members.finishBits(0);
57405761 const decls_slice = wip_members.declsSlice();
5741 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len);
5762 try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() + decls_slice.len);
5763 astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
57425764 astgen.extra.appendSliceAssumeCapacity(decls_slice);
57435765
57445766 block_scope.unstack();
5745 try gz.addNamespaceCaptures(&namespace);
57465767 return rvalue(gz, ri, decl_inst.toRef(), node);
57475768 },
57485769 else => unreachable,
......@@ -8238,12 +8259,17 @@ fn localVarRef(
82388259 ident_token: Ast.TokenIndex,
82398260) InnerError!Zir.Inst.Ref {
82408261 const astgen = gz.astgen;
8241 const gpa = astgen.gpa;
82428262 const name_str_index = try astgen.identAsString(ident_token);
82438263 var s = scope;
82448264 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already
8265 var found_needs_tunnel: bool = undefined; // defined when `found_already != null`
8266 var found_namespaces_out: u32 = undefined; // defined when `found_already != null`
8267
8268 // The number of namespaces above `gz` we currently are
82458269 var num_namespaces_out: u32 = 0;
8246 var capturing_namespace: ?*Scope.Namespace = null;
8270 // defined by `num_namespaces_out != 0`
8271 var capturing_namespace: *Scope.Namespace = undefined;
8272
82478273 while (true) switch (s.tag) {
82488274 .local_val => {
82498275 const local_val = s.cast(Scope.LocalVal).?;
......@@ -8257,15 +8283,13 @@ fn localVarRef(
82578283 local_val.used = ident_token;
82588284 }
82598285
8260 const value_inst = try tunnelThroughClosure(
8286 const value_inst = if (num_namespaces_out != 0) try tunnelThroughClosure(
82618287 gz,
82628288 ident,
82638289 num_namespaces_out,
8264 capturing_namespace,
8265 local_val.inst,
8266 local_val.token_src,
8267 gpa,
8268 );
8290 .{ .ref = local_val.inst },
8291 .{ .token = local_val.token_src },
8292 ) else local_val.inst;
82698293
82708294 return rvalueNoCoercePreRef(gz, ri, value_inst, ident);
82718295 }
......@@ -8285,19 +8309,17 @@ fn localVarRef(
82858309 const ident_name = try astgen.identifierTokenString(ident_token);
82868310 return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{
82878311 try astgen.errNoteTok(local_ptr.token_src, "declared mutable here", .{}),
8288 try astgen.errNoteNode(capturing_namespace.?.node, "crosses namespace boundary here", .{}),
8312 try astgen.errNoteNode(capturing_namespace.node, "crosses namespace boundary here", .{}),
82898313 });
82908314 }
82918315
8292 const ptr_inst = try tunnelThroughClosure(
8316 const ptr_inst = if (num_namespaces_out != 0) try tunnelThroughClosure(
82938317 gz,
82948318 ident,
82958319 num_namespaces_out,
8296 capturing_namespace,
8297 local_ptr.ptr,
8298 local_ptr.token_src,
8299 gpa,
8300 );
8320 .{ .ref = local_ptr.ptr },
8321 .{ .token = local_ptr.token_src },
8322 ) else local_ptr.ptr;
83018323
83028324 switch (ri.rl) {
83038325 .ref, .ref_coerced_ty => {
......@@ -8314,7 +8336,7 @@ fn localVarRef(
83148336 },
83158337 .gen_zir => s = s.cast(GenZir).?.parent,
83168338 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
8317 .namespace, .enum_namespace => {
8339 .namespace => {
83188340 const ns = s.cast(Scope.Namespace).?;
83198341 if (ns.decls.get(name_str_index)) |i| {
83208342 if (found_already) |f| {
......@@ -8325,8 +8347,10 @@ fn localVarRef(
83258347 }
83268348 // We found a match but must continue looking for ambiguous references to decls.
83278349 found_already = i;
8350 found_needs_tunnel = ns.maybe_generic;
8351 found_namespaces_out = num_namespaces_out;
83288352 }
8329 if (s.tag == .namespace) num_namespaces_out += 1;
8353 num_namespaces_out += 1;
83308354 capturing_namespace = ns;
83318355 s = ns.parent;
83328356 },
......@@ -8339,6 +8363,29 @@ fn localVarRef(
83398363
83408364 // Decl references happen by name rather than ZIR index so that when unrelated
83418365 // decls are modified, ZIR code containing references to them can be unmodified.
8366
8367 if (found_namespaces_out > 0 and found_needs_tunnel) {
8368 switch (ri.rl) {
8369 .ref, .ref_coerced_ty => return tunnelThroughClosure(
8370 gz,
8371 ident,
8372 found_namespaces_out,
8373 .{ .decl_ref = name_str_index },
8374 .{ .node = found_already.? },
8375 ),
8376 else => {
8377 const result = try tunnelThroughClosure(
8378 gz,
8379 ident,
8380 found_namespaces_out,
8381 .{ .decl_val = name_str_index },
8382 .{ .node = found_already.? },
8383 );
8384 return rvalueNoCoercePreRef(gz, ri, result, ident);
8385 },
8386 }
8387 }
8388
83428389 switch (ri.rl) {
83438390 .ref, .ref_coerced_ty => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
83448391 else => {
......@@ -8348,41 +8395,90 @@ fn localVarRef(
83488395 }
83498396}
83508397
8351/// Adds a capture to a namespace, if needed.
8352/// Returns the index of the closure_capture instruction.
8398/// Access a ZIR instruction through closure. May tunnel through arbitrarily
8399/// many namespaces, adding closure captures as required.
8400/// Returns the index of the `closure_get` instruction added to `gz`.
83538401fn tunnelThroughClosure(
83548402 gz: *GenZir,
8403 /// The node which references the value to be captured.
83558404 inner_ref_node: Ast.Node.Index,
8405 /// The number of namespaces being tunnelled through. At least 1.
83568406 num_tunnels: u32,
8357 ns: ?*Scope.Namespace,
8358 value: Zir.Inst.Ref,
8359 token: Ast.TokenIndex,
8360 gpa: Allocator,
8407 /// The value being captured.
8408 value: union(enum) {
8409 ref: Zir.Inst.Ref,
8410 decl_val: Zir.NullTerminatedString,
8411 decl_ref: Zir.NullTerminatedString,
8412 },
8413 /// The location of the value's declaration.
8414 decl_src: union(enum) {
8415 token: Ast.TokenIndex,
8416 node: Ast.Node.Index,
8417 },
83618418) !Zir.Inst.Ref {
8362 // For trivial values, we don't need a tunnel.
8363 // Just return the ref.
8364 if (num_tunnels == 0 or value.toIndex() == null) {
8365 return value;
8419 switch (value) {
8420 .ref => |v| if (v.toIndex() == null) return v, // trivia value; do not need tunnel
8421 .decl_val, .decl_ref => {},
83668422 }
83678423
8368 // Otherwise we need a tunnel. Check if this namespace
8369 // already has one for this value.
8370 const gop = try ns.?.captures.getOrPut(gpa, value.toIndex().?);
8371 if (!gop.found_existing) {
8372 // Make a new capture for this value but don't add it to the declaring_gz yet
8373 try gz.astgen.instructions.append(gz.astgen.gpa, .{
8374 .tag = .closure_capture,
8375 .data = .{ .un_tok = .{
8376 .operand = value,
8377 .src_tok = ns.?.declaring_gz.?.tokenIndexToRelative(token),
8378 } },
8424 const astgen = gz.astgen;
8425 const gpa = astgen.gpa;
8426
8427 // Otherwise we need a tunnel. First, figure out the path of namespaces we
8428 // are tunneling through. This is usually only going to be one or two, so
8429 // use an SFBA to optimize for the common case.
8430 var sfba = std.heap.stackFallback(@sizeOf(usize) * 2, astgen.arena);
8431 var intermediate_tunnels = try sfba.get().alloc(*Scope.Namespace, num_tunnels - 1);
8432
8433 const root_ns = ns: {
8434 var i: usize = num_tunnels - 1;
8435 var scope: *Scope = gz.parent;
8436 while (i > 0) {
8437 if (scope.cast(Scope.Namespace)) |mid_ns| {
8438 i -= 1;
8439 intermediate_tunnels[i] = mid_ns;
8440 }
8441 scope = scope.parent().?;
8442 }
8443 while (true) {
8444 if (scope.cast(Scope.Namespace)) |ns| break :ns ns;
8445 scope = scope.parent().?;
8446 }
8447 };
8448
8449 // Now that we know the scopes we're tunneling through, begin adding
8450 // captures as required, starting with the outermost namespace.
8451 const root_capture = Zir.Inst.Capture.wrap(switch (value) {
8452 .ref => |v| .{ .instruction = v.toIndex().? },
8453 .decl_val => |str| .{ .decl_val = str },
8454 .decl_ref => |str| .{ .decl_ref = str },
8455 });
8456 var cur_capture_index = std.math.cast(
8457 u16,
8458 (try root_ns.captures.getOrPut(gpa, root_capture)).index,
8459 ) orelse return astgen.failNodeNotes(root_ns.node, "this compiler implementation only supports up to 65536 captures per namespace", .{}, &.{
8460 switch (decl_src) {
8461 .token => |t| try astgen.errNoteTok(t, "captured value here", .{}),
8462 .node => |n| try astgen.errNoteNode(n, "captured value here", .{}),
8463 },
8464 try astgen.errNoteNode(inner_ref_node, "value used here", .{}),
8465 });
8466
8467 for (intermediate_tunnels) |tunnel_ns| {
8468 cur_capture_index = std.math.cast(
8469 u16,
8470 (try tunnel_ns.captures.getOrPut(gpa, Zir.Inst.Capture.wrap(.{ .nested = cur_capture_index }))).index,
8471 ) orelse return astgen.failNodeNotes(tunnel_ns.node, "this compiler implementation only supports up to 65536 captures per namespace", .{}, &.{
8472 switch (decl_src) {
8473 .token => |t| try astgen.errNoteTok(t, "captured value here", .{}),
8474 .node => |n| try astgen.errNoteNode(n, "captured value here", .{}),
8475 },
8476 try astgen.errNoteNode(inner_ref_node, "value used here", .{}),
83798477 });
8380 gop.value_ptr.* = @enumFromInt(gz.astgen.instructions.len - 1);
83818478 }
83828479
8383 // Add an instruction to get the value from the closure into
8384 // our current context
8385 return try gz.addInstNode(.closure_get, gop.value_ptr.*, inner_ref_node);
8480 // Add an instruction to get the value from the closure.
8481 return gz.addExtendedNodeSmall(.closure_get, inner_ref_node, cur_capture_index);
83868482}
83878483
83888484fn stringLiteral(
......@@ -9095,7 +9191,7 @@ fn builtinCall(
90959191 },
90969192 .gen_zir => s = s.cast(GenZir).?.parent,
90979193 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
9098 .namespace, .enum_namespace => {
9194 .namespace => {
90999195 const ns = s.cast(Scope.Namespace).?;
91009196 if (ns.decls.get(decl_name)) |i| {
91019197 if (found_already) |f| {
......@@ -11605,7 +11701,7 @@ const Scope = struct {
1160511701 }
1160611702 if (T == Namespace) {
1160711703 switch (base.tag) {
11608 .namespace, .enum_namespace => return @fieldParentPtr(T, "base", base),
11704 .namespace => return @fieldParentPtr(T, "base", base),
1160911705 else => return null,
1161011706 }
1161111707 }
......@@ -11621,7 +11717,7 @@ const Scope = struct {
1162111717 .local_val => base.cast(LocalVal).?.parent,
1162211718 .local_ptr => base.cast(LocalPtr).?.parent,
1162311719 .defer_normal, .defer_error => base.cast(Defer).?.parent,
11624 .namespace, .enum_namespace => base.cast(Namespace).?.parent,
11720 .namespace => base.cast(Namespace).?.parent,
1162511721 .top => null,
1162611722 };
1162711723 }
......@@ -11633,7 +11729,6 @@ const Scope = struct {
1163311729 defer_normal,
1163411730 defer_error,
1163511731 namespace,
11636 enum_namespace,
1163711732 top,
1163811733 };
1163911734
......@@ -11720,14 +11815,14 @@ const Scope = struct {
1172011815 decls: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{},
1172111816 node: Ast.Node.Index,
1172211817 inst: Zir.Inst.Index,
11818 maybe_generic: bool,
1172311819
1172411820 /// The astgen scope containing this namespace.
1172511821 /// Only valid during astgen.
1172611822 declaring_gz: ?*GenZir,
1172711823
11728 /// Map from the raw captured value to the instruction
11729 /// ref of the capture for decls in this namespace
11730 captures: std.AutoArrayHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
11824 /// Set of captures used by this namespace.
11825 captures: std.AutoArrayHashMapUnmanaged(Zir.Inst.Capture, void) = .{},
1173111826
1173211827 fn deinit(self: *Namespace, gpa: Allocator) void {
1173311828 self.decls.deinit(gpa);
......@@ -11787,12 +11882,6 @@ const GenZir = struct {
1178711882 // Set if this GenZir is a defer or it is inside a defer.
1178811883 any_defer_node: Ast.Node.Index = 0,
1178911884
11790 /// Namespace members are lazy. When executing a decl within a namespace,
11791 /// any references to external instructions need to be treated specially.
11792 /// This list tracks those references. See also .closure_capture and .closure_get.
11793 /// Keys are the raw instruction index, values are the closure_capture instruction.
11794 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
11795
1179611885 const unstacked_top = std.math.maxInt(usize);
1179711886 /// Call unstack before adding any new instructions to containing GenZir.
1179811887 fn unstack(self: *GenZir) void {
......@@ -12534,6 +12623,30 @@ const GenZir = struct {
1253412623 return new_index.toRef();
1253512624 }
1253612625
12626 fn addExtendedNodeSmall(
12627 gz: *GenZir,
12628 opcode: Zir.Inst.Extended,
12629 src_node: Ast.Node.Index,
12630 small: u16,
12631 ) !Zir.Inst.Ref {
12632 const astgen = gz.astgen;
12633 const gpa = astgen.gpa;
12634
12635 try gz.instructions.ensureUnusedCapacity(gpa, 1);
12636 try astgen.instructions.ensureUnusedCapacity(gpa, 1);
12637 const new_index: Zir.Inst.Index = @enumFromInt(astgen.instructions.len);
12638 astgen.instructions.appendAssumeCapacity(.{
12639 .tag = .extended,
12640 .data = .{ .extended = .{
12641 .opcode = opcode,
12642 .small = small,
12643 .operand = @bitCast(gz.nodeIndexToRelative(src_node)),
12644 } },
12645 });
12646 gz.instructions.appendAssumeCapacity(new_index);
12647 return new_index.toRef();
12648 }
12649
1253712650 fn addUnTok(
1253812651 gz: *GenZir,
1253912652 tag: Zir.Inst.Tag,
......@@ -12957,10 +13070,10 @@ const GenZir = struct {
1295713070
1295813071 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
1295913072 src_node: Ast.Node.Index,
13073 captures_len: u32,
1296013074 fields_len: u32,
1296113075 decls_len: u32,
12962 backing_int_ref: Zir.Inst.Ref,
12963 backing_int_body_len: u32,
13076 has_backing_int: bool,
1296413077 layout: std.builtin.Type.ContainerLayout,
1296513078 known_non_opv: bool,
1296613079 known_comptime_only: bool,
......@@ -12978,7 +13091,7 @@ const GenZir = struct {
1297813091
1297913092 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1298013093
12981 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).Struct.fields.len + 4);
13094 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).Struct.fields.len + 3);
1298213095 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
1298313096 .fields_hash_0 = fields_hash_arr[0],
1298413097 .fields_hash_1 = fields_hash_arr[1],
......@@ -12987,26 +13100,24 @@ const GenZir = struct {
1298713100 .src_node = gz.nodeIndexToRelative(args.src_node),
1298813101 });
1298913102
13103 if (args.captures_len != 0) {
13104 astgen.extra.appendAssumeCapacity(args.captures_len);
13105 }
1299013106 if (args.fields_len != 0) {
1299113107 astgen.extra.appendAssumeCapacity(args.fields_len);
1299213108 }
1299313109 if (args.decls_len != 0) {
1299413110 astgen.extra.appendAssumeCapacity(args.decls_len);
1299513111 }
12996 if (args.backing_int_ref != .none) {
12997 astgen.extra.appendAssumeCapacity(args.backing_int_body_len);
12998 if (args.backing_int_body_len == 0) {
12999 astgen.extra.appendAssumeCapacity(@intFromEnum(args.backing_int_ref));
13000 }
13001 }
1300213112 astgen.instructions.set(@intFromEnum(inst), .{
1300313113 .tag = .extended,
1300413114 .data = .{ .extended = .{
1300513115 .opcode = .struct_decl,
1300613116 .small = @bitCast(Zir.Inst.StructDecl.Small{
13117 .has_captures_len = args.captures_len != 0,
1300713118 .has_fields_len = args.fields_len != 0,
1300813119 .has_decls_len = args.decls_len != 0,
13009 .has_backing_int = args.backing_int_ref != .none,
13120 .has_backing_int = args.has_backing_int,
1301013121 .known_non_opv = args.known_non_opv,
1301113122 .known_comptime_only = args.known_comptime_only,
1301213123 .is_tuple = args.is_tuple,
......@@ -13024,6 +13135,7 @@ const GenZir = struct {
1302413135 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
1302513136 src_node: Ast.Node.Index,
1302613137 tag_type: Zir.Inst.Ref,
13138 captures_len: u32,
1302713139 body_len: u32,
1302813140 fields_len: u32,
1302913141 decls_len: u32,
......@@ -13039,7 +13151,7 @@ const GenZir = struct {
1303913151
1304013152 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1304113153
13042 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len + 4);
13154 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len + 5);
1304313155 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{
1304413156 .fields_hash_0 = fields_hash_arr[0],
1304513157 .fields_hash_1 = fields_hash_arr[1],
......@@ -13051,6 +13163,9 @@ const GenZir = struct {
1305113163 if (args.tag_type != .none) {
1305213164 astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));
1305313165 }
13166 if (args.captures_len != 0) {
13167 astgen.extra.appendAssumeCapacity(args.captures_len);
13168 }
1305413169 if (args.body_len != 0) {
1305513170 astgen.extra.appendAssumeCapacity(args.body_len);
1305613171 }
......@@ -13066,6 +13181,7 @@ const GenZir = struct {
1306613181 .opcode = .union_decl,
1306713182 .small = @bitCast(Zir.Inst.UnionDecl.Small{
1306813183 .has_tag_type = args.tag_type != .none,
13184 .has_captures_len = args.captures_len != 0,
1306913185 .has_body_len = args.body_len != 0,
1307013186 .has_fields_len = args.fields_len != 0,
1307113187 .has_decls_len = args.decls_len != 0,
......@@ -13082,6 +13198,7 @@ const GenZir = struct {
1308213198 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
1308313199 src_node: Ast.Node.Index,
1308413200 tag_type: Zir.Inst.Ref,
13201 captures_len: u32,
1308513202 body_len: u32,
1308613203 fields_len: u32,
1308713204 decls_len: u32,
......@@ -13095,7 +13212,7 @@ const GenZir = struct {
1309513212
1309613213 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
1309713214
13098 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len + 4);
13215 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len + 5);
1309913216 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{
1310013217 .fields_hash_0 = fields_hash_arr[0],
1310113218 .fields_hash_1 = fields_hash_arr[1],
......@@ -13107,6 +13224,9 @@ const GenZir = struct {
1310713224 if (args.tag_type != .none) {
1310813225 astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));
1310913226 }
13227 if (args.captures_len != 0) {
13228 astgen.extra.appendAssumeCapacity(args.captures_len);
13229 }
1311013230 if (args.body_len != 0) {
1311113231 astgen.extra.appendAssumeCapacity(args.body_len);
1311213232 }
......@@ -13122,6 +13242,7 @@ const GenZir = struct {
1312213242 .opcode = .enum_decl,
1312313243 .small = @bitCast(Zir.Inst.EnumDecl.Small{
1312413244 .has_tag_type = args.tag_type != .none,
13245 .has_captures_len = args.captures_len != 0,
1312513246 .has_body_len = args.body_len != 0,
1312613247 .has_fields_len = args.fields_len != 0,
1312713248 .has_decls_len = args.decls_len != 0,
......@@ -13135,6 +13256,7 @@ const GenZir = struct {
1313513256
1313613257 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
1313713258 src_node: Ast.Node.Index,
13259 captures_len: u32,
1313813260 decls_len: u32,
1313913261 }) !void {
1314013262 const astgen = gz.astgen;
......@@ -13142,11 +13264,14 @@ const GenZir = struct {
1314213264
1314313265 assert(args.src_node != 0);
1314413266
13145 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).Struct.fields.len + 1);
13267 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).Struct.fields.len + 2);
1314613268 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{
1314713269 .src_node = gz.nodeIndexToRelative(args.src_node),
1314813270 });
1314913271
13272 if (args.captures_len != 0) {
13273 astgen.extra.appendAssumeCapacity(args.captures_len);
13274 }
1315013275 if (args.decls_len != 0) {
1315113276 astgen.extra.appendAssumeCapacity(args.decls_len);
1315213277 }
......@@ -13155,6 +13280,7 @@ const GenZir = struct {
1315513280 .data = .{ .extended = .{
1315613281 .opcode = .opaque_decl,
1315713282 .small = @bitCast(Zir.Inst.OpaqueDecl.Small{
13283 .has_captures_len = args.captures_len != 0,
1315813284 .has_decls_len = args.decls_len != 0,
1315913285 .name_strategy = gz.anon_name_strategy,
1316013286 }),
......@@ -13197,15 +13323,6 @@ const GenZir = struct {
1319713323 }
1319813324 }
1319913325
13200 fn addNamespaceCaptures(gz: *GenZir, namespace: *Scope.Namespace) !void {
13201 if (namespace.captures.count() > 0) {
13202 try gz.instructions.ensureUnusedCapacity(gz.astgen.gpa, namespace.captures.count());
13203 for (namespace.captures.values()) |capture| {
13204 gz.instructions.appendAssumeCapacity(capture);
13205 }
13206 }
13207 }
13208
1320913326 fn addDbgVar(gz: *GenZir, tag: Zir.Inst.Tag, name: Zir.NullTerminatedString, inst: Zir.Inst.Ref) !void {
1321013327 if (gz.is_comptime) return;
1321113328
......@@ -13305,7 +13422,7 @@ fn detectLocalShadowing(
1330513422 }
1330613423 s = local_ptr.parent;
1330713424 },
13308 .namespace, .enum_namespace => {
13425 .namespace => {
1330913426 outer_scope = true;
1331013427 const ns = s.cast(Scope.Namespace).?;
1331113428 const decl_node = ns.decls.get(ident_name) orelse {
......@@ -13478,7 +13595,7 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
1347813595 }
1347913596 s = local_ptr.parent;
1348013597 },
13481 .namespace, .enum_namespace => s = s.cast(Scope.Namespace).?.parent,
13598 .namespace => s = s.cast(Scope.Namespace).?.parent,
1348213599 .gen_zir => s = s.cast(GenZir).?.parent,
1348313600 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
1348413601 .top => break,
lib/std/zig/Zir.zig+123-48
......@@ -1004,17 +1004,6 @@ pub const Inst = struct {
10041004 @"resume",
10051005 @"await",
10061006
1007 /// When a type or function refers to a comptime value from an outer
1008 /// scope, that forms a closure over comptime value. The outer scope
1009 /// will record a capture of that value, which encodes its current state
1010 /// and marks it to persist. Uses `un_tok` field. Operand is the
1011 /// instruction value to capture.
1012 closure_capture,
1013 /// The inner scope of a closure uses closure_get to retrieve the value
1014 /// stored by the outer scope. Uses `inst_node` field. Operand is the
1015 /// closure_capture instruction ref.
1016 closure_get,
1017
10181007 /// A defer statement.
10191008 /// Uses the `defer` union field.
10201009 @"defer",
......@@ -1251,8 +1240,6 @@ pub const Inst = struct {
12511240 .@"await",
12521241 .ret_err_value_code,
12531242 .extended,
1254 .closure_get,
1255 .closure_capture,
12561243 .ret_ptr,
12571244 .ret_type,
12581245 .@"try",
......@@ -1542,8 +1529,6 @@ pub const Inst = struct {
15421529 .@"resume",
15431530 .@"await",
15441531 .ret_err_value_code,
1545 .closure_get,
1546 .closure_capture,
15471532 .@"break",
15481533 .break_inline,
15491534 .condbr,
......@@ -1829,9 +1814,6 @@ pub const Inst = struct {
18291814 .@"resume" = .un_node,
18301815 .@"await" = .un_node,
18311816
1832 .closure_capture = .un_tok,
1833 .closure_get = .inst_node,
1834
18351817 .@"defer" = .@"defer",
18361818 .defer_err_code = .defer_err_code,
18371819
......@@ -2074,6 +2056,10 @@ pub const Inst = struct {
20742056 /// `operand` is payload index to `RestoreErrRetIndex`.
20752057 /// `small` is undefined.
20762058 restore_err_ret_index,
2059 /// Retrieves a value from the current type declaration scope's closure.
2060 /// `operand` is `src_node: i32`.
2061 /// `small` is closure index.
2062 closure_get,
20772063 /// Used as a placeholder instruction which is just a dummy index for Sema to replace
20782064 /// with a specific value. For instance, this is used for the capture of an `errdefer`.
20792065 /// This should never appear in a body.
......@@ -2949,7 +2935,7 @@ pub const Inst = struct {
29492935 /// These are stored in trailing data in `extra` for each prong.
29502936 pub const ProngInfo = packed struct(u32) {
29512937 body_len: u28,
2952 capture: Capture,
2938 capture: ProngInfo.Capture,
29532939 is_inline: bool,
29542940 has_tag_capture: bool,
29552941
......@@ -3013,19 +2999,21 @@ pub const Inst = struct {
30132999 };
30143000
30153001 /// Trailing:
3016 /// 0. fields_len: u32, // if has_fields_len
3017 /// 1. decls_len: u32, // if has_decls_len
3018 /// 2. backing_int_body_len: u32, // if has_backing_int
3019 /// 3. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
3020 /// 4. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
3021 /// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
3022 /// 6. flags: u32 // for every 8 fields
3002 /// 0. captures_len: u32 // if has_captures_len
3003 /// 1. fields_len: u32, // if has_fields_len
3004 /// 2. decls_len: u32, // if has_decls_len
3005 /// 3. capture: Capture // for every captures_len
3006 /// 4. backing_int_body_len: u32, // if has_backing_int
3007 /// 5. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
3008 /// 6. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
3009 /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction
3010 /// 8. flags: u32 // for every 8 fields
30233011 /// - sets of 4 bits:
30243012 /// 0b000X: whether corresponding field has an align expression
30253013 /// 0b00X0: whether corresponding field has a default expression
30263014 /// 0b0X00: whether corresponding field is comptime
30273015 /// 0bX000: whether corresponding field has a type expression
3028 /// 7. fields: { // for every fields_len
3016 /// 9. fields: { // for every fields_len
30293017 /// field_name: u32, // if !is_tuple
30303018 /// doc_comment: NullTerminatedString, // .empty if no doc comment
30313019 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
......@@ -3033,7 +3021,7 @@ pub const Inst = struct {
30333021 /// align_body_len: u32, // if corresponding bit is set
30343022 /// init_body_len: u32, // if corresponding bit is set
30353023 /// }
3036 /// 8. bodies: { // for every fields_len
3024 /// 10. bodies: { // for every fields_len
30373025 /// field_type_body_inst: Inst, // for each field_type_body_len
30383026 /// align_body_inst: Inst, // for each align_body_len
30393027 /// init_body_inst: Inst, // for each init_body_len
......@@ -3052,6 +3040,7 @@ pub const Inst = struct {
30523040 }
30533041
30543042 pub const Small = packed struct {
3043 has_captures_len: bool,
30553044 has_fields_len: bool,
30563045 has_decls_len: bool,
30573046 has_backing_int: bool,
......@@ -3063,8 +3052,57 @@ pub const Inst = struct {
30633052 any_default_inits: bool,
30643053 any_comptime_fields: bool,
30653054 any_aligned_fields: bool,
3066 _: u3 = undefined,
3055 _: u2 = undefined,
3056 };
3057 };
3058
3059 /// Represents a single value being captured in a type declaration's closure.
3060 pub const Capture = packed struct(u32) {
3061 tag: enum(u2) {
3062 /// `data` is a `u16` index into the parent closure.
3063 nested,
3064 /// `data` is a `Zir.Inst.Index` to an instruction whose value is being captured.
3065 instruction,
3066 /// `data` is a `NullTerminatedString` to a decl name.
3067 decl_val,
3068 /// `data` is a `NullTerminatedString` to a decl name.
3069 decl_ref,
3070 },
3071 data: u30,
3072 pub const Unwrapped = union(enum) {
3073 nested: u16,
3074 instruction: Zir.Inst.Index,
3075 decl_val: NullTerminatedString,
3076 decl_ref: NullTerminatedString,
30673077 };
3078 pub fn wrap(cap: Unwrapped) Capture {
3079 return switch (cap) {
3080 .nested => |idx| .{
3081 .tag = .nested,
3082 .data = idx,
3083 },
3084 .instruction => |inst| .{
3085 .tag = .instruction,
3086 .data = @intCast(@intFromEnum(inst)),
3087 },
3088 .decl_val => |str| .{
3089 .tag = .decl_val,
3090 .data = @intCast(@intFromEnum(str)),
3091 },
3092 .decl_ref => |str| .{
3093 .tag = .decl_ref,
3094 .data = @intCast(@intFromEnum(str)),
3095 },
3096 };
3097 }
3098 pub fn unwrap(cap: Capture) Unwrapped {
3099 return switch (cap.tag) {
3100 .nested => .{ .nested = @intCast(cap.data) },
3101 .instruction => .{ .instruction = @enumFromInt(cap.data) },
3102 .decl_val => .{ .decl_val = @enumFromInt(cap.data) },
3103 .decl_ref => .{ .decl_ref = @enumFromInt(cap.data) },
3104 };
3105 }
30683106 };
30693107
30703108 pub const NameStrategy = enum(u2) {
......@@ -3098,14 +3136,16 @@ pub const Inst = struct {
30983136
30993137 /// Trailing:
31003138 /// 0. tag_type: Ref, // if has_tag_type
3101 /// 1. body_len: u32, // if has_body_len
3102 /// 2. fields_len: u32, // if has_fields_len
3103 /// 3. decls_len: u32, // if has_decls_len
3104 /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction
3105 /// 5. inst: Index // for every body_len
3106 /// 6. has_bits: u32 // for every 32 fields
3139 /// 1. captures_len: u32, // if has_captures_len
3140 /// 2. body_len: u32, // if has_body_len
3141 /// 3. fields_len: u32, // if has_fields_len
3142 /// 4. decls_len: u32, // if has_decls_len
3143 /// 5. capture: Capture // for every captures_len
3144 /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction
3145 /// 7. inst: Index // for every body_len
3146 /// 8. has_bits: u32 // for every 32 fields
31073147 /// - the bit is whether corresponding field has an value expression
3108 /// 7. fields: { // for every fields_len
3148 /// 9. fields: { // for every fields_len
31093149 /// field_name: u32,
31103150 /// doc_comment: u32, // .empty if no doc_comment
31113151 /// value: Ref, // if corresponding bit is set
......@@ -3125,29 +3165,32 @@ pub const Inst = struct {
31253165
31263166 pub const Small = packed struct {
31273167 has_tag_type: bool,
3168 has_captures_len: bool,
31283169 has_body_len: bool,
31293170 has_fields_len: bool,
31303171 has_decls_len: bool,
31313172 name_strategy: NameStrategy,
31323173 nonexhaustive: bool,
3133 _: u9 = undefined,
3174 _: u8 = undefined,
31343175 };
31353176 };
31363177
31373178 /// Trailing:
31383179 /// 0. tag_type: Ref, // if has_tag_type
3139 /// 1. body_len: u32, // if has_body_len
3140 /// 2. fields_len: u32, // if has_fields_len
3141 /// 3. decls_len: u32, // if has_decls_len
3142 /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction
3143 /// 5. inst: Index // for every body_len
3144 /// 6. has_bits: u32 // for every 8 fields
3180 /// 1. captures_len: u32 // if has_captures_len
3181 /// 2. body_len: u32, // if has_body_len
3182 /// 3. fields_len: u32, // if has_fields_len
3183 /// 4. decls_len: u37, // if has_decls_len
3184 /// 5. capture: Capture // for every captures_len
3185 /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction
3186 /// 7. inst: Index // for every body_len
3187 /// 8. has_bits: u32 // for every 8 fields
31453188 /// - sets of 4 bits:
31463189 /// 0b000X: whether corresponding field has a type expression
31473190 /// 0b00X0: whether corresponding field has a align expression
31483191 /// 0b0X00: whether corresponding field has a tag value expression
31493192 /// 0bX000: unused
3150 /// 7. fields: { // for every fields_len
3193 /// 9. fields: { // for every fields_len
31513194 /// field_name: NullTerminatedString, // null terminated string index
31523195 /// doc_comment: NullTerminatedString, // .empty if no doc comment
31533196 /// field_type: Ref, // if corresponding bit is set
......@@ -3170,6 +3213,7 @@ pub const Inst = struct {
31703213
31713214 pub const Small = packed struct {
31723215 has_tag_type: bool,
3216 has_captures_len: bool,
31733217 has_body_len: bool,
31743218 has_fields_len: bool,
31753219 has_decls_len: bool,
......@@ -3183,13 +3227,15 @@ pub const Inst = struct {
31833227 /// true | false | union(T) { }
31843228 auto_enum_tag: bool,
31853229 any_aligned_fields: bool,
3186 _: u6 = undefined,
3230 _: u5 = undefined,
31873231 };
31883232 };
31893233
31903234 /// Trailing:
3191 /// 0. decls_len: u32, // if has_decls_len
3192 /// 1. decl: Index, // for every decls_len; points to a `declaration` instruction
3235 /// 0. captures_len: u32, // if has_captures_len
3236 /// 1. decls_len: u32, // if has_decls_len
3237 /// 2. capture: Capture, // for every captures_len
3238 /// 3. decl: Index, // for every decls_len; points to a `declaration` instruction
31933239 pub const OpaqueDecl = struct {
31943240 src_node: i32,
31953241
......@@ -3198,9 +3244,10 @@ pub const Inst = struct {
31983244 }
31993245
32003246 pub const Small = packed struct {
3247 has_captures_len: bool,
32013248 has_decls_len: bool,
32023249 name_strategy: NameStrategy,
3203 _: u13 = undefined,
3250 _: u12 = undefined,
32043251 };
32053252 };
32063253
......@@ -3502,6 +3549,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35023549 .struct_decl => {
35033550 const small: Inst.StructDecl.Small = @bitCast(extended.small);
35043551 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).Struct.fields.len);
3552 const captures_len = if (small.has_captures_len) captures_len: {
3553 const captures_len = zir.extra[extra_index];
3554 extra_index += 1;
3555 break :captures_len captures_len;
3556 } else 0;
35053557 extra_index += @intFromBool(small.has_fields_len);
35063558 const decls_len = if (small.has_decls_len) decls_len: {
35073559 const decls_len = zir.extra[extra_index];
......@@ -3509,6 +3561,8 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35093561 break :decls_len decls_len;
35103562 } else 0;
35113563
3564 extra_index += captures_len;
3565
35123566 if (small.has_backing_int) {
35133567 const backing_int_body_len = zir.extra[extra_index];
35143568 extra_index += 1; // backing_int_body_len
......@@ -3529,6 +3583,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35293583 const small: Inst.EnumDecl.Small = @bitCast(extended.small);
35303584 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).Struct.fields.len);
35313585 extra_index += @intFromBool(small.has_tag_type);
3586 const captures_len = if (small.has_captures_len) captures_len: {
3587 const captures_len = zir.extra[extra_index];
3588 extra_index += 1;
3589 break :captures_len captures_len;
3590 } else 0;
35323591 extra_index += @intFromBool(small.has_body_len);
35333592 extra_index += @intFromBool(small.has_fields_len);
35343593 const decls_len = if (small.has_decls_len) decls_len: {
......@@ -3537,6 +3596,8 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35373596 break :decls_len decls_len;
35383597 } else 0;
35393598
3599 extra_index += captures_len;
3600
35403601 return .{
35413602 .extra_index = extra_index,
35423603 .decls_remaining = decls_len,
......@@ -3547,6 +3608,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35473608 const small: Inst.UnionDecl.Small = @bitCast(extended.small);
35483609 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).Struct.fields.len);
35493610 extra_index += @intFromBool(small.has_tag_type);
3611 const captures_len = if (small.has_captures_len) captures_len: {
3612 const captures_len = zir.extra[extra_index];
3613 extra_index += 1;
3614 break :captures_len captures_len;
3615 } else 0;
35503616 extra_index += @intFromBool(small.has_body_len);
35513617 extra_index += @intFromBool(small.has_fields_len);
35523618 const decls_len = if (small.has_decls_len) decls_len: {
......@@ -3555,6 +3621,8 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35553621 break :decls_len decls_len;
35563622 } else 0;
35573623
3624 extra_index += captures_len;
3625
35583626 return .{
35593627 .extra_index = extra_index,
35603628 .decls_remaining = decls_len,
......@@ -3569,6 +3637,13 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35693637 extra_index += 1;
35703638 break :decls_len decls_len;
35713639 } else 0;
3640 const captures_len = if (small.has_captures_len) captures_len: {
3641 const captures_len = zir.extra[extra_index];
3642 extra_index += 1;
3643 break :captures_len captures_len;
3644 } else 0;
3645
3646 extra_index += captures_len;
35723647
35733648 return .{
35743649 .extra_index = extra_index,
src/Autodoc.zig+72-24
......@@ -450,7 +450,7 @@ const Scope = struct {
450450 Zir.NullTerminatedString, // index into the current file's string table (decl name)
451451 *DeclStatus,
452452 ) = .{},
453
453 captures: []const Zir.Inst.Capture = &.{},
454454 enclosing_type: ?usize, // index into `types`, null = file top-level struct
455455
456456 pub const DeclStatus = union(enum) {
......@@ -459,6 +459,24 @@ const Scope = struct {
459459 NotRequested: u32, // instr_index
460460 };
461461
462 fn getCapture(scope: Scope, idx: u16) struct {
463 union(enum) { inst: Zir.Inst.Index, decl: Zir.NullTerminatedString },
464 *Scope,
465 } {
466 const parent = scope.parent.?;
467 return switch (scope.captures[idx].unwrap()) {
468 .nested => |parent_idx| parent.getCapture(parent_idx),
469 .instruction => |inst| .{
470 .{ .inst = inst },
471 parent,
472 },
473 .decl_val, .decl_ref => |str| .{
474 .{ .decl = str },
475 parent,
476 },
477 };
478 }
479
462480 /// Returns a pointer so that the caller has a chance to modify the value
463481 /// in case they decide to start analyzing a previously not requested decl.
464482 /// Another reason is that in some places we use the pointer to uniquely
......@@ -1151,29 +1169,6 @@ fn walkInstruction(
11511169 .expr = .{ .comptimeExpr = 0 },
11521170 };
11531171 },
1154 .closure_get => {
1155 const inst_node = data[@intFromEnum(inst)].inst_node;
1156
1157 const code = try self.getBlockSource(file, parent_src, inst_node.src_node);
1158 const idx = self.comptime_exprs.items.len;
1159 try self.exprs.append(self.arena, .{ .comptimeExpr = idx });
1160 try self.comptime_exprs.append(self.arena, .{ .code = code });
1161
1162 return DocData.WalkResult{
1163 .expr = .{ .comptimeExpr = idx },
1164 };
1165 },
1166 .closure_capture => {
1167 const un_tok = data[@intFromEnum(inst)].un_tok;
1168 return try self.walkRef(
1169 file,
1170 parent_scope,
1171 parent_src,
1172 un_tok.operand,
1173 need_type,
1174 call_ctx,
1175 );
1176 },
11771172 .str => {
11781173 const str = data[@intFromEnum(inst)].str.get(file.zir);
11791174
......@@ -3395,11 +3390,23 @@ fn walkInstruction(
33953390 .enclosing_type = type_slot_index,
33963391 };
33973392
3393 const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
33983394 const extra = file.zir.extraData(Zir.Inst.OpaqueDecl, extended.operand);
33993395 var extra_index: usize = extra.end;
34003396
34013397 const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
34023398
3399 const captures_len = if (small.has_captures_len) blk: {
3400 const captures_len = file.zir.extra[extra_index];
3401 extra_index += 1;
3402 break :blk captures_len;
3403 } else 0;
3404
3405 if (small.has_decls_len) extra_index += 1;
3406
3407 scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
3408 extra_index += captures_len;
3409
34033410 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
34043411 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
34053412
......@@ -3503,6 +3510,12 @@ fn walkInstruction(
35033510 break :blk tag_ref;
35043511 } else null;
35053512
3513 const captures_len = if (small.has_captures_len) blk: {
3514 const captures_len = file.zir.extra[extra_index];
3515 extra_index += 1;
3516 break :blk captures_len;
3517 } else 0;
3518
35063519 const body_len = if (small.has_body_len) blk: {
35073520 const body_len = file.zir.extra[extra_index];
35083521 extra_index += 1;
......@@ -3520,6 +3533,11 @@ fn walkInstruction(
35203533 else => .{ .enumLiteral = @tagName(small.layout) },
35213534 };
35223535
3536 if (small.has_decls_len) extra_index += 1;
3537
3538 scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
3539 extra_index += captures_len;
3540
35233541 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
35243542 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
35253543
......@@ -3631,6 +3649,12 @@ fn walkInstruction(
36313649 break :blk wr.expr;
36323650 } else null;
36333651
3652 const captures_len = if (small.has_captures_len) blk: {
3653 const captures_len = file.zir.extra[extra_index];
3654 extra_index += 1;
3655 break :blk captures_len;
3656 } else 0;
3657
36343658 const body_len = if (small.has_body_len) blk: {
36353659 const body_len = file.zir.extra[extra_index];
36363660 extra_index += 1;
......@@ -3643,6 +3667,11 @@ fn walkInstruction(
36433667 break :blk fields_len;
36443668 } else 0;
36453669
3670 if (small.has_decls_len) extra_index += 1;
3671
3672 scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
3673 extra_index += captures_len;
3674
36463675 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
36473676 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
36483677
......@@ -3759,6 +3788,12 @@ fn walkInstruction(
37593788
37603789 const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
37613790
3791 const captures_len = if (small.has_captures_len) blk: {
3792 const captures_len = file.zir.extra[extra_index];
3793 extra_index += 1;
3794 break :blk captures_len;
3795 } else 0;
3796
37623797 const fields_len = if (small.has_fields_len) blk: {
37633798 const fields_len = file.zir.extra[extra_index];
37643799 extra_index += 1;
......@@ -3768,6 +3803,9 @@ fn walkInstruction(
37683803 // We don't care about decls yet
37693804 if (small.has_decls_len) extra_index += 1;
37703805
3806 scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
3807 extra_index += captures_len;
3808
37713809 var backing_int: ?DocData.Expr = null;
37723810 if (small.has_backing_int) {
37733811 const backing_int_body_len = file.zir.extra[extra_index];
......@@ -4018,6 +4056,16 @@ fn walkInstruction(
40184056 .expr = .{ .cmpxchgIndex = cmpxchg_index },
40194057 };
40204058 },
4059 .closure_get => {
4060 const captured, const scope = parent_scope.getCapture(extended.small);
4061 switch (captured) {
4062 .inst => |cap_inst| return self.walkInstruction(file, scope, parent_src, cap_inst, need_type, call_ctx),
4063 .decl => |str| {
4064 const decl_status = parent_scope.resolveDeclName(str, file, inst.toOptional());
4065 return .{ .expr = .{ .declRef = decl_status } };
4066 },
4067 }
4068 },
40214069 }
40224070 },
40234071 }
src/Builtin.zig+2
......@@ -264,6 +264,8 @@ pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void {
264264 assert(!file.zir.hasCompileErrors()); // builtin.zig must not have astgen errors
265265 file.zir_loaded = true;
266266 file.status = .success_zir;
267 // Note that whilst we set `zir_loaded` here, we populated `path_digest`
268 // all the way back in `Package.Module.create`.
267269}
268270
269271fn writeFile(file: *File, mod: *Module) !void {
src/Compilation.zig+4
......@@ -1326,6 +1326,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
13261326 .global = options.config,
13271327 .parent = options.root_mod,
13281328 .builtin_mod = options.root_mod.getBuiltinDependency(),
1329 .builtin_modules = null, // `builtin_mod` is set
13291330 });
13301331 try options.root_mod.deps.putNoClobber(arena, "compiler_rt", compiler_rt_mod);
13311332 }
......@@ -1430,6 +1431,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
14301431 .global = options.config,
14311432 .parent = options.root_mod,
14321433 .builtin_mod = options.root_mod.getBuiltinDependency(),
1434 .builtin_modules = null, // `builtin_mod` is set
14331435 });
14341436
14351437 const zcu = try arena.create(Module);
......@@ -6107,6 +6109,7 @@ fn buildOutputFromZig(
61076109 .cc_argv = &.{},
61086110 .parent = null,
61096111 .builtin_mod = null,
6112 .builtin_modules = null, // there is only one module in this compilation
61106113 });
61116114 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
61126115 const target = comp.getTarget();
......@@ -6219,6 +6222,7 @@ pub fn build_crt_file(
62196222 .cc_argv = &.{},
62206223 .parent = null,
62216224 .builtin_mod = null,
6225 .builtin_modules = null, // there is only one module in this compilation
62226226 });
62236227
62246228 for (c_source_files) |*item| {
src/InternPool.zig+1781-1219
......@@ -1,7 +1,6 @@
11//! All interned objects have both a value and a type.
22//! This data structure is self-contained, with the following exceptions:
33//! * Module.Namespace has a pointer to Module.File
4//! * Module.Decl has a pointer to Module.CaptureScope
54
65/// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are
76/// constructed lazily.
......@@ -345,6 +344,7 @@ const KeyAdapter = struct {
345344
346345 pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool {
347346 _ = b_void;
347 if (ctx.intern_pool.items.items(.tag)[b_map_index] == .removed) return false;
348348 return ctx.intern_pool.indexToKey(@as(Index, @enumFromInt(b_map_index))).eql(a, ctx.intern_pool);
349349 }
350350
......@@ -502,6 +502,51 @@ pub const OptionalNullTerminatedString = enum(u32) {
502502 }
503503};
504504
505/// A single value captured in the closure of a namespace type. This is not a plain
506/// `Index` because we must differentiate between the following cases:
507/// * runtime-known value (where we store the type)
508/// * comptime-known value (where we store the value)
509/// * decl val (so that we can analyze the value lazily)
510/// * decl ref (so that we can analyze the reference lazily)
511pub const CaptureValue = packed struct(u32) {
512 tag: enum { @"comptime", runtime, decl_val, decl_ref },
513 idx: u30,
514
515 pub fn wrap(val: Unwrapped) CaptureValue {
516 return switch (val) {
517 .@"comptime" => |i| .{ .tag = .@"comptime", .idx = @intCast(@intFromEnum(i)) },
518 .runtime => |i| .{ .tag = .runtime, .idx = @intCast(@intFromEnum(i)) },
519 .decl_val => |i| .{ .tag = .decl_val, .idx = @intCast(@intFromEnum(i)) },
520 .decl_ref => |i| .{ .tag = .decl_ref, .idx = @intCast(@intFromEnum(i)) },
521 };
522 }
523 pub fn unwrap(val: CaptureValue) Unwrapped {
524 return switch (val.tag) {
525 .@"comptime" => .{ .@"comptime" = @enumFromInt(val.idx) },
526 .runtime => .{ .runtime = @enumFromInt(val.idx) },
527 .decl_val => .{ .decl_val = @enumFromInt(val.idx) },
528 .decl_ref => .{ .decl_ref = @enumFromInt(val.idx) },
529 };
530 }
531
532 pub const Unwrapped = union(enum) {
533 /// Index refers to the value.
534 @"comptime": Index,
535 /// Index refers to the type.
536 runtime: Index,
537 decl_val: DeclIndex,
538 decl_ref: DeclIndex,
539 };
540
541 pub const Slice = struct {
542 start: u32,
543 len: u32,
544 pub fn get(slice: Slice, ip: *const InternPool) []CaptureValue {
545 return @ptrCast(ip.extra.items[slice.start..][0..slice.len]);
546 }
547 };
548};
549
505550pub const Key = union(enum) {
506551 int_type: IntType,
507552 ptr_type: PtrType,
......@@ -516,14 +561,14 @@ pub const Key = union(enum) {
516561 /// This represents a struct that has been explicitly declared in source code,
517562 /// or was created with `@Type`. It is unique and based on a declaration.
518563 /// It may be a tuple, if declared like this: `struct {A, B, C}`.
519 struct_type: StructType,
564 struct_type: NamespaceType,
520565 /// This is an anonymous struct or tuple type which has no corresponding
521566 /// declaration. It is used for types that have no `struct` keyword in the
522567 /// source code, and were not created via `@Type`.
523568 anon_struct_type: AnonStructType,
524 union_type: Key.UnionType,
525 opaque_type: OpaqueType,
526 enum_type: EnumType,
569 union_type: NamespaceType,
570 opaque_type: NamespaceType,
571 enum_type: NamespaceType,
527572 func_type: FuncType,
528573 error_set_type: ErrorSetType,
529574 /// The payload is the function body, either a `func_decl` or `func_instance`.
......@@ -645,348 +690,6 @@ pub const Key = union(enum) {
645690 child: Index,
646691 };
647692
648 pub const OpaqueType = extern struct {
649 /// The Decl that corresponds to the opaque itself.
650 decl: DeclIndex,
651 /// Represents the declarations inside this opaque.
652 namespace: NamespaceIndex,
653 zir_index: TrackedInst.Index.Optional,
654 };
655
656 /// Although packed structs and non-packed structs are encoded differently,
657 /// this struct is used for both categories since they share some common
658 /// functionality.
659 pub const StructType = struct {
660 extra_index: u32,
661 /// `none` when the struct is `@TypeOf(.{})`.
662 decl: OptionalDeclIndex,
663 /// `none` when the struct has no declarations.
664 namespace: OptionalNamespaceIndex,
665 /// Index of the struct_decl ZIR instruction.
666 zir_index: TrackedInst.Index.Optional,
667 layout: std.builtin.Type.ContainerLayout,
668 field_names: NullTerminatedString.Slice,
669 field_types: Index.Slice,
670 field_inits: Index.Slice,
671 field_aligns: Alignment.Slice,
672 runtime_order: RuntimeOrder.Slice,
673 comptime_bits: ComptimeBits,
674 offsets: Offsets,
675 names_map: OptionalMapIndex,
676
677 pub const ComptimeBits = struct {
678 start: u32,
679 /// This is the number of u32 elements, not the number of struct fields.
680 len: u32,
681
682 pub fn get(this: @This(), ip: *const InternPool) []u32 {
683 return ip.extra.items[this.start..][0..this.len];
684 }
685
686 pub fn getBit(this: @This(), ip: *const InternPool, i: usize) bool {
687 if (this.len == 0) return false;
688 return @as(u1, @truncate(this.get(ip)[i / 32] >> @intCast(i % 32))) != 0;
689 }
690
691 pub fn setBit(this: @This(), ip: *const InternPool, i: usize) void {
692 this.get(ip)[i / 32] |= @as(u32, 1) << @intCast(i % 32);
693 }
694
695 pub fn clearBit(this: @This(), ip: *const InternPool, i: usize) void {
696 this.get(ip)[i / 32] &= ~(@as(u32, 1) << @intCast(i % 32));
697 }
698 };
699
700 pub const Offsets = struct {
701 start: u32,
702 len: u32,
703
704 pub fn get(this: @This(), ip: *const InternPool) []u32 {
705 return @ptrCast(ip.extra.items[this.start..][0..this.len]);
706 }
707 };
708
709 pub const RuntimeOrder = enum(u32) {
710 /// Placeholder until layout is resolved.
711 unresolved = std.math.maxInt(u32) - 0,
712 /// Field not present at runtime
713 omitted = std.math.maxInt(u32) - 1,
714 _,
715
716 pub const Slice = struct {
717 start: u32,
718 len: u32,
719
720 pub fn get(slice: RuntimeOrder.Slice, ip: *const InternPool) []RuntimeOrder {
721 return @ptrCast(ip.extra.items[slice.start..][0..slice.len]);
722 }
723 };
724
725 pub fn toInt(i: @This()) ?u32 {
726 return switch (i) {
727 .omitted => null,
728 .unresolved => unreachable,
729 else => @intFromEnum(i),
730 };
731 }
732 };
733
734 /// Look up field index based on field name.
735 pub fn nameIndex(self: StructType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
736 const names_map = self.names_map.unwrap() orelse {
737 const i = name.toUnsigned(ip) orelse return null;
738 if (i >= self.field_types.len) return null;
739 return i;
740 };
741 const map = &ip.maps.items[@intFromEnum(names_map)];
742 const adapter: NullTerminatedString.Adapter = .{ .strings = self.field_names.get(ip) };
743 const field_index = map.getIndexAdapted(name, adapter) orelse return null;
744 return @intCast(field_index);
745 }
746
747 /// Returns the already-existing field with the same name, if any.
748 pub fn addFieldName(
749 self: @This(),
750 ip: *InternPool,
751 name: NullTerminatedString,
752 ) ?u32 {
753 return ip.addFieldName(self.names_map.unwrap().?, self.field_names.start, name);
754 }
755
756 pub fn fieldAlign(s: @This(), ip: *const InternPool, i: usize) Alignment {
757 if (s.field_aligns.len == 0) return .none;
758 return s.field_aligns.get(ip)[i];
759 }
760
761 pub fn fieldInit(s: @This(), ip: *const InternPool, i: usize) Index {
762 if (s.field_inits.len == 0) return .none;
763 assert(s.haveFieldInits(ip));
764 return s.field_inits.get(ip)[i];
765 }
766
767 /// Returns `none` in the case the struct is a tuple.
768 pub fn fieldName(s: @This(), ip: *const InternPool, i: usize) OptionalNullTerminatedString {
769 if (s.field_names.len == 0) return .none;
770 return s.field_names.get(ip)[i].toOptional();
771 }
772
773 pub fn fieldIsComptime(s: @This(), ip: *const InternPool, i: usize) bool {
774 return s.comptime_bits.getBit(ip, i);
775 }
776
777 pub fn setFieldComptime(s: @This(), ip: *InternPool, i: usize) void {
778 s.comptime_bits.setBit(ip, i);
779 }
780
781 /// Reads the non-opv flag calculated during AstGen. Used to short-circuit more
782 /// complicated logic.
783 pub fn knownNonOpv(s: @This(), ip: *InternPool) bool {
784 return switch (s.layout) {
785 .Packed => false,
786 .Auto, .Extern => s.flagsPtr(ip).known_non_opv,
787 };
788 }
789
790 /// The returned pointer expires with any addition to the `InternPool`.
791 /// Asserts the struct is not packed.
792 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeStruct.Flags {
793 assert(self.layout != .Packed);
794 const flags_field_index = std.meta.fieldIndex(Tag.TypeStruct, "flags").?;
795 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
796 }
797
798 /// The returned pointer expires with any addition to the `InternPool`.
799 /// Asserts that the struct is packed.
800 pub fn packedFlagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeStructPacked.Flags {
801 assert(self.layout == .Packed);
802 const flags_field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?;
803 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
804 }
805
806 pub fn assumeRuntimeBitsIfFieldTypesWip(s: @This(), ip: *InternPool) bool {
807 if (s.layout == .Packed) return false;
808 const flags_ptr = s.flagsPtr(ip);
809 if (flags_ptr.field_types_wip) {
810 flags_ptr.assumed_runtime_bits = true;
811 return true;
812 }
813 return false;
814 }
815
816 pub fn setTypesWip(s: @This(), ip: *InternPool) bool {
817 if (s.layout == .Packed) return false;
818 const flags_ptr = s.flagsPtr(ip);
819 if (flags_ptr.field_types_wip) return true;
820 flags_ptr.field_types_wip = true;
821 return false;
822 }
823
824 pub fn clearTypesWip(s: @This(), ip: *InternPool) void {
825 if (s.layout == .Packed) return;
826 s.flagsPtr(ip).field_types_wip = false;
827 }
828
829 pub fn setLayoutWip(s: @This(), ip: *InternPool) bool {
830 if (s.layout == .Packed) return false;
831 const flags_ptr = s.flagsPtr(ip);
832 if (flags_ptr.layout_wip) return true;
833 flags_ptr.layout_wip = true;
834 return false;
835 }
836
837 pub fn clearLayoutWip(s: @This(), ip: *InternPool) void {
838 if (s.layout == .Packed) return;
839 s.flagsPtr(ip).layout_wip = false;
840 }
841
842 pub fn setAlignmentWip(s: @This(), ip: *InternPool) bool {
843 if (s.layout == .Packed) return false;
844 const flags_ptr = s.flagsPtr(ip);
845 if (flags_ptr.alignment_wip) return true;
846 flags_ptr.alignment_wip = true;
847 return false;
848 }
849
850 pub fn clearAlignmentWip(s: @This(), ip: *InternPool) void {
851 if (s.layout == .Packed) return;
852 s.flagsPtr(ip).alignment_wip = false;
853 }
854
855 pub fn setInitsWip(s: @This(), ip: *InternPool) bool {
856 switch (s.layout) {
857 .Packed => {
858 const flag = &s.packedFlagsPtr(ip).field_inits_wip;
859 if (flag.*) return true;
860 flag.* = true;
861 return false;
862 },
863 .Auto, .Extern => {
864 const flag = &s.flagsPtr(ip).field_inits_wip;
865 if (flag.*) return true;
866 flag.* = true;
867 return false;
868 },
869 }
870 }
871
872 pub fn clearInitsWip(s: @This(), ip: *InternPool) void {
873 switch (s.layout) {
874 .Packed => s.packedFlagsPtr(ip).field_inits_wip = false,
875 .Auto, .Extern => s.flagsPtr(ip).field_inits_wip = false,
876 }
877 }
878
879 pub fn setFullyResolved(s: @This(), ip: *InternPool) bool {
880 if (s.layout == .Packed) return true;
881 const flags_ptr = s.flagsPtr(ip);
882 if (flags_ptr.fully_resolved) return true;
883 flags_ptr.fully_resolved = true;
884 return false;
885 }
886
887 pub fn clearFullyResolved(s: @This(), ip: *InternPool) void {
888 s.flagsPtr(ip).fully_resolved = false;
889 }
890
891 /// The returned pointer expires with any addition to the `InternPool`.
892 /// Asserts the struct is not packed.
893 pub fn size(self: @This(), ip: *InternPool) *u32 {
894 assert(self.layout != .Packed);
895 const size_field_index = std.meta.fieldIndex(Tag.TypeStruct, "size").?;
896 return @ptrCast(&ip.extra.items[self.extra_index + size_field_index]);
897 }
898
899 /// The backing integer type of the packed struct. Whether zig chooses
900 /// this type or the user specifies it, it is stored here. This will be
901 /// set to `none` until the layout is resolved.
902 /// Asserts the struct is packed.
903 pub fn backingIntType(s: @This(), ip: *const InternPool) *Index {
904 assert(s.layout == .Packed);
905 const field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_ty").?;
906 return @ptrCast(&ip.extra.items[s.extra_index + field_index]);
907 }
908
909 /// Asserts the struct is not packed.
910 pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
911 assert(s.layout != .Packed);
912 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;
913 ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);
914 }
915
916 pub fn haveFieldTypes(s: @This(), ip: *const InternPool) bool {
917 const types = s.field_types.get(ip);
918 return types.len == 0 or types[0] != .none;
919 }
920
921 pub fn haveFieldInits(s: @This(), ip: *const InternPool) bool {
922 return switch (s.layout) {
923 .Packed => s.packedFlagsPtr(ip).inits_resolved,
924 .Auto, .Extern => s.flagsPtr(ip).inits_resolved,
925 };
926 }
927
928 pub fn setHaveFieldInits(s: @This(), ip: *InternPool) void {
929 switch (s.layout) {
930 .Packed => s.packedFlagsPtr(ip).inits_resolved = true,
931 .Auto, .Extern => s.flagsPtr(ip).inits_resolved = true,
932 }
933 }
934
935 pub fn haveLayout(s: @This(), ip: *InternPool) bool {
936 return switch (s.layout) {
937 .Packed => s.backingIntType(ip).* != .none,
938 .Auto, .Extern => s.flagsPtr(ip).layout_resolved,
939 };
940 }
941
942 pub fn isTuple(s: @This(), ip: *InternPool) bool {
943 return s.layout != .Packed and s.flagsPtr(ip).is_tuple;
944 }
945
946 pub fn hasReorderedFields(s: @This()) bool {
947 return s.layout == .Auto;
948 }
949
950 pub const RuntimeOrderIterator = struct {
951 ip: *InternPool,
952 field_index: u32,
953 struct_type: InternPool.Key.StructType,
954
955 pub fn next(it: *@This()) ?u32 {
956 var i = it.field_index;
957
958 if (i >= it.struct_type.field_types.len)
959 return null;
960
961 if (it.struct_type.hasReorderedFields()) {
962 it.field_index += 1;
963 return it.struct_type.runtime_order.get(it.ip)[i].toInt();
964 }
965
966 while (it.struct_type.fieldIsComptime(it.ip, i)) {
967 i += 1;
968 if (i >= it.struct_type.field_types.len)
969 return null;
970 }
971
972 it.field_index = i + 1;
973 return i;
974 }
975 };
976
977 /// Iterates over non-comptime fields in the order they are laid out in memory at runtime.
978 /// May or may not include zero-bit fields.
979 /// Asserts the struct is not packed.
980 pub fn iterateRuntimeOrder(s: @This(), ip: *InternPool) RuntimeOrderIterator {
981 assert(s.layout != .Packed);
982 return .{
983 .ip = ip,
984 .field_index = 0,
985 .struct_type = s,
986 };
987 }
988 };
989
990693 pub const AnonStructType = struct {
991694 types: Index.Slice,
992695 /// This may be empty, indicating this is a tuple.
......@@ -1010,192 +713,41 @@ pub const Key = union(enum) {
1010713 }
1011714 };
1012715
1013 /// Serves two purposes:
1014 /// * Being the key in the InternPool hash map, which only requires the `decl` field.
1015 /// * Provide the other fields that do not require chasing the enum type.
1016 pub const UnionType = struct {
1017 /// The Decl that corresponds to the union itself.
1018 decl: DeclIndex,
1019 /// The index of the `Tag.TypeUnion` payload. Ignored by `get`,
1020 /// populated by `indexToKey`.
1021 extra_index: u32,
1022 namespace: NamespaceIndex,
1023 flags: Tag.TypeUnion.Flags,
1024 /// The enum that provides the list of field names and values.
1025 enum_tag_ty: Index,
1026 zir_index: TrackedInst.Index.Optional,
1027
1028 /// The returned pointer expires with any addition to the `InternPool`.
1029 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeUnion.Flags {
1030 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
1031 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
1032 }
1033
1034 /// The returned pointer expires with any addition to the `InternPool`.
1035 pub fn size(self: @This(), ip: *InternPool) *u32 {
1036 const size_field_index = std.meta.fieldIndex(Tag.TypeUnion, "size").?;
1037 return &ip.extra.items[self.extra_index + size_field_index];
1038 }
1039
1040 /// The returned pointer expires with any addition to the `InternPool`.
1041 pub fn padding(self: @This(), ip: *InternPool) *u32 {
1042 const padding_field_index = std.meta.fieldIndex(Tag.TypeUnion, "padding").?;
1043 return &ip.extra.items[self.extra_index + padding_field_index];
1044 }
1045
1046 pub fn haveFieldTypes(self: @This(), ip: *const InternPool) bool {
1047 return self.flagsPtr(ip).status.haveFieldTypes();
1048 }
1049
1050 pub fn hasTag(self: @This(), ip: *const InternPool) bool {
1051 return self.flagsPtr(ip).runtime_tag.hasTag();
1052 }
1053
1054 pub fn getLayout(self: @This(), ip: *const InternPool) std.builtin.Type.ContainerLayout {
1055 return self.flagsPtr(ip).layout;
1056 }
1057
1058 pub fn haveLayout(self: @This(), ip: *const InternPool) bool {
1059 return self.flagsPtr(ip).status.haveLayout();
1060 }
1061
1062 /// Pointer to an enum type which is used for the tag of the union.
1063 /// This type is created even for untagged unions, even when the memory
1064 /// layout does not store the tag.
1065 /// Whether zig chooses this type or the user specifies it, it is stored here.
1066 /// This will be set to the null type until status is `have_field_types`.
1067 /// This accessor is provided so that the tag type can be mutated, and so that
1068 /// when it is mutated, the mutations are observed.
1069 /// The returned pointer is invalidated when something is added to the `InternPool`.
1070 pub fn tagTypePtr(self: @This(), ip: *const InternPool) *Index {
1071 const tag_ty_field_index = std.meta.fieldIndex(Tag.TypeUnion, "tag_ty").?;
1072 return @ptrCast(&ip.extra.items[self.extra_index + tag_ty_field_index]);
1073 }
1074
1075 pub fn setFieldTypes(self: @This(), ip: *InternPool, types: []const Index) void {
1076 @memcpy((Index.Slice{
1077 .start = @intCast(self.extra_index + @typeInfo(Tag.TypeUnion).Struct.fields.len),
1078 .len = @intCast(types.len),
1079 }).get(ip), types);
1080 }
1081
1082 pub fn setFieldAligns(self: @This(), ip: *InternPool, aligns: []const Alignment) void {
1083 if (aligns.len == 0) return;
1084 assert(self.flagsPtr(ip).any_aligned_fields);
1085 @memcpy((Alignment.Slice{
1086 .start = @intCast(
1087 self.extra_index + @typeInfo(Tag.TypeUnion).Struct.fields.len + aligns.len,
1088 ),
1089 .len = @intCast(aligns.len),
1090 }).get(ip), aligns);
1091 }
1092 };
1093
1094 pub const EnumType = struct {
1095 /// The Decl that corresponds to the enum itself.
1096 decl: DeclIndex,
1097 /// Represents the declarations inside this enum.
1098 namespace: OptionalNamespaceIndex,
1099 /// An integer type which is used for the numerical value of the enum.
1100 /// This field is present regardless of whether the enum has an
1101 /// explicitly provided tag type or auto-numbered.
1102 tag_ty: Index,
1103 /// Set of field names in declaration order.
1104 names: NullTerminatedString.Slice,
1105 /// Maps integer tag value to field index.
1106 /// Entries are in declaration order, same as `fields`.
1107 /// If this is empty, it means the enum tags are auto-numbered.
1108 values: Index.Slice,
1109 tag_mode: TagMode,
1110 /// This is ignored by `get` but will always be provided by `indexToKey`.
1111 names_map: OptionalMapIndex = .none,
1112 /// This is ignored by `get` but will be provided by `indexToKey` when
1113 /// a value map exists.
1114 values_map: OptionalMapIndex = .none,
1115 zir_index: TrackedInst.Index.Optional,
1116
1117 pub const TagMode = enum {
1118 /// The integer tag type was auto-numbered by zig.
1119 auto,
1120 /// The integer tag type was provided by the enum declaration, and the enum
1121 /// is exhaustive.
1122 explicit,
1123 /// The integer tag type was provided by the enum declaration, and the enum
1124 /// is non-exhaustive.
1125 nonexhaustive,
1126 };
1127
1128 /// Look up field index based on field name.
1129 pub fn nameIndex(self: EnumType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
1130 const map = &ip.maps.items[@intFromEnum(self.names_map.unwrap().?)];
1131 const adapter: NullTerminatedString.Adapter = .{ .strings = self.names.get(ip) };
1132 const field_index = map.getIndexAdapted(name, adapter) orelse return null;
1133 return @intCast(field_index);
1134 }
1135
1136 /// Look up field index based on tag value.
1137 /// Asserts that `values_map` is not `none`.
1138 /// This function returns `null` when `tag_val` does not have the
1139 /// integer tag type of the enum.
1140 pub fn tagValueIndex(self: EnumType, ip: *const InternPool, tag_val: Index) ?u32 {
1141 assert(tag_val != .none);
1142 // TODO: we should probably decide a single interface for this function, but currently
1143 // it's being called with both tag values and underlying ints. Fix this!
1144 const int_tag_val = switch (ip.indexToKey(tag_val)) {
1145 .enum_tag => |enum_tag| enum_tag.int,
1146 .int => tag_val,
1147 else => unreachable,
1148 };
1149 if (self.values_map.unwrap()) |values_map| {
1150 const map = &ip.maps.items[@intFromEnum(values_map)];
1151 const adapter: Index.Adapter = .{ .indexes = self.values.get(ip) };
1152 const field_index = map.getIndexAdapted(int_tag_val, adapter) orelse return null;
1153 return @intCast(field_index);
1154 }
1155 // Auto-numbered enum. Convert `int_tag_val` to field index.
1156 const field_index = switch (ip.indexToKey(int_tag_val).int.storage) {
1157 inline .u64, .i64 => |x| std.math.cast(u32, x) orelse return null,
1158 .big_int => |x| x.to(u32) catch return null,
1159 .lazy_align, .lazy_size => unreachable,
1160 };
1161 return if (field_index < self.names.len) field_index else null;
1162 }
1163 };
1164
1165 pub const IncompleteEnumType = struct {
1166 /// Same as corresponding `EnumType` field.
1167 decl: DeclIndex,
1168 /// Same as corresponding `EnumType` field.
1169 namespace: OptionalNamespaceIndex,
1170 /// The field names and field values are not known yet, but
1171 /// the number of fields must be known ahead of time.
1172 fields_len: u32,
1173 /// This information is needed so that the size does not change
1174 /// later when populating field values.
1175 has_values: bool,
1176 /// Same as corresponding `EnumType` field.
1177 tag_mode: EnumType.TagMode,
1178 /// This may be updated via `setTagType` later.
1179 tag_ty: Index = .none,
1180 zir_index: TrackedInst.Index.Optional,
1181
1182 pub fn toEnumType(self: @This()) EnumType {
1183 return .{
1184 .decl = self.decl,
1185 .namespace = self.namespace,
1186 .tag_ty = self.tag_ty,
1187 .tag_mode = self.tag_mode,
1188 .names = .{ .start = 0, .len = 0 },
1189 .values = .{ .start = 0, .len = 0 },
1190 .zir_index = self.zir_index,
1191 };
1192 }
1193
1194 /// Only the decl is used for hashing and equality, so we can construct
1195 /// this minimal key for use with `map`.
1196 pub fn toKey(self: @This()) Key {
1197 return .{ .enum_type = self.toEnumType() };
1198 }
716 /// This is the hashmap key. To fetch other data associated with the type, see:
717 /// * `loadStructType`
718 /// * `loadUnionType`
719 /// * `loadEnumType`
720 /// * `loadOpaqueType`
721 pub const NamespaceType = union(enum) {
722 /// This type corresponds to an actual source declaration, e.g. `struct { ... }`.
723 /// It is hashed based on its ZIR instruction index and set of captures.
724 declared: struct {
725 /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction.
726 zir_index: TrackedInst.Index,
727 /// The captured values of this type. These values must be fully resolved per the language spec.
728 captures: union(enum) {
729 owned: CaptureValue.Slice,
730 external: []const CaptureValue,
731 },
732 },
733 /// This type is an automatically-generated enum tag type for a union.
734 /// It is hashed based on the index of the union type it corresponds to.
735 generated_tag: struct {
736 /// The union for which this is a tag type.
737 union_type: Index,
738 },
739 /// This type originates from a reification via `@Type`.
740 /// It is hased based on its ZIR instruction index and fields, attributes, etc.
741 /// To avoid making this key overly complex, the type-specific data is hased by Sema.
742 reified: struct {
743 /// A `reify` instruction.
744 zir_index: TrackedInst.Index,
745 /// A hash of this type's attributes, fields, etc, generated by Sema.
746 type_hash: u64,
747 },
748 /// This type is `@TypeOf(.{})`.
749 /// TODO: can we change the language spec to not special-case this type?
750 empty_struct: void,
1199751 };
1200752
1201753 pub const FuncType = struct {
......@@ -1546,12 +1098,37 @@ pub const Key = union(enum) {
15461098 .payload => |y| Hash.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)),
15471099 },
15481100
1549 inline .opaque_type,
1101 .variable => |variable| Hash.hash(seed, asBytes(&variable.decl)),
1102
1103 .opaque_type,
15501104 .enum_type,
1551 .variable,
15521105 .union_type,
15531106 .struct_type,
1554 => |x| Hash.hash(seed, asBytes(&x.decl)),
1107 => |namespace_type| {
1108 var hasher = Hash.init(seed);
1109 std.hash.autoHash(&hasher, std.meta.activeTag(namespace_type));
1110 switch (namespace_type) {
1111 .declared => |declared| {
1112 std.hash.autoHash(&hasher, declared.zir_index);
1113 const captures = switch (declared.captures) {
1114 .owned => |cvs| cvs.get(ip),
1115 .external => |cvs| cvs,
1116 };
1117 for (captures) |cv| {
1118 std.hash.autoHash(&hasher, cv);
1119 }
1120 },
1121 .generated_tag => |generated_tag| {
1122 std.hash.autoHash(&hasher, generated_tag.union_type);
1123 },
1124 .reified => |reified| {
1125 std.hash.autoHash(&hasher, reified.zir_index);
1126 std.hash.autoHash(&hasher, reified.type_hash);
1127 },
1128 .empty_struct => {},
1129 }
1130 return hasher.final();
1131 },
15551132
15561133 .int => |int| {
15571134 var hasher = Hash.init(seed);
......@@ -1956,21 +1533,31 @@ pub const Key = union(enum) {
19561533 }
19571534 },
19581535
1959 .opaque_type => |a_info| {
1960 const b_info = b.opaque_type;
1961 return a_info.decl == b_info.decl;
1962 },
1963 .enum_type => |a_info| {
1964 const b_info = b.enum_type;
1965 return a_info.decl == b_info.decl;
1966 },
1967 .union_type => |a_info| {
1968 const b_info = b.union_type;
1969 return a_info.decl == b_info.decl;
1970 },
1971 .struct_type => |a_info| {
1972 const b_info = b.struct_type;
1973 return a_info.decl == b_info.decl;
1536 inline .opaque_type, .enum_type, .union_type, .struct_type => |a_info, a_tag_ct| {
1537 const b_info = @field(b, @tagName(a_tag_ct));
1538 if (std.meta.activeTag(a_info) != b_info) return false;
1539 switch (a_info) {
1540 .declared => |a_d| {
1541 const b_d = b_info.declared;
1542 if (a_d.zir_index != b_d.zir_index) return false;
1543 const a_captures = switch (a_d.captures) {
1544 .owned => |s| s.get(ip),
1545 .external => |cvs| cvs,
1546 };
1547 const b_captures = switch (b_d.captures) {
1548 .owned => |s| s.get(ip),
1549 .external => |cvs| cvs,
1550 };
1551 return std.mem.eql(u32, @ptrCast(a_captures), @ptrCast(b_captures));
1552 },
1553 .generated_tag => |a_gt| return a_gt.union_type == b_info.generated_tag.union_type,
1554 .reified => |a_r| {
1555 const b_r = b_info.reified;
1556 return a_r.zir_index == b_r.zir_index and
1557 a_r.type_hash == b_r.type_hash;
1558 },
1559 .empty_struct => return true,
1560 }
19741561 },
19751562 .aggregate => |a_info| {
19761563 const b_info = b.aggregate;
......@@ -2112,21 +1699,15 @@ pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };
21121699// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a
21131700// minimal hashmap key, this type is a convenience type that contains info
21141701// needed by semantic analysis.
2115pub const UnionType = struct {
1702pub const LoadedUnionType = struct {
1703 /// The index of the `Tag.TypeUnion` payload.
1704 extra_index: u32,
21161705 /// The Decl that corresponds to the union itself.
21171706 decl: DeclIndex,
21181707 /// Represents the declarations inside this union.
2119 namespace: NamespaceIndex,
1708 namespace: OptionalNamespaceIndex,
21201709 /// The enum tag type.
21211710 enum_tag_ty: Index,
2122 /// The integer tag type of the enum.
2123 int_tag_ty: Index,
2124 /// ABI size of the union, including padding
2125 size: u64,
2126 /// Trailing padding bytes
2127 padding: u32,
2128 /// List of field names in declaration order.
2129 field_names: NullTerminatedString.Slice,
21301711 /// List of field types in declaration order.
21311712 /// These are `none` until `status` is `have_field_types` or `have_layout`.
21321713 field_types: Index.Slice,
......@@ -2134,12 +1715,9 @@ pub const UnionType = struct {
21341715 /// `none` means the ABI alignment of the type.
21351716 /// If this slice has length 0 it means all elements are `none`.
21361717 field_aligns: Alignment.Slice,
2137 /// Index of the union_decl ZIR instruction.
2138 zir_index: TrackedInst.Index.Optional,
2139 /// Index into extra array of the `flags` field.
2140 flags_index: u32,
2141 /// Copied from `enum_tag_ty`.
2142 names_map: OptionalMapIndex,
1718 /// Index of the union_decl or reify ZIR instruction.
1719 zir_index: TrackedInst.Index,
1720 captures: CaptureValue.Slice,
21431721
21441722 pub const RuntimeTag = enum(u2) {
21451723 none,
......@@ -2154,118 +1732,823 @@ pub const UnionType = struct {
21541732 }
21551733 };
21561734
2157 pub const Status = enum(u3) {
2158 none,
2159 field_types_wip,
2160 have_field_types,
2161 layout_wip,
2162 have_layout,
2163 fully_resolved_wip,
2164 /// The types and all its fields have had their layout resolved.
2165 /// Even through pointer, which `have_layout` does not ensure.
2166 fully_resolved,
1735 pub const Status = enum(u3) {
1736 none,
1737 field_types_wip,
1738 have_field_types,
1739 layout_wip,
1740 have_layout,
1741 fully_resolved_wip,
1742 /// The types and all its fields have had their layout resolved.
1743 /// Even through pointer, which `have_layout` does not ensure.
1744 fully_resolved,
1745
1746 pub fn haveFieldTypes(status: Status) bool {
1747 return switch (status) {
1748 .none,
1749 .field_types_wip,
1750 => false,
1751 .have_field_types,
1752 .layout_wip,
1753 .have_layout,
1754 .fully_resolved_wip,
1755 .fully_resolved,
1756 => true,
1757 };
1758 }
1759
1760 pub fn haveLayout(status: Status) bool {
1761 return switch (status) {
1762 .none,
1763 .field_types_wip,
1764 .have_field_types,
1765 .layout_wip,
1766 => false,
1767 .have_layout,
1768 .fully_resolved_wip,
1769 .fully_resolved,
1770 => true,
1771 };
1772 }
1773 };
1774
1775 pub fn loadTagType(self: LoadedUnionType, ip: *InternPool) LoadedEnumType {
1776 return ip.loadEnumType(self.enum_tag_ty);
1777 }
1778
1779 /// Pointer to an enum type which is used for the tag of the union.
1780 /// This type is created even for untagged unions, even when the memory
1781 /// layout does not store the tag.
1782 /// Whether zig chooses this type or the user specifies it, it is stored here.
1783 /// This will be set to the null type until status is `have_field_types`.
1784 /// This accessor is provided so that the tag type can be mutated, and so that
1785 /// when it is mutated, the mutations are observed.
1786 /// The returned pointer expires with any addition to the `InternPool`.
1787 pub fn tagTypePtr(self: LoadedUnionType, ip: *const InternPool) *Index {
1788 const field_index = std.meta.fieldIndex(Tag.TypeUnion, "tag_ty").?;
1789 return @ptrCast(&ip.extra.items[self.extra_index + field_index]);
1790 }
1791
1792 /// The returned pointer expires with any addition to the `InternPool`.
1793 pub fn flagsPtr(self: LoadedUnionType, ip: *const InternPool) *Tag.TypeUnion.Flags {
1794 const field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
1795 return @ptrCast(&ip.extra.items[self.extra_index + field_index]);
1796 }
1797
1798 /// The returned pointer expires with any addition to the `InternPool`.
1799 pub fn size(self: LoadedUnionType, ip: *const InternPool) *u32 {
1800 const field_index = std.meta.fieldIndex(Tag.TypeUnion, "size").?;
1801 return &ip.extra.items[self.extra_index + field_index];
1802 }
1803
1804 /// The returned pointer expires with any addition to the `InternPool`.
1805 pub fn padding(self: LoadedUnionType, ip: *const InternPool) *u32 {
1806 const field_index = std.meta.fieldIndex(Tag.TypeUnion, "padding").?;
1807 return &ip.extra.items[self.extra_index + field_index];
1808 }
1809
1810 pub fn hasTag(self: LoadedUnionType, ip: *const InternPool) bool {
1811 return self.flagsPtr(ip).runtime_tag.hasTag();
1812 }
1813
1814 pub fn haveFieldTypes(self: LoadedUnionType, ip: *const InternPool) bool {
1815 return self.flagsPtr(ip).status.haveFieldTypes();
1816 }
1817
1818 pub fn haveLayout(self: LoadedUnionType, ip: *const InternPool) bool {
1819 return self.flagsPtr(ip).status.haveLayout();
1820 }
1821
1822 pub fn getLayout(self: LoadedUnionType, ip: *const InternPool) std.builtin.Type.ContainerLayout {
1823 return self.flagsPtr(ip).layout;
1824 }
1825
1826 pub fn fieldAlign(self: LoadedUnionType, ip: *const InternPool, field_index: u32) Alignment {
1827 if (self.field_aligns.len == 0) return .none;
1828 return self.field_aligns.get(ip)[field_index];
1829 }
1830
1831 /// This does not mutate the field of LoadedUnionType.
1832 pub fn setZirIndex(self: LoadedUnionType, ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
1833 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
1834 const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;
1835 const ptr: *TrackedInst.Index.Optional =
1836 @ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]);
1837 ptr.* = new_zir_index;
1838 }
1839
1840 pub fn setFieldTypes(self: LoadedUnionType, ip: *const InternPool, types: []const Index) void {
1841 @memcpy(self.field_types.get(ip), types);
1842 }
1843
1844 pub fn setFieldAligns(self: LoadedUnionType, ip: *const InternPool, aligns: []const Alignment) void {
1845 if (aligns.len == 0) return;
1846 assert(self.flagsPtr(ip).any_aligned_fields);
1847 @memcpy(self.field_aligns.get(ip), aligns);
1848 }
1849};
1850
1851pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
1852 const data = ip.items.items(.data)[@intFromEnum(index)];
1853 const type_union = ip.extraDataTrail(Tag.TypeUnion, data);
1854 const fields_len = type_union.data.fields_len;
1855
1856 var extra_index = type_union.end;
1857 const captures_len = if (type_union.data.flags.any_captures) c: {
1858 const len = ip.extra.items[extra_index];
1859 extra_index += 1;
1860 break :c len;
1861 } else 0;
1862
1863 const captures: CaptureValue.Slice = .{
1864 .start = extra_index,
1865 .len = captures_len,
1866 };
1867 extra_index += captures_len;
1868 if (type_union.data.flags.is_reified) {
1869 extra_index += 2; // PackedU64
1870 }
1871
1872 const field_types: Index.Slice = .{
1873 .start = extra_index,
1874 .len = fields_len,
1875 };
1876 extra_index += fields_len;
1877
1878 const field_aligns: Alignment.Slice = if (type_union.data.flags.any_aligned_fields) a: {
1879 const a: Alignment.Slice = .{
1880 .start = extra_index,
1881 .len = fields_len,
1882 };
1883 extra_index += std.math.divCeil(u32, fields_len, 4) catch unreachable;
1884 break :a a;
1885 } else .{ .start = 0, .len = 0 };
1886
1887 return .{
1888 .extra_index = data,
1889 .decl = type_union.data.decl,
1890 .namespace = type_union.data.namespace,
1891 .enum_tag_ty = type_union.data.tag_ty,
1892 .field_types = field_types,
1893 .field_aligns = field_aligns,
1894 .zir_index = type_union.data.zir_index,
1895 .captures = captures,
1896 };
1897}
1898
1899pub const LoadedStructType = struct {
1900 /// The index of the `Tag.TypeStruct` or `Tag.TypeStructPacked` payload.
1901 extra_index: u32,
1902 /// The struct's owner Decl. `none` when the struct is `@TypeOf(.{})`.
1903 decl: OptionalDeclIndex,
1904 /// `none` when the struct has no declarations.
1905 namespace: OptionalNamespaceIndex,
1906 /// Index of the `struct_decl` or `reify` ZIR instruction.
1907 /// Only `none` when the struct is `@TypeOf(.{})`.
1908 zir_index: TrackedInst.Index.Optional,
1909 layout: std.builtin.Type.ContainerLayout,
1910 field_names: NullTerminatedString.Slice,
1911 field_types: Index.Slice,
1912 field_inits: Index.Slice,
1913 field_aligns: Alignment.Slice,
1914 runtime_order: RuntimeOrder.Slice,
1915 comptime_bits: ComptimeBits,
1916 offsets: Offsets,
1917 names_map: OptionalMapIndex,
1918 captures: CaptureValue.Slice,
1919
1920 pub const ComptimeBits = struct {
1921 start: u32,
1922 /// This is the number of u32 elements, not the number of struct fields.
1923 len: u32,
1924
1925 pub fn get(this: ComptimeBits, ip: *const InternPool) []u32 {
1926 return ip.extra.items[this.start..][0..this.len];
1927 }
1928
1929 pub fn getBit(this: ComptimeBits, ip: *const InternPool, i: usize) bool {
1930 if (this.len == 0) return false;
1931 return @as(u1, @truncate(this.get(ip)[i / 32] >> @intCast(i % 32))) != 0;
1932 }
1933
1934 pub fn setBit(this: ComptimeBits, ip: *const InternPool, i: usize) void {
1935 this.get(ip)[i / 32] |= @as(u32, 1) << @intCast(i % 32);
1936 }
1937
1938 pub fn clearBit(this: ComptimeBits, ip: *const InternPool, i: usize) void {
1939 this.get(ip)[i / 32] &= ~(@as(u32, 1) << @intCast(i % 32));
1940 }
1941 };
1942
1943 pub const Offsets = struct {
1944 start: u32,
1945 len: u32,
1946
1947 pub fn get(this: Offsets, ip: *const InternPool) []u32 {
1948 return @ptrCast(ip.extra.items[this.start..][0..this.len]);
1949 }
1950 };
1951
1952 pub const RuntimeOrder = enum(u32) {
1953 /// Placeholder until layout is resolved.
1954 unresolved = std.math.maxInt(u32) - 0,
1955 /// Field not present at runtime
1956 omitted = std.math.maxInt(u32) - 1,
1957 _,
1958
1959 pub const Slice = struct {
1960 start: u32,
1961 len: u32,
1962
1963 pub fn get(slice: RuntimeOrder.Slice, ip: *const InternPool) []RuntimeOrder {
1964 return @ptrCast(ip.extra.items[slice.start..][0..slice.len]);
1965 }
1966 };
1967
1968 pub fn toInt(i: RuntimeOrder) ?u32 {
1969 return switch (i) {
1970 .omitted => null,
1971 .unresolved => unreachable,
1972 else => @intFromEnum(i),
1973 };
1974 }
1975 };
1976
1977 /// Look up field index based on field name.
1978 pub fn nameIndex(self: LoadedStructType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
1979 const names_map = self.names_map.unwrap() orelse {
1980 const i = name.toUnsigned(ip) orelse return null;
1981 if (i >= self.field_types.len) return null;
1982 return i;
1983 };
1984 const map = &ip.maps.items[@intFromEnum(names_map)];
1985 const adapter: NullTerminatedString.Adapter = .{ .strings = self.field_names.get(ip) };
1986 const field_index = map.getIndexAdapted(name, adapter) orelse return null;
1987 return @intCast(field_index);
1988 }
1989
1990 /// Returns the already-existing field with the same name, if any.
1991 pub fn addFieldName(
1992 self: @This(),
1993 ip: *InternPool,
1994 name: NullTerminatedString,
1995 ) ?u32 {
1996 return ip.addFieldName(self.names_map.unwrap().?, self.field_names.start, name);
1997 }
1998
1999 pub fn fieldAlign(s: @This(), ip: *const InternPool, i: usize) Alignment {
2000 if (s.field_aligns.len == 0) return .none;
2001 return s.field_aligns.get(ip)[i];
2002 }
2003
2004 pub fn fieldInit(s: @This(), ip: *const InternPool, i: usize) Index {
2005 if (s.field_inits.len == 0) return .none;
2006 assert(s.haveFieldInits(ip));
2007 return s.field_inits.get(ip)[i];
2008 }
2009
2010 /// Returns `none` in the case the struct is a tuple.
2011 pub fn fieldName(s: @This(), ip: *const InternPool, i: usize) OptionalNullTerminatedString {
2012 if (s.field_names.len == 0) return .none;
2013 return s.field_names.get(ip)[i].toOptional();
2014 }
2015
2016 pub fn fieldIsComptime(s: @This(), ip: *const InternPool, i: usize) bool {
2017 return s.comptime_bits.getBit(ip, i);
2018 }
2019
2020 pub fn setFieldComptime(s: @This(), ip: *InternPool, i: usize) void {
2021 s.comptime_bits.setBit(ip, i);
2022 }
2023
2024 /// Reads the non-opv flag calculated during AstGen. Used to short-circuit more
2025 /// complicated logic.
2026 pub fn knownNonOpv(s: @This(), ip: *InternPool) bool {
2027 return switch (s.layout) {
2028 .Packed => false,
2029 .Auto, .Extern => s.flagsPtr(ip).known_non_opv,
2030 };
2031 }
2032
2033 /// The returned pointer expires with any addition to the `InternPool`.
2034 /// Asserts the struct is not packed.
2035 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeStruct.Flags {
2036 assert(self.layout != .Packed);
2037 const flags_field_index = std.meta.fieldIndex(Tag.TypeStruct, "flags").?;
2038 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
2039 }
2040
2041 /// The returned pointer expires with any addition to the `InternPool`.
2042 /// Asserts that the struct is packed.
2043 pub fn packedFlagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeStructPacked.Flags {
2044 assert(self.layout == .Packed);
2045 const flags_field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?;
2046 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
2047 }
2048
2049 pub fn assumeRuntimeBitsIfFieldTypesWip(s: @This(), ip: *InternPool) bool {
2050 if (s.layout == .Packed) return false;
2051 const flags_ptr = s.flagsPtr(ip);
2052 if (flags_ptr.field_types_wip) {
2053 flags_ptr.assumed_runtime_bits = true;
2054 return true;
2055 }
2056 return false;
2057 }
2058
2059 pub fn setTypesWip(s: @This(), ip: *InternPool) bool {
2060 if (s.layout == .Packed) return false;
2061 const flags_ptr = s.flagsPtr(ip);
2062 if (flags_ptr.field_types_wip) return true;
2063 flags_ptr.field_types_wip = true;
2064 return false;
2065 }
2066
2067 pub fn clearTypesWip(s: @This(), ip: *InternPool) void {
2068 if (s.layout == .Packed) return;
2069 s.flagsPtr(ip).field_types_wip = false;
2070 }
2071
2072 pub fn setLayoutWip(s: @This(), ip: *InternPool) bool {
2073 if (s.layout == .Packed) return false;
2074 const flags_ptr = s.flagsPtr(ip);
2075 if (flags_ptr.layout_wip) return true;
2076 flags_ptr.layout_wip = true;
2077 return false;
2078 }
2079
2080 pub fn clearLayoutWip(s: @This(), ip: *InternPool) void {
2081 if (s.layout == .Packed) return;
2082 s.flagsPtr(ip).layout_wip = false;
2083 }
2084
2085 pub fn setAlignmentWip(s: @This(), ip: *InternPool) bool {
2086 if (s.layout == .Packed) return false;
2087 const flags_ptr = s.flagsPtr(ip);
2088 if (flags_ptr.alignment_wip) return true;
2089 flags_ptr.alignment_wip = true;
2090 return false;
2091 }
2092
2093 pub fn clearAlignmentWip(s: @This(), ip: *InternPool) void {
2094 if (s.layout == .Packed) return;
2095 s.flagsPtr(ip).alignment_wip = false;
2096 }
21672097
2168 pub fn haveFieldTypes(status: Status) bool {
2169 return switch (status) {
2170 .none,
2171 .field_types_wip,
2172 => false,
2173 .have_field_types,
2174 .layout_wip,
2175 .have_layout,
2176 .fully_resolved_wip,
2177 .fully_resolved,
2178 => true,
2179 };
2098 pub fn setInitsWip(s: @This(), ip: *InternPool) bool {
2099 switch (s.layout) {
2100 .Packed => {
2101 const flag = &s.packedFlagsPtr(ip).field_inits_wip;
2102 if (flag.*) return true;
2103 flag.* = true;
2104 return false;
2105 },
2106 .Auto, .Extern => {
2107 const flag = &s.flagsPtr(ip).field_inits_wip;
2108 if (flag.*) return true;
2109 flag.* = true;
2110 return false;
2111 },
21802112 }
2113 }
21812114
2182 pub fn haveLayout(status: Status) bool {
2183 return switch (status) {
2184 .none,
2185 .field_types_wip,
2186 .have_field_types,
2187 .layout_wip,
2188 => false,
2189 .have_layout,
2190 .fully_resolved_wip,
2191 .fully_resolved,
2192 => true,
2193 };
2115 pub fn clearInitsWip(s: @This(), ip: *InternPool) void {
2116 switch (s.layout) {
2117 .Packed => s.packedFlagsPtr(ip).field_inits_wip = false,
2118 .Auto, .Extern => s.flagsPtr(ip).field_inits_wip = false,
21942119 }
2195 };
2120 }
2121
2122 pub fn setFullyResolved(s: @This(), ip: *InternPool) bool {
2123 if (s.layout == .Packed) return true;
2124 const flags_ptr = s.flagsPtr(ip);
2125 if (flags_ptr.fully_resolved) return true;
2126 flags_ptr.fully_resolved = true;
2127 return false;
2128 }
2129
2130 pub fn clearFullyResolved(s: @This(), ip: *InternPool) void {
2131 s.flagsPtr(ip).fully_resolved = false;
2132 }
21962133
21972134 /// The returned pointer expires with any addition to the `InternPool`.
2198 pub fn flagsPtr(self: UnionType, ip: *const InternPool) *Tag.TypeUnion.Flags {
2199 return @ptrCast(&ip.extra.items[self.flags_index]);
2135 /// Asserts the struct is not packed.
2136 pub fn size(self: @This(), ip: *InternPool) *u32 {
2137 assert(self.layout != .Packed);
2138 const size_field_index = std.meta.fieldIndex(Tag.TypeStruct, "size").?;
2139 return @ptrCast(&ip.extra.items[self.extra_index + size_field_index]);
22002140 }
22012141
2202 /// Look up field index based on field name.
2203 pub fn nameIndex(self: UnionType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
2204 const map = &ip.maps.items[@intFromEnum(self.names_map.unwrap().?)];
2205 const adapter: NullTerminatedString.Adapter = .{ .strings = self.field_names.get(ip) };
2206 const field_index = map.getIndexAdapted(name, adapter) orelse return null;
2207 return @intCast(field_index);
2142 /// The backing integer type of the packed struct. Whether zig chooses
2143 /// this type or the user specifies it, it is stored here. This will be
2144 /// set to `none` until the layout is resolved.
2145 /// Asserts the struct is packed.
2146 pub fn backingIntType(s: @This(), ip: *const InternPool) *Index {
2147 assert(s.layout == .Packed);
2148 const field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_ty").?;
2149 return @ptrCast(&ip.extra.items[s.extra_index + field_index]);
22082150 }
22092151
2210 pub fn hasTag(self: UnionType, ip: *const InternPool) bool {
2211 return self.flagsPtr(ip).runtime_tag.hasTag();
2152 /// Asserts the struct is not packed.
2153 pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
2154 assert(s.layout != .Packed);
2155 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;
2156 ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);
22122157 }
22132158
2214 pub fn haveFieldTypes(self: UnionType, ip: *const InternPool) bool {
2215 return self.flagsPtr(ip).status.haveFieldTypes();
2159 pub fn haveFieldTypes(s: @This(), ip: *const InternPool) bool {
2160 const types = s.field_types.get(ip);
2161 return types.len == 0 or types[0] != .none;
22162162 }
22172163
2218 pub fn haveLayout(self: UnionType, ip: *const InternPool) bool {
2219 return self.flagsPtr(ip).status.haveLayout();
2164 pub fn haveFieldInits(s: @This(), ip: *const InternPool) bool {
2165 return switch (s.layout) {
2166 .Packed => s.packedFlagsPtr(ip).inits_resolved,
2167 .Auto, .Extern => s.flagsPtr(ip).inits_resolved,
2168 };
22202169 }
22212170
2222 pub fn getLayout(self: UnionType, ip: *const InternPool) std.builtin.Type.ContainerLayout {
2223 return self.flagsPtr(ip).layout;
2171 pub fn setHaveFieldInits(s: @This(), ip: *InternPool) void {
2172 switch (s.layout) {
2173 .Packed => s.packedFlagsPtr(ip).inits_resolved = true,
2174 .Auto, .Extern => s.flagsPtr(ip).inits_resolved = true,
2175 }
22242176 }
22252177
2226 pub fn fieldAlign(self: UnionType, ip: *const InternPool, field_index: u32) Alignment {
2227 if (self.field_aligns.len == 0) return .none;
2228 return self.field_aligns.get(ip)[field_index];
2178 pub fn haveLayout(s: @This(), ip: *InternPool) bool {
2179 return switch (s.layout) {
2180 .Packed => s.backingIntType(ip).* != .none,
2181 .Auto, .Extern => s.flagsPtr(ip).layout_resolved,
2182 };
22292183 }
22302184
2231 /// This does not mutate the field of UnionType.
2232 pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
2233 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
2234 const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;
2235 const ptr: *TrackedInst.Index.Optional =
2236 @ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]);
2237 ptr.* = new_zir_index;
2185 pub fn isTuple(s: @This(), ip: *InternPool) bool {
2186 return s.layout != .Packed and s.flagsPtr(ip).is_tuple;
2187 }
2188
2189 pub fn hasReorderedFields(s: @This()) bool {
2190 return s.layout == .Auto;
2191 }
2192
2193 pub const RuntimeOrderIterator = struct {
2194 ip: *InternPool,
2195 field_index: u32,
2196 struct_type: InternPool.LoadedStructType,
2197
2198 pub fn next(it: *@This()) ?u32 {
2199 var i = it.field_index;
2200
2201 if (i >= it.struct_type.field_types.len)
2202 return null;
2203
2204 if (it.struct_type.hasReorderedFields()) {
2205 it.field_index += 1;
2206 return it.struct_type.runtime_order.get(it.ip)[i].toInt();
2207 }
2208
2209 while (it.struct_type.fieldIsComptime(it.ip, i)) {
2210 i += 1;
2211 if (i >= it.struct_type.field_types.len)
2212 return null;
2213 }
2214
2215 it.field_index = i + 1;
2216 return i;
2217 }
2218 };
2219
2220 /// Iterates over non-comptime fields in the order they are laid out in memory at runtime.
2221 /// May or may not include zero-bit fields.
2222 /// Asserts the struct is not packed.
2223 pub fn iterateRuntimeOrder(s: @This(), ip: *InternPool) RuntimeOrderIterator {
2224 assert(s.layout != .Packed);
2225 return .{
2226 .ip = ip,
2227 .field_index = 0,
2228 .struct_type = s,
2229 };
22382230 }
22392231};
22402232
2241/// Fetch all the interesting fields of a union type into a convenient data
2242/// structure.
2243/// This asserts that the union's enum tag type has been resolved.
2244pub fn loadUnionType(ip: *InternPool, key: Key.UnionType) UnionType {
2245 const type_union = ip.extraDataTrail(Tag.TypeUnion, key.extra_index);
2246 const enum_ty = type_union.data.tag_ty;
2247 const enum_info = ip.indexToKey(enum_ty).enum_type;
2248 const fields_len: u32 = @intCast(enum_info.names.len);
2233pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
2234 const item = ip.items.get(@intFromEnum(index));
2235 switch (item.tag) {
2236 .type_struct => {
2237 if (item.data == 0) return .{
2238 .extra_index = 0,
2239 .decl = .none,
2240 .namespace = .none,
2241 .zir_index = .none,
2242 .layout = .Auto,
2243 .field_names = .{ .start = 0, .len = 0 },
2244 .field_types = .{ .start = 0, .len = 0 },
2245 .field_inits = .{ .start = 0, .len = 0 },
2246 .field_aligns = .{ .start = 0, .len = 0 },
2247 .runtime_order = .{ .start = 0, .len = 0 },
2248 .comptime_bits = .{ .start = 0, .len = 0 },
2249 .offsets = .{ .start = 0, .len = 0 },
2250 .names_map = .none,
2251 .captures = .{ .start = 0, .len = 0 },
2252 };
2253 const extra = ip.extraDataTrail(Tag.TypeStruct, item.data);
2254 const fields_len = extra.data.fields_len;
2255 var extra_index = extra.end;
2256 const captures_len = if (extra.data.flags.any_captures) c: {
2257 const len = ip.extra.items[extra_index];
2258 extra_index += 1;
2259 break :c len;
2260 } else 0;
2261 const captures: CaptureValue.Slice = .{
2262 .start = extra_index,
2263 .len = captures_len,
2264 };
2265 extra_index += captures_len;
2266 if (extra.data.flags.is_reified) {
2267 extra_index += 2; // PackedU64
2268 }
2269 const field_types: Index.Slice = .{
2270 .start = extra_index,
2271 .len = fields_len,
2272 };
2273 extra_index += fields_len;
2274 const names_map: OptionalMapIndex, const names: NullTerminatedString.Slice = if (!extra.data.flags.is_tuple) n: {
2275 const names_map: OptionalMapIndex = @enumFromInt(ip.extra.items[extra_index]);
2276 extra_index += 1;
2277 const names: NullTerminatedString.Slice = .{ .start = extra_index, .len = fields_len };
2278 extra_index += fields_len;
2279 break :n .{ names_map, names };
2280 } else .{ .none, .{ .start = 0, .len = 0 } };
2281 const inits: Index.Slice = if (extra.data.flags.any_default_inits) i: {
2282 const inits: Index.Slice = .{ .start = extra_index, .len = fields_len };
2283 extra_index += fields_len;
2284 break :i inits;
2285 } else .{ .start = 0, .len = 0 };
2286 const namespace: OptionalNamespaceIndex = if (extra.data.flags.has_namespace) n: {
2287 const n: NamespaceIndex = @enumFromInt(ip.extra.items[extra_index]);
2288 extra_index += 1;
2289 break :n n.toOptional();
2290 } else .none;
2291 const aligns: Alignment.Slice = if (extra.data.flags.any_aligned_fields) a: {
2292 const a: Alignment.Slice = .{ .start = extra_index, .len = fields_len };
2293 extra_index += std.math.divCeil(u32, fields_len, 4) catch unreachable;
2294 break :a a;
2295 } else .{ .start = 0, .len = 0 };
2296 const comptime_bits: LoadedStructType.ComptimeBits = if (extra.data.flags.any_comptime_fields) c: {
2297 const len = std.math.divCeil(u32, fields_len, 32) catch unreachable;
2298 const c: LoadedStructType.ComptimeBits = .{ .start = extra_index, .len = len };
2299 extra_index += len;
2300 break :c c;
2301 } else .{ .start = 0, .len = 0 };
2302 const runtime_order: LoadedStructType.RuntimeOrder.Slice = if (!extra.data.flags.is_extern) ro: {
2303 const ro: LoadedStructType.RuntimeOrder.Slice = .{ .start = extra_index, .len = fields_len };
2304 extra_index += fields_len;
2305 break :ro ro;
2306 } else .{ .start = 0, .len = 0 };
2307 const offsets: LoadedStructType.Offsets = o: {
2308 const o: LoadedStructType.Offsets = .{ .start = extra_index, .len = fields_len };
2309 extra_index += fields_len;
2310 break :o o;
2311 };
2312 return .{
2313 .extra_index = item.data,
2314 .decl = extra.data.decl.toOptional(),
2315 .namespace = namespace,
2316 .zir_index = extra.data.zir_index.toOptional(),
2317 .layout = if (extra.data.flags.is_extern) .Extern else .Auto,
2318 .field_names = names,
2319 .field_types = field_types,
2320 .field_inits = inits,
2321 .field_aligns = aligns,
2322 .runtime_order = runtime_order,
2323 .comptime_bits = comptime_bits,
2324 .offsets = offsets,
2325 .names_map = names_map,
2326 .captures = captures,
2327 };
2328 },
2329 .type_struct_packed, .type_struct_packed_inits => {
2330 const extra = ip.extraDataTrail(Tag.TypeStructPacked, item.data);
2331 const has_inits = item.tag == .type_struct_packed_inits;
2332 const fields_len = extra.data.fields_len;
2333 var extra_index = extra.end;
2334 const captures_len = if (extra.data.flags.any_captures) c: {
2335 const len = ip.extra.items[extra_index];
2336 extra_index += 1;
2337 break :c len;
2338 } else 0;
2339 const captures: CaptureValue.Slice = .{
2340 .start = extra_index,
2341 .len = captures_len,
2342 };
2343 extra_index += captures_len;
2344 if (extra.data.flags.is_reified) {
2345 extra_index += 2; // PackedU64
2346 }
2347 const field_types: Index.Slice = .{
2348 .start = extra_index,
2349 .len = fields_len,
2350 };
2351 extra_index += fields_len;
2352 const field_names: NullTerminatedString.Slice = .{
2353 .start = extra_index,
2354 .len = fields_len,
2355 };
2356 extra_index += fields_len;
2357 const field_inits: Index.Slice = if (has_inits) inits: {
2358 const i: Index.Slice = .{
2359 .start = extra_index,
2360 .len = fields_len,
2361 };
2362 extra_index += fields_len;
2363 break :inits i;
2364 } else .{ .start = 0, .len = 0 };
2365 return .{
2366 .extra_index = item.data,
2367 .decl = extra.data.decl.toOptional(),
2368 .namespace = extra.data.namespace,
2369 .zir_index = extra.data.zir_index.toOptional(),
2370 .layout = .Packed,
2371 .field_names = field_names,
2372 .field_types = field_types,
2373 .field_inits = field_inits,
2374 .field_aligns = .{ .start = 0, .len = 0 },
2375 .runtime_order = .{ .start = 0, .len = 0 },
2376 .comptime_bits = .{ .start = 0, .len = 0 },
2377 .offsets = .{ .start = 0, .len = 0 },
2378 .names_map = extra.data.names_map.toOptional(),
2379 .captures = captures,
2380 };
2381 },
2382 else => unreachable,
2383 }
2384}
2385
2386const LoadedEnumType = struct {
2387 /// The Decl that corresponds to the enum itself.
2388 decl: DeclIndex,
2389 /// Represents the declarations inside this enum.
2390 namespace: OptionalNamespaceIndex,
2391 /// An integer type which is used for the numerical value of the enum.
2392 /// This field is present regardless of whether the enum has an
2393 /// explicitly provided tag type or auto-numbered.
2394 tag_ty: Index,
2395 /// Set of field names in declaration order.
2396 names: NullTerminatedString.Slice,
2397 /// Maps integer tag value to field index.
2398 /// Entries are in declaration order, same as `fields`.
2399 /// If this is empty, it means the enum tags are auto-numbered.
2400 values: Index.Slice,
2401 tag_mode: TagMode,
2402 names_map: MapIndex,
2403 /// This is guaranteed to not be `.none` if explicit values are provided.
2404 values_map: OptionalMapIndex,
2405 /// This is `none` only if this is a generated tag type.
2406 zir_index: TrackedInst.Index.Optional,
2407 captures: CaptureValue.Slice,
2408
2409 pub const TagMode = enum {
2410 /// The integer tag type was auto-numbered by zig.
2411 auto,
2412 /// The integer tag type was provided by the enum declaration, and the enum
2413 /// is exhaustive.
2414 explicit,
2415 /// The integer tag type was provided by the enum declaration, and the enum
2416 /// is non-exhaustive.
2417 nonexhaustive,
2418 };
2419
2420 /// Look up field index based on field name.
2421 pub fn nameIndex(self: LoadedEnumType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
2422 const map = &ip.maps.items[@intFromEnum(self.names_map)];
2423 const adapter: NullTerminatedString.Adapter = .{ .strings = self.names.get(ip) };
2424 const field_index = map.getIndexAdapted(name, adapter) orelse return null;
2425 return @intCast(field_index);
2426 }
2427
2428 /// Look up field index based on tag value.
2429 /// Asserts that `values_map` is not `none`.
2430 /// This function returns `null` when `tag_val` does not have the
2431 /// integer tag type of the enum.
2432 pub fn tagValueIndex(self: LoadedEnumType, ip: *const InternPool, tag_val: Index) ?u32 {
2433 assert(tag_val != .none);
2434 // TODO: we should probably decide a single interface for this function, but currently
2435 // it's being called with both tag values and underlying ints. Fix this!
2436 const int_tag_val = switch (ip.indexToKey(tag_val)) {
2437 .enum_tag => |enum_tag| enum_tag.int,
2438 .int => tag_val,
2439 else => unreachable,
2440 };
2441 if (self.values_map.unwrap()) |values_map| {
2442 const map = &ip.maps.items[@intFromEnum(values_map)];
2443 const adapter: Index.Adapter = .{ .indexes = self.values.get(ip) };
2444 const field_index = map.getIndexAdapted(int_tag_val, adapter) orelse return null;
2445 return @intCast(field_index);
2446 }
2447 // Auto-numbered enum. Convert `int_tag_val` to field index.
2448 const field_index = switch (ip.indexToKey(int_tag_val).int.storage) {
2449 inline .u64, .i64 => |x| std.math.cast(u32, x) orelse return null,
2450 .big_int => |x| x.to(u32) catch return null,
2451 .lazy_align, .lazy_size => unreachable,
2452 };
2453 return if (field_index < self.names.len) field_index else null;
2454 }
2455};
22492456
2457pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
2458 const item = ip.items.get(@intFromEnum(index));
2459 const tag_mode: LoadedEnumType.TagMode = switch (item.tag) {
2460 .type_enum_auto => {
2461 const extra = ip.extraDataTrail(EnumAuto, item.data);
2462 var extra_index: u32 = @intCast(extra.end);
2463 if (extra.data.zir_index == .none) {
2464 extra_index += 1; // owner_union
2465 }
2466 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {
2467 extra_index += 2; // type_hash: PackedU64
2468 break :c 0;
2469 } else extra.data.captures_len;
2470 return .{
2471 .decl = extra.data.decl,
2472 .namespace = extra.data.namespace,
2473 .tag_ty = extra.data.int_tag_type,
2474 .names = .{
2475 .start = extra_index + captures_len,
2476 .len = extra.data.fields_len,
2477 },
2478 .values = .{ .start = 0, .len = 0 },
2479 .tag_mode = .auto,
2480 .names_map = extra.data.names_map,
2481 .values_map = .none,
2482 .zir_index = extra.data.zir_index,
2483 .captures = .{
2484 .start = extra_index,
2485 .len = captures_len,
2486 },
2487 };
2488 },
2489 .type_enum_explicit => .explicit,
2490 .type_enum_nonexhaustive => .nonexhaustive,
2491 else => unreachable,
2492 };
2493 const extra = ip.extraDataTrail(EnumExplicit, item.data);
2494 var extra_index: u32 = @intCast(extra.end);
2495 if (extra.data.zir_index == .none) {
2496 extra_index += 1; // owner_union
2497 }
2498 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {
2499 extra_index += 2; // type_hash: PackedU64
2500 break :c 0;
2501 } else extra.data.captures_len;
22502502 return .{
2251 .decl = type_union.data.decl,
2252 .namespace = type_union.data.namespace,
2253 .enum_tag_ty = enum_ty,
2254 .int_tag_ty = enum_info.tag_ty,
2255 .size = type_union.data.size,
2256 .padding = type_union.data.padding,
2257 .field_names = enum_info.names,
2258 .names_map = enum_info.names_map,
2259 .field_types = .{
2260 .start = type_union.end,
2261 .len = fields_len,
2503 .decl = extra.data.decl,
2504 .namespace = extra.data.namespace,
2505 .tag_ty = extra.data.int_tag_type,
2506 .names = .{
2507 .start = extra_index + captures_len,
2508 .len = extra.data.fields_len,
22622509 },
2263 .field_aligns = .{
2264 .start = type_union.end + fields_len,
2265 .len = if (type_union.data.flags.any_aligned_fields) fields_len else 0,
2510 .values = .{
2511 .start = extra_index + captures_len + extra.data.fields_len,
2512 .len = if (extra.data.values_map != .none) extra.data.fields_len else 0,
2513 },
2514 .tag_mode = tag_mode,
2515 .names_map = extra.data.names_map,
2516 .values_map = extra.data.values_map,
2517 .zir_index = extra.data.zir_index,
2518 .captures = .{
2519 .start = extra_index,
2520 .len = captures_len,
2521 },
2522 };
2523}
2524
2525/// Note that this type doubles as the payload for `Tag.type_opaque`.
2526pub const LoadedOpaqueType = struct {
2527 /// The opaque's owner Decl.
2528 decl: DeclIndex,
2529 /// Contains the declarations inside this opaque.
2530 namespace: OptionalNamespaceIndex,
2531 /// Index of the `opaque_decl` or `reify` instruction.
2532 zir_index: TrackedInst.Index,
2533 captures: CaptureValue.Slice,
2534};
2535
2536pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType {
2537 assert(ip.items.items(.tag)[@intFromEnum(index)] == .type_opaque);
2538 const extra_index = ip.items.items(.data)[@intFromEnum(index)];
2539 const extra = ip.extraDataTrail(Tag.TypeOpaque, extra_index);
2540 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32))
2541 0
2542 else
2543 extra.data.captures_len;
2544 return .{
2545 .decl = extra.data.decl,
2546 .namespace = extra.data.namespace,
2547 .zir_index = extra.data.zir_index,
2548 .captures = .{
2549 .start = extra.end,
2550 .len = captures_len,
22662551 },
2267 .zir_index = type_union.data.zir_index,
2268 .flags_index = key.extra_index + std.meta.fieldIndex(Tag.TypeUnion, "flags").?,
22692552 };
22702553}
22712554
......@@ -2457,6 +2740,7 @@ pub const Index = enum(u32) {
24572740 },
24582741 };
24592742
2743 removed: void,
24602744 type_int_signed: struct { data: u32 },
24612745 type_int_unsigned: struct { data: u32 },
24622746 type_array_big: struct { data: *Array },
......@@ -2484,9 +2768,8 @@ pub const Index = enum(u32) {
24842768 type_enum_explicit: DataIsExtraIndexOfEnumExplicit,
24852769 type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit,
24862770 simple_type: struct { data: SimpleType },
2487 type_opaque: struct { data: *Key.OpaqueType },
2771 type_opaque: struct { data: *Tag.TypeOpaque },
24882772 type_struct: struct { data: *Tag.TypeStruct },
2489 type_struct_ns: struct { data: NamespaceIndex },
24902773 type_struct_anon: DataIsExtraIndexOfTypeStructAnon,
24912774 type_struct_packed: struct { data: *Tag.TypeStructPacked },
24922775 type_struct_packed_inits: struct { data: *Tag.TypeStructPacked },
......@@ -2865,6 +3148,12 @@ comptime {
28653148}
28663149
28673150pub const Tag = enum(u8) {
3151 /// This special tag represents a value which was removed from this pool via
3152 /// `InternPool.remove`. The item remains allocated to preserve indices, but
3153 /// lookups will consider it not equal to any other item, and all queries
3154 /// assert not this tag. `data` is unused.
3155 removed,
3156
28683157 /// An integer type.
28693158 /// data is number of bits
28703159 type_int_signed,
......@@ -2920,15 +3209,12 @@ pub const Tag = enum(u8) {
29203209 /// data is SimpleType enum value.
29213210 simple_type,
29223211 /// An opaque type.
2923 /// data is index of Key.OpaqueType in extra.
3212 /// data is index of Tag.TypeOpaque in extra.
29243213 type_opaque,
29253214 /// A non-packed struct type.
29263215 /// data is 0 or extra index of `TypeStruct`.
29273216 /// data == 0 represents `@TypeOf(.{})`.
29283217 type_struct,
2929 /// A non-packed struct type that has only a namespace; no fields.
2930 /// data is NamespaceIndex.
2931 type_struct_ns,
29323218 /// An AnonStructType which stores types, names, and values for fields.
29333219 /// data is extra index of `TypeStructAnon`.
29343220 type_struct_anon,
......@@ -3126,7 +3412,6 @@ pub const Tag = enum(u8) {
31263412 memoized_call,
31273413
31283414 const ErrorUnionType = Key.ErrorUnionType;
3129 const OpaqueType = Key.OpaqueType;
31303415 const TypeValue = Key.TypeValue;
31313416 const Error = Key.Error;
31323417 const EnumTag = Key.EnumTag;
......@@ -3136,6 +3421,7 @@ pub const Tag = enum(u8) {
31363421
31373422 fn Payload(comptime tag: Tag) type {
31383423 return switch (tag) {
3424 .removed => unreachable,
31393425 .type_int_signed => unreachable,
31403426 .type_int_unsigned => unreachable,
31413427 .type_array_big => Array,
......@@ -3153,9 +3439,8 @@ pub const Tag = enum(u8) {
31533439 .type_enum_explicit => EnumExplicit,
31543440 .type_enum_nonexhaustive => EnumExplicit,
31553441 .simple_type => unreachable,
3156 .type_opaque => OpaqueType,
3442 .type_opaque => TypeOpaque,
31573443 .type_struct => TypeStruct,
3158 .type_struct_ns => unreachable,
31593444 .type_struct_anon => TypeStructAnon,
31603445 .type_struct_packed, .type_struct_packed_inits => TypeStructPacked,
31613446 .type_tuple_anon => TypeStructAnon,
......@@ -3311,43 +3596,54 @@ pub const Tag = enum(u8) {
33113596 };
33123597 };
33133598
3314 /// The number of fields is provided by the `tag_ty` field.
33153599 /// Trailing:
3316 /// 0. field type: Index for each field; declaration order
3317 /// 1. field align: Alignment for each field; declaration order
3600 /// 0. captures_len: u32 // if `any_captures`
3601 /// 1. capture: CaptureValue // for each `captures_len`
3602 /// 2. type_hash: PackedU64 // if `is_reified`
3603 /// 3. field type: Index for each field; declaration order
3604 /// 4. field align: Alignment for each field; declaration order
33183605 pub const TypeUnion = struct {
33193606 flags: Flags,
3607 /// This could be provided through the tag type, but it is more convenient
3608 /// to store it directly. This is also necessary for `dumpStatsFallible` to
3609 /// work on unresolved types.
3610 fields_len: u32,
33203611 /// Only valid after .have_layout
33213612 size: u32,
33223613 /// Only valid after .have_layout
33233614 padding: u32,
33243615 decl: DeclIndex,
3325 namespace: NamespaceIndex,
3616 namespace: OptionalNamespaceIndex,
33263617 /// The enum that provides the list of field names and values.
33273618 tag_ty: Index,
3328 zir_index: TrackedInst.Index.Optional,
3619 zir_index: TrackedInst.Index,
33293620
33303621 pub const Flags = packed struct(u32) {
3331 runtime_tag: UnionType.RuntimeTag,
3622 any_captures: bool,
3623 runtime_tag: LoadedUnionType.RuntimeTag,
33323624 /// If false, the field alignment trailing data is omitted.
33333625 any_aligned_fields: bool,
33343626 layout: std.builtin.Type.ContainerLayout,
3335 status: UnionType.Status,
3627 status: LoadedUnionType.Status,
33363628 requires_comptime: RequiresComptime,
33373629 assumed_runtime_bits: bool,
33383630 assumed_pointer_aligned: bool,
33393631 alignment: Alignment,
3340 _: u14 = 0,
3632 is_reified: bool,
3633 _: u12 = 0,
33413634 };
33423635 };
33433636
33443637 /// Trailing:
3345 /// 0. type: Index for each fields_len
3346 /// 1. name: NullTerminatedString for each fields_len
3347 /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits
3638 /// 0. captures_len: u32 // if `any_captures`
3639 /// 1. capture: CaptureValue // for each `captures_len`
3640 /// 2. type_hash: PackedU64 // if `is_reified`
3641 /// 3. type: Index for each fields_len
3642 /// 4. name: NullTerminatedString for each fields_len
3643 /// 5. init: Index for each fields_len // if tag is type_struct_packed_inits
33483644 pub const TypeStructPacked = struct {
33493645 decl: DeclIndex,
3350 zir_index: TrackedInst.Index.Optional,
3646 zir_index: TrackedInst.Index,
33513647 fields_len: u32,
33523648 namespace: OptionalNamespaceIndex,
33533649 backing_int_ty: Index,
......@@ -3355,10 +3651,12 @@ pub const Tag = enum(u8) {
33553651 flags: Flags,
33563652
33573653 pub const Flags = packed struct(u32) {
3654 any_captures: bool,
33583655 /// Dependency loop detection when resolving field inits.
33593656 field_inits_wip: bool,
33603657 inits_resolved: bool,
3361 _: u30 = 0,
3658 is_reified: bool,
3659 _: u28 = 0,
33623660 };
33633661 };
33643662
......@@ -3377,29 +3675,33 @@ pub const Tag = enum(u8) {
33773675 /// than coming up with some other scheme for the data.
33783676 ///
33793677 /// Trailing:
3380 /// 0. type: Index for each field in declared order
3381 /// 1. if not is_tuple:
3678 /// 0. captures_len: u32 // if `any_captures`
3679 /// 1. capture: CaptureValue // for each `captures_len`
3680 /// 2. type_hash: PackedU64 // if `is_reified`
3681 /// 3. type: Index for each field in declared order
3682 /// 4. if not is_tuple:
33823683 /// names_map: MapIndex,
33833684 /// name: NullTerminatedString // for each field in declared order
3384 /// 2. if any_default_inits:
3685 /// 5. if any_default_inits:
33853686 /// init: Index // for each field in declared order
3386 /// 3. if has_namespace:
3687 /// 6. if has_namespace:
33873688 /// namespace: NamespaceIndex
3388 /// 4. if any_aligned_fields:
3689 /// 7. if any_aligned_fields:
33893690 /// align: Alignment // for each field in declared order
3390 /// 5. if any_comptime_fields:
3691 /// 8. if any_comptime_fields:
33913692 /// field_is_comptime_bits: u32 // minimal number of u32s needed, LSB is field 0
3392 /// 6. if not is_extern:
3693 /// 9. if not is_extern:
33933694 /// field_index: RuntimeOrder // for each field in runtime order
3394 /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved
3695 /// 10. field_offset: u32 // for each field in declared order, undef until layout_resolved
33953696 pub const TypeStruct = struct {
33963697 decl: DeclIndex,
3397 zir_index: TrackedInst.Index.Optional,
3698 zir_index: TrackedInst.Index,
33983699 fields_len: u32,
33993700 flags: Flags,
34003701 size: u32,
34013702
34023703 pub const Flags = packed struct(u32) {
3704 any_captures: bool,
34033705 is_extern: bool,
34043706 known_non_opv: bool,
34053707 requires_comptime: RequiresComptime,
......@@ -3428,10 +3730,23 @@ pub const Tag = enum(u8) {
34283730 // The types and all its fields have had their layout resolved. Even through pointer,
34293731 // which `layout_resolved` does not ensure.
34303732 fully_resolved: bool,
3431
3432 _: u8 = 0,
3733 is_reified: bool,
3734 _: u6 = 0,
34333735 };
34343736 };
3737
3738 /// Trailing:
3739 /// 0. capture: CaptureValue // for each `captures_len`
3740 pub const TypeOpaque = struct {
3741 /// The opaque's owner Decl.
3742 decl: DeclIndex,
3743 /// Contains the declarations inside this opaque.
3744 namespace: OptionalNamespaceIndex,
3745 /// The index of the `opaque_decl` instruction.
3746 zir_index: TrackedInst.Index,
3747 /// `std.math.maxInt(u32)` indicates this type is reified.
3748 captures_len: u32,
3749 };
34353750};
34363751
34373752/// State that is mutable during semantic analysis. This data is not used for
......@@ -3738,11 +4053,16 @@ pub const Array = struct {
37384053};
37394054
37404055/// Trailing:
3741/// 0. field name: NullTerminatedString for each fields_len; declaration order
3742/// 1. tag value: Index for each fields_len; declaration order
4056/// 0. owner_union: Index // if `zir_index == .none`
4057/// 1. capture: CaptureValue // for each `captures_len`
4058/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
4059/// 3. field name: NullTerminatedString for each fields_len; declaration order
4060/// 4. tag value: Index for each fields_len; declaration order
37434061pub const EnumExplicit = struct {
37444062 /// The Decl that corresponds to the enum itself.
37454063 decl: DeclIndex,
4064 /// `std.math.maxInt(u32)` indicates this type is reified.
4065 captures_len: u32,
37464066 /// This may be `none` if there are no declarations.
37474067 namespace: OptionalNamespaceIndex,
37484068 /// An integer type which is used for the numerical value of the enum, which
......@@ -3755,14 +4075,21 @@ pub const EnumExplicit = struct {
37554075 /// If this is `none`, it means the trailing tag values are absent because
37564076 /// they are auto-numbered.
37574077 values_map: OptionalMapIndex,
4078 /// `none` means this is a generated tag type.
4079 /// There will be a trailing union type for which this is a tag.
37584080 zir_index: TrackedInst.Index.Optional,
37594081};
37604082
37614083/// Trailing:
3762/// 0. field name: NullTerminatedString for each fields_len; declaration order
4084/// 0. owner_union: Index // if `zir_index == .none`
4085/// 1. capture: CaptureValue // for each `captures_len`
4086/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
4087/// 3. field name: NullTerminatedString for each fields_len; declaration order
37634088pub const EnumAuto = struct {
37644089 /// The Decl that corresponds to the enum itself.
37654090 decl: DeclIndex,
4091 /// `std.math.maxInt(u32)` indicates this type is reified.
4092 captures_len: u32,
37664093 /// This may be `none` if there are no declarations.
37674094 namespace: OptionalNamespaceIndex,
37684095 /// An integer type which is used for the numerical value of the enum, which
......@@ -3771,6 +4098,8 @@ pub const EnumAuto = struct {
37714098 fields_len: u32,
37724099 /// Maps field names to declaration index.
37734100 names_map: MapIndex,
4101 /// `none` means this is a generated tag type.
4102 /// There will be a trailing union type for which this is a tag.
37744103 zir_index: TrackedInst.Index.Optional,
37754104};
37764105
......@@ -4011,6 +4340,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
40114340 const item = ip.items.get(@intFromEnum(index));
40124341 const data = item.data;
40134342 return switch (item.tag) {
4343 .removed => unreachable,
40144344 .type_int_signed => .{
40154345 .int_type = .{
40164346 .signedness = .signed,
......@@ -4072,68 +4402,124 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
40724402 .inferred_error_set_type = @enumFromInt(data),
40734403 },
40744404
4075 .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) },
4076
4077 .type_struct => .{ .struct_type = if (data == 0) .{
4078 .extra_index = 0,
4079 .namespace = .none,
4080 .decl = .none,
4081 .zir_index = undefined,
4082 .layout = .Auto,
4083 .field_names = .{ .start = 0, .len = 0 },
4084 .field_types = .{ .start = 0, .len = 0 },
4085 .field_inits = .{ .start = 0, .len = 0 },
4086 .field_aligns = .{ .start = 0, .len = 0 },
4087 .runtime_order = .{ .start = 0, .len = 0 },
4088 .comptime_bits = .{ .start = 0, .len = 0 },
4089 .offsets = .{ .start = 0, .len = 0 },
4090 .names_map = undefined,
4091 } else extraStructType(ip, data) },
4092
4093 .type_struct_ns => .{ .struct_type = .{
4094 .extra_index = 0,
4095 .namespace = @as(NamespaceIndex, @enumFromInt(data)).toOptional(),
4096 .decl = .none,
4097 .zir_index = undefined,
4098 .layout = .Auto,
4099 .field_names = .{ .start = 0, .len = 0 },
4100 .field_types = .{ .start = 0, .len = 0 },
4101 .field_inits = .{ .start = 0, .len = 0 },
4102 .field_aligns = .{ .start = 0, .len = 0 },
4103 .runtime_order = .{ .start = 0, .len = 0 },
4104 .comptime_bits = .{ .start = 0, .len = 0 },
4105 .offsets = .{ .start = 0, .len = 0 },
4106 .names_map = undefined,
4405 .type_opaque => .{ .opaque_type = ns: {
4406 const extra = ip.extraDataTrail(Tag.TypeOpaque, data);
4407 if (extra.data.captures_len == std.math.maxInt(u32)) {
4408 break :ns .{ .reified = .{
4409 .zir_index = extra.data.zir_index,
4410 .type_hash = 0,
4411 } };
4412 }
4413 break :ns .{ .declared = .{
4414 .zir_index = extra.data.zir_index,
4415 .captures = .{ .owned = .{
4416 .start = extra.end,
4417 .len = extra.data.captures_len,
4418 } },
4419 } };
4420 } },
4421
4422 .type_struct => .{ .struct_type = ns: {
4423 if (data == 0) break :ns .empty_struct;
4424 const extra = ip.extraDataTrail(Tag.TypeStruct, data);
4425 if (extra.data.flags.is_reified) {
4426 assert(!extra.data.flags.any_captures);
4427 break :ns .{ .reified = .{
4428 .zir_index = extra.data.zir_index,
4429 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4430 } };
4431 }
4432 break :ns .{ .declared = .{
4433 .zir_index = extra.data.zir_index,
4434 .captures = .{ .owned = if (extra.data.flags.any_captures) .{
4435 .start = extra.end + 1,
4436 .len = ip.extra.items[extra.end],
4437 } else .{ .start = 0, .len = 0 } },
4438 } };
4439 } },
4440
4441 .type_struct_packed, .type_struct_packed_inits => .{ .struct_type = ns: {
4442 const extra = ip.extraDataTrail(Tag.TypeStructPacked, data);
4443 if (extra.data.flags.is_reified) {
4444 assert(!extra.data.flags.any_captures);
4445 break :ns .{ .reified = .{
4446 .zir_index = extra.data.zir_index,
4447 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4448 } };
4449 }
4450 break :ns .{ .declared = .{
4451 .zir_index = extra.data.zir_index,
4452 .captures = .{ .owned = if (extra.data.flags.any_captures) .{
4453 .start = extra.end + 1,
4454 .len = ip.extra.items[extra.end],
4455 } else .{ .start = 0, .len = 0 } },
4456 } };
41074457 } },
41084458
41094459 .type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(ip, data) },
41104460 .type_tuple_anon => .{ .anon_struct_type = extraTypeTupleAnon(ip, data) },
4111 .type_struct_packed => .{ .struct_type = extraPackedStructType(ip, data, false) },
4112 .type_struct_packed_inits => .{ .struct_type = extraPackedStructType(ip, data, true) },
4113 .type_union => .{ .union_type = extraUnionType(ip, data) },
4461 .type_union => .{ .union_type = ns: {
4462 const extra = ip.extraDataTrail(Tag.TypeUnion, data);
4463 if (extra.data.flags.is_reified) {
4464 assert(!extra.data.flags.any_captures);
4465 break :ns .{ .reified = .{
4466 .zir_index = extra.data.zir_index,
4467 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4468 } };
4469 }
4470 break :ns .{ .declared = .{
4471 .zir_index = extra.data.zir_index,
4472 .captures = .{ .owned = if (extra.data.flags.any_captures) .{
4473 .start = extra.end + 1,
4474 .len = ip.extra.items[extra.end],
4475 } else .{ .start = 0, .len = 0 } },
4476 } };
4477 } },
41144478
4115 .type_enum_auto => {
4116 const enum_auto = ip.extraDataTrail(EnumAuto, data);
4117 return .{ .enum_type = .{
4118 .decl = enum_auto.data.decl,
4119 .namespace = enum_auto.data.namespace,
4120 .tag_ty = enum_auto.data.int_tag_type,
4121 .names = .{
4122 .start = @intCast(enum_auto.end),
4123 .len = enum_auto.data.fields_len,
4124 },
4125 .values = .{
4126 .start = 0,
4127 .len = 0,
4128 },
4129 .tag_mode = .auto,
4130 .names_map = enum_auto.data.names_map.toOptional(),
4131 .values_map = .none,
4132 .zir_index = enum_auto.data.zir_index,
4479 .type_enum_auto => .{ .enum_type = ns: {
4480 const extra = ip.extraDataTrail(EnumAuto, data);
4481 const zir_index = extra.data.zir_index.unwrap() orelse {
4482 assert(extra.data.captures_len == 0);
4483 break :ns .{ .generated_tag = .{
4484 .union_type = @enumFromInt(ip.extra.items[extra.end]),
4485 } };
4486 };
4487 if (extra.data.captures_len == std.math.maxInt(u32)) {
4488 break :ns .{ .reified = .{
4489 .zir_index = zir_index,
4490 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4491 } };
4492 }
4493 break :ns .{ .declared = .{
4494 .zir_index = zir_index,
4495 .captures = .{ .owned = .{
4496 .start = extra.end,
4497 .len = extra.data.captures_len,
4498 } },
41334499 } };
4134 },
4135 .type_enum_explicit => ip.indexToKeyEnum(data, .explicit),
4136 .type_enum_nonexhaustive => ip.indexToKeyEnum(data, .nonexhaustive),
4500 } },
4501 .type_enum_explicit, .type_enum_nonexhaustive => .{ .enum_type = ns: {
4502 const extra = ip.extraDataTrail(EnumExplicit, data);
4503 const zir_index = extra.data.zir_index.unwrap() orelse {
4504 assert(extra.data.captures_len == 0);
4505 break :ns .{ .generated_tag = .{
4506 .union_type = @enumFromInt(ip.extra.items[extra.end]),
4507 } };
4508 };
4509 if (extra.data.captures_len == std.math.maxInt(u32)) {
4510 break :ns .{ .reified = .{
4511 .zir_index = zir_index,
4512 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4513 } };
4514 }
4515 break :ns .{ .declared = .{
4516 .zir_index = zir_index,
4517 .captures = .{ .owned = .{
4518 .start = extra.end,
4519 .len = extra.data.captures_len,
4520 } },
4521 } };
4522 } },
41374523 .type_function => .{ .func_type = ip.extraFuncType(data) },
41384524
41394525 .undef => .{ .undef = @as(Index, @enumFromInt(data)) },
......@@ -4366,7 +4752,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
43664752 },
43674753 .type_array_small,
43684754 .type_vector,
4369 .type_struct_ns,
43704755 .type_struct_packed,
43714756 => .{ .aggregate = .{
43724757 .ty = ty,
......@@ -4375,16 +4760,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
43754760
43764761 // There is only one possible value precisely due to the
43774762 // fact that this values slice is fully populated!
4378 .type_struct => {
4379 const info = extraStructType(ip, ty_item.data);
4380 return .{ .aggregate = .{
4381 .ty = ty,
4382 .storage = .{ .elems = @ptrCast(info.field_inits.get(ip)) },
4383 } };
4384 },
4385
4386 .type_struct_packed_inits => {
4387 const info = extraPackedStructType(ip, ty_item.data, true);
4763 .type_struct, .type_struct_packed_inits => {
4764 const info = loadStructType(ip, ty);
43884765 return .{ .aggregate = .{
43894766 .ty = ty,
43904767 .storage = .{ .elems = @ptrCast(info.field_inits.get(ip)) },
......@@ -4476,18 +4853,6 @@ fn extraErrorSet(ip: *const InternPool, extra_index: u32) Key.ErrorSetType {
44764853 };
44774854}
44784855
4479fn extraUnionType(ip: *const InternPool, extra_index: u32) Key.UnionType {
4480 const type_union = ip.extraData(Tag.TypeUnion, extra_index);
4481 return .{
4482 .decl = type_union.decl,
4483 .namespace = type_union.namespace,
4484 .flags = type_union.flags,
4485 .enum_tag_ty = type_union.tag_ty,
4486 .zir_index = type_union.zir_index,
4487 .extra_index = extra_index,
4488 };
4489}
4490
44914856fn extraTypeStructAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructType {
44924857 const type_struct_anon = ip.extraDataTrail(TypeStructAnon, extra_index);
44934858 const fields_len = type_struct_anon.data.fields_len;
......@@ -4526,109 +4891,6 @@ fn extraTypeTupleAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructTyp
45264891 };
45274892}
45284893
4529fn extraStructType(ip: *const InternPool, extra_index: u32) Key.StructType {
4530 const s = ip.extraDataTrail(Tag.TypeStruct, extra_index);
4531 const fields_len = s.data.fields_len;
4532
4533 var index = s.end;
4534
4535 const field_types = t: {
4536 const types: Index.Slice = .{ .start = index, .len = fields_len };
4537 index += fields_len;
4538 break :t types;
4539 };
4540 const names_map, const field_names: NullTerminatedString.Slice = t: {
4541 if (s.data.flags.is_tuple) break :t .{ .none, .{ .start = 0, .len = 0 } };
4542 const names_map: MapIndex = @enumFromInt(ip.extra.items[index]);
4543 index += 1;
4544 const names: NullTerminatedString.Slice = .{ .start = index, .len = fields_len };
4545 index += fields_len;
4546 break :t .{ names_map.toOptional(), names };
4547 };
4548 const field_inits: Index.Slice = t: {
4549 if (!s.data.flags.any_default_inits) break :t .{ .start = 0, .len = 0 };
4550 const inits: Index.Slice = .{ .start = index, .len = fields_len };
4551 index += fields_len;
4552 break :t inits;
4553 };
4554 const namespace = t: {
4555 if (!s.data.flags.has_namespace) break :t .none;
4556 const namespace: NamespaceIndex = @enumFromInt(ip.extra.items[index]);
4557 index += 1;
4558 break :t namespace.toOptional();
4559 };
4560 const field_aligns: Alignment.Slice = t: {
4561 if (!s.data.flags.any_aligned_fields) break :t .{ .start = 0, .len = 0 };
4562 const aligns: Alignment.Slice = .{ .start = index, .len = fields_len };
4563 index += (fields_len + 3) / 4;
4564 break :t aligns;
4565 };
4566 const comptime_bits: Key.StructType.ComptimeBits = t: {
4567 if (!s.data.flags.any_comptime_fields) break :t .{ .start = 0, .len = 0 };
4568 const comptime_bits: Key.StructType.ComptimeBits = .{ .start = index, .len = fields_len };
4569 index += (fields_len + 31) / 32;
4570 break :t comptime_bits;
4571 };
4572 const runtime_order: Key.StructType.RuntimeOrder.Slice = t: {
4573 if (s.data.flags.is_extern) break :t .{ .start = 0, .len = 0 };
4574 const ro: Key.StructType.RuntimeOrder.Slice = .{ .start = index, .len = fields_len };
4575 index += fields_len;
4576 break :t ro;
4577 };
4578 const offsets = t: {
4579 const offsets: Key.StructType.Offsets = .{ .start = index, .len = fields_len };
4580 index += fields_len;
4581 break :t offsets;
4582 };
4583 return .{
4584 .extra_index = extra_index,
4585 .decl = s.data.decl.toOptional(),
4586 .zir_index = s.data.zir_index,
4587 .layout = if (s.data.flags.is_extern) .Extern else .Auto,
4588 .field_types = field_types,
4589 .names_map = names_map,
4590 .field_names = field_names,
4591 .field_inits = field_inits,
4592 .namespace = namespace,
4593 .field_aligns = field_aligns,
4594 .comptime_bits = comptime_bits,
4595 .runtime_order = runtime_order,
4596 .offsets = offsets,
4597 };
4598}
4599
4600fn extraPackedStructType(ip: *const InternPool, extra_index: u32, inits: bool) Key.StructType {
4601 const type_struct_packed = ip.extraDataTrail(Tag.TypeStructPacked, extra_index);
4602 const fields_len = type_struct_packed.data.fields_len;
4603 return .{
4604 .extra_index = extra_index,
4605 .decl = type_struct_packed.data.decl.toOptional(),
4606 .namespace = type_struct_packed.data.namespace,
4607 .zir_index = type_struct_packed.data.zir_index,
4608 .layout = .Packed,
4609 .field_types = .{
4610 .start = type_struct_packed.end,
4611 .len = fields_len,
4612 },
4613 .field_names = .{
4614 .start = type_struct_packed.end + fields_len,
4615 .len = fields_len,
4616 },
4617 .field_inits = if (inits) .{
4618 .start = type_struct_packed.end + fields_len * 2,
4619 .len = fields_len,
4620 } else .{
4621 .start = 0,
4622 .len = 0,
4623 },
4624 .field_aligns = .{ .start = 0, .len = 0 },
4625 .runtime_order = .{ .start = 0, .len = 0 },
4626 .comptime_bits = .{ .start = 0, .len = 0 },
4627 .offsets = .{ .start = 0, .len = 0 },
4628 .names_map = type_struct_packed.data.names_map.toOptional(),
4629 };
4630}
4631
46324894fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {
46334895 const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index);
46344896 var index: usize = type_function.end;
......@@ -4720,28 +4982,6 @@ fn extraFuncCoerced(ip: *const InternPool, extra_index: u32) Key.Func {
47204982 return func;
47214983}
47224984
4723fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMode) Key {
4724 const enum_explicit = ip.extraDataTrail(EnumExplicit, data);
4725 const fields_len = enum_explicit.data.fields_len;
4726 return .{ .enum_type = .{
4727 .decl = enum_explicit.data.decl,
4728 .namespace = enum_explicit.data.namespace,
4729 .tag_ty = enum_explicit.data.int_tag_type,
4730 .names = .{
4731 .start = @intCast(enum_explicit.end),
4732 .len = fields_len,
4733 },
4734 .values = .{
4735 .start = @intCast(enum_explicit.end + fields_len),
4736 .len = if (enum_explicit.data.values_map != .none) fields_len else 0,
4737 },
4738 .tag_mode = tag_mode,
4739 .names_map = enum_explicit.data.names_map.toOptional(),
4740 .values_map = enum_explicit.data.values_map,
4741 .zir_index = enum_explicit.data.zir_index,
4742 } };
4743}
4744
47454985fn indexToKeyBigInt(ip: *const InternPool, limb_index: u32, positive: bool) Key {
47464986 const int_info = ip.limbData(Int, limb_index);
47474987 return .{ .int = .{
......@@ -4901,15 +5141,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
49015141 .struct_type => unreachable, // use getStructType() instead
49025142 .anon_struct_type => unreachable, // use getAnonStructType() instead
49035143 .union_type => unreachable, // use getUnionType() instead
5144 .opaque_type => unreachable, // use getOpaqueType() instead
49045145
4905 .opaque_type => |opaque_type| {
4906 ip.items.appendAssumeCapacity(.{
4907 .tag = .type_opaque,
4908 .data = try ip.addExtra(gpa, opaque_type),
4909 });
4910 },
4911
4912 .enum_type => unreachable, // use getEnum() or getIncompleteEnum() instead
5146 .enum_type => unreachable, // use getEnumType() instead
49135147 .func_type => unreachable, // use getFuncType() instead
49145148 .extern_func => unreachable, // use getExternFunc() instead
49155149 .func => unreachable, // use getFuncInstance() or getFuncDecl() instead
......@@ -5027,14 +5261,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
50275261 assert(ptr.addr == .field);
50285262 assert(base_index.index < anon_struct_type.types.len);
50295263 },
5030 .struct_type => |struct_type| {
5264 .struct_type => {
50315265 assert(ptr.addr == .field);
5032 assert(base_index.index < struct_type.field_types.len);
5266 assert(base_index.index < ip.loadStructType(base_ptr_type.child).field_types.len);
50335267 },
5034 .union_type => |union_key| {
5035 const union_type = ip.loadUnionType(union_key);
5268 .union_type => {
5269 const union_type = ip.loadUnionType(base_ptr_type.child);
50365270 assert(ptr.addr == .field);
5037 assert(base_index.index < union_type.field_names.len);
5271 assert(base_index.index < union_type.field_types.len);
50385272 },
50395273 .ptr_type => |slice_type| {
50405274 assert(ptr.addr == .field);
......@@ -5305,7 +5539,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
53055539 assert(ip.isEnumType(enum_tag.ty));
53065540 switch (ip.indexToKey(enum_tag.ty)) {
53075541 .simple_type => assert(ip.isIntegerType(ip.typeOf(enum_tag.int))),
5308 .enum_type => |enum_type| assert(ip.typeOf(enum_tag.int) == enum_type.tag_ty),
5542 .enum_type => assert(ip.typeOf(enum_tag.int) == ip.loadEnumType(enum_tag.ty).tag_ty),
53095543 else => unreachable,
53105544 }
53115545 ip.items.appendAssumeCapacity(.{
......@@ -5398,8 +5632,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
53985632 assert(ip.typeOf(elem) == child);
53995633 }
54005634 },
5401 .struct_type => |t| {
5402 for (aggregate.storage.values(), t.field_types.get(ip)) |elem, field_ty| {
5635 .struct_type => {
5636 for (aggregate.storage.values(), ip.loadStructType(aggregate.ty).field_types.get(ip)) |elem, field_ty| {
54035637 assert(ip.typeOf(elem) == field_ty);
54045638 }
54055639 },
......@@ -5572,10 +5806,17 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
55725806}
55735807
55745808pub const UnionTypeInit = struct {
5575 flags: Tag.TypeUnion.Flags,
5576 decl: DeclIndex,
5577 namespace: NamespaceIndex,
5578 zir_index: TrackedInst.Index.Optional,
5809 flags: packed struct {
5810 runtime_tag: LoadedUnionType.RuntimeTag,
5811 any_aligned_fields: bool,
5812 layout: std.builtin.Type.ContainerLayout,
5813 status: LoadedUnionType.Status,
5814 requires_comptime: RequiresComptime,
5815 assumed_runtime_bits: bool,
5816 assumed_pointer_aligned: bool,
5817 alignment: Alignment,
5818 },
5819 has_namespace: bool,
55795820 fields_len: u32,
55805821 enum_tag_ty: Index,
55815822 /// May have length 0 which leaves the values unset until later.
......@@ -5584,27 +5825,84 @@ pub const UnionTypeInit = struct {
55845825 /// The logic for `any_aligned_fields` is asserted to have been done before
55855826 /// calling this function.
55865827 field_aligns: []const Alignment,
5828 key: union(enum) {
5829 declared: struct {
5830 zir_index: TrackedInst.Index,
5831 captures: []const CaptureValue,
5832 },
5833 reified: struct {
5834 zir_index: TrackedInst.Index,
5835 type_hash: u64,
5836 },
5837 },
55875838};
55885839
5589pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocator.Error!Index {
5590 const prev_extra_len = ip.extra.items.len;
5840pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocator.Error!WipNamespaceType.Result {
5841 const adapter: KeyAdapter = .{ .intern_pool = ip };
5842 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .union_type = switch (ini.key) {
5843 .declared => |d| .{ .declared = .{
5844 .zir_index = d.zir_index,
5845 .captures = .{ .external = d.captures },
5846 } },
5847 .reified => |r| .{ .reified = .{
5848 .zir_index = r.zir_index,
5849 .type_hash = r.type_hash,
5850 } },
5851 } }, adapter);
5852 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };
5853 errdefer _ = ip.map.pop();
5854
55915855 const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;
55925856 const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);
55935857 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeUnion).Struct.fields.len +
5858 // TODO: fmt bug
5859 // zig fmt: off
5860 switch (ini.key) {
5861 .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
5862 .reified => 2, // type_hash: PackedU64
5863 } +
5864 // zig fmt: on
55945865 ini.fields_len + // field types
55955866 align_elements_len);
55965867 try ip.items.ensureUnusedCapacity(gpa, 1);
55975868
5598 const union_type_extra_index = ip.addExtraAssumeCapacity(Tag.TypeUnion{
5599 .flags = ini.flags,
5869 const extra_index = ip.addExtraAssumeCapacity(Tag.TypeUnion{
5870 .flags = .{
5871 .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0,
5872 .runtime_tag = ini.flags.runtime_tag,
5873 .any_aligned_fields = ini.flags.any_aligned_fields,
5874 .layout = ini.flags.layout,
5875 .status = ini.flags.status,
5876 .requires_comptime = ini.flags.requires_comptime,
5877 .assumed_runtime_bits = ini.flags.assumed_runtime_bits,
5878 .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned,
5879 .alignment = ini.flags.alignment,
5880 .is_reified = ini.key == .reified,
5881 },
5882 .fields_len = ini.fields_len,
56005883 .size = std.math.maxInt(u32),
56015884 .padding = std.math.maxInt(u32),
5602 .decl = ini.decl,
5603 .namespace = ini.namespace,
5885 .decl = undefined, // set by `finish`
5886 .namespace = .none, // set by `finish`
56045887 .tag_ty = ini.enum_tag_ty,
5605 .zir_index = ini.zir_index,
5888 .zir_index = switch (ini.key) {
5889 inline else => |x| x.zir_index,
5890 },
5891 });
5892
5893 ip.items.appendAssumeCapacity(.{
5894 .tag = .type_union,
5895 .data = extra_index,
56065896 });
56075897
5898 switch (ini.key) {
5899 .declared => |d| if (d.captures.len != 0) {
5900 ip.extra.appendAssumeCapacity(@intCast(d.captures.len));
5901 ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures));
5902 },
5903 .reified => |r| _ = ip.addExtraAssumeCapacity(PackedU64.init(r.type_hash)),
5904 }
5905
56085906 // field types
56095907 if (ini.field_types.len > 0) {
56105908 assert(ini.field_types.len == ini.fields_len);
......@@ -5627,27 +5925,41 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat
56275925 assert(ini.field_aligns.len == 0);
56285926 }
56295927
5630 const adapter: KeyAdapter = .{ .intern_pool = ip };
5631 const gop = try ip.map.getOrPutAdapted(gpa, Key{
5632 .union_type = extraUnionType(ip, union_type_extra_index),
5633 }, adapter);
5634 if (gop.found_existing) {
5635 ip.extra.items.len = prev_extra_len;
5636 return @enumFromInt(gop.index);
5928 return .{ .wip = .{
5929 .index = @enumFromInt(ip.items.len - 1),
5930 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "decl").?,
5931 .namespace_extra_index = if (ini.has_namespace)
5932 extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?
5933 else
5934 null,
5935 } };
5936}
5937
5938pub const WipNamespaceType = struct {
5939 index: Index,
5940 decl_extra_index: u32,
5941 namespace_extra_index: ?u32,
5942 pub fn finish(wip: WipNamespaceType, ip: *InternPool, decl: DeclIndex, namespace: OptionalNamespaceIndex) Index {
5943 ip.extra.items[wip.decl_extra_index] = @intFromEnum(decl);
5944 if (wip.namespace_extra_index) |i| {
5945 ip.extra.items[i] = @intFromEnum(namespace.unwrap().?);
5946 } else {
5947 assert(namespace == .none);
5948 }
5949 return wip.index;
5950 }
5951 pub fn cancel(wip: WipNamespaceType, ip: *InternPool) void {
5952 ip.remove(wip.index);
56375953 }
56385954
5639 ip.items.appendAssumeCapacity(.{
5640 .tag = .type_union,
5641 .data = union_type_extra_index,
5642 });
5643 return @enumFromInt(ip.items.len - 1);
5644}
5955 pub const Result = union(enum) {
5956 wip: WipNamespaceType,
5957 existing: Index,
5958 };
5959};
56455960
56465961pub const StructTypeInit = struct {
5647 decl: DeclIndex,
5648 namespace: OptionalNamespaceIndex,
56495962 layout: std.builtin.Type.ContainerLayout,
5650 zir_index: TrackedInst.Index.Optional,
56515963 fields_len: u32,
56525964 known_non_opv: bool,
56535965 requires_comptime: RequiresComptime,
......@@ -5656,69 +5968,101 @@ pub const StructTypeInit = struct {
56565968 any_default_inits: bool,
56575969 inits_resolved: bool,
56585970 any_aligned_fields: bool,
5971 has_namespace: bool,
5972 key: union(enum) {
5973 declared: struct {
5974 zir_index: TrackedInst.Index,
5975 captures: []const CaptureValue,
5976 },
5977 reified: struct {
5978 zir_index: TrackedInst.Index,
5979 type_hash: u64,
5980 },
5981 },
56595982};
56605983
56615984pub fn getStructType(
56625985 ip: *InternPool,
56635986 gpa: Allocator,
56645987 ini: StructTypeInit,
5665) Allocator.Error!Index {
5988) Allocator.Error!WipNamespaceType.Result {
56665989 const adapter: KeyAdapter = .{ .intern_pool = ip };
5667 const key: Key = .{
5668 .struct_type = .{
5669 // Only the decl matters for hashing and equality purposes.
5670 .decl = ini.decl.toOptional(),
5671
5672 .extra_index = undefined,
5673 .namespace = undefined,
5674 .zir_index = undefined,
5675 .layout = undefined,
5676 .field_names = undefined,
5677 .field_types = undefined,
5678 .field_inits = undefined,
5679 .field_aligns = undefined,
5680 .runtime_order = undefined,
5681 .comptime_bits = undefined,
5682 .offsets = undefined,
5683 .names_map = undefined,
5684 },
5685 };
5990 const key: Key = .{ .struct_type = switch (ini.key) {
5991 .declared => |d| .{ .declared = .{
5992 .zir_index = d.zir_index,
5993 .captures = .{ .external = d.captures },
5994 } },
5995 .reified => |r| .{ .reified = .{
5996 .zir_index = r.zir_index,
5997 .type_hash = r.type_hash,
5998 } },
5999 } };
56866000 const gop = try ip.map.getOrPutAdapted(gpa, key, adapter);
5687 if (gop.found_existing) return @enumFromInt(gop.index);
6001 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };
56886002 errdefer _ = ip.map.pop();
56896003
56906004 const names_map = try ip.addMap(gpa, ini.fields_len);
56916005 errdefer _ = ip.maps.pop();
56926006
6007 const zir_index = switch (ini.key) {
6008 inline else => |x| x.zir_index,
6009 };
6010
56936011 const is_extern = switch (ini.layout) {
56946012 .Auto => false,
56956013 .Extern => true,
56966014 .Packed => {
56976015 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStructPacked).Struct.fields.len +
6016 // TODO: fmt bug
6017 // zig fmt: off
6018 switch (ini.key) {
6019 .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
6020 .reified => 2, // type_hash: PackedU64
6021 } +
6022 // zig fmt: on
56986023 ini.fields_len + // types
56996024 ini.fields_len + // names
57006025 ini.fields_len); // inits
6026 const extra_index = ip.addExtraAssumeCapacity(Tag.TypeStructPacked{
6027 .decl = undefined, // set by `finish`
6028 .zir_index = zir_index,
6029 .fields_len = ini.fields_len,
6030 .namespace = .none,
6031 .backing_int_ty = .none,
6032 .names_map = names_map,
6033 .flags = .{
6034 .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0,
6035 .field_inits_wip = false,
6036 .inits_resolved = ini.inits_resolved,
6037 .is_reified = ini.key == .reified,
6038 },
6039 });
57016040 try ip.items.append(gpa, .{
57026041 .tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed,
5703 .data = ip.addExtraAssumeCapacity(Tag.TypeStructPacked{
5704 .decl = ini.decl,
5705 .zir_index = ini.zir_index,
5706 .fields_len = ini.fields_len,
5707 .namespace = ini.namespace,
5708 .backing_int_ty = .none,
5709 .names_map = names_map,
5710 .flags = .{
5711 .field_inits_wip = false,
5712 .inits_resolved = ini.inits_resolved,
5713 },
5714 }),
6042 .data = extra_index,
57156043 });
6044 switch (ini.key) {
6045 .declared => |d| if (d.captures.len != 0) {
6046 ip.extra.appendAssumeCapacity(@intCast(d.captures.len));
6047 ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures));
6048 },
6049 .reified => |r| {
6050 _ = ip.addExtraAssumeCapacity(PackedU64.init(r.type_hash));
6051 },
6052 }
57166053 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
57176054 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);
57186055 if (ini.any_default_inits) {
57196056 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
57206057 }
5721 return @enumFromInt(ip.items.len - 1);
6058 return .{ .wip = .{
6059 .index = @enumFromInt(ip.items.len - 1),
6060 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "decl").?,
6061 .namespace_extra_index = if (ini.has_namespace)
6062 extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?
6063 else
6064 null,
6065 } };
57226066 },
57236067 };
57246068
......@@ -5727,38 +6071,57 @@ pub fn getStructType(
57276071 const comptime_elements_len = if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0;
57286072
57296073 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStruct).Struct.fields.len +
6074 // TODO: fmt bug
6075 // zig fmt: off
6076 switch (ini.key) {
6077 .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
6078 .reified => 2, // type_hash: PackedU64
6079 } +
6080 // zig fmt: on
57306081 (ini.fields_len * 5) + // types, names, inits, runtime order, offsets
57316082 align_elements_len + comptime_elements_len +
57326083 2); // names_map + namespace
6084 const extra_index = ip.addExtraAssumeCapacity(Tag.TypeStruct{
6085 .decl = undefined, // set by `finish`
6086 .zir_index = zir_index,
6087 .fields_len = ini.fields_len,
6088 .size = std.math.maxInt(u32),
6089 .flags = .{
6090 .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0,
6091 .is_extern = is_extern,
6092 .known_non_opv = ini.known_non_opv,
6093 .requires_comptime = ini.requires_comptime,
6094 .is_tuple = ini.is_tuple,
6095 .assumed_runtime_bits = false,
6096 .assumed_pointer_aligned = false,
6097 .has_namespace = ini.has_namespace,
6098 .any_comptime_fields = ini.any_comptime_fields,
6099 .any_default_inits = ini.any_default_inits,
6100 .any_aligned_fields = ini.any_aligned_fields,
6101 .alignment = .none,
6102 .alignment_wip = false,
6103 .field_types_wip = false,
6104 .layout_wip = false,
6105 .layout_resolved = false,
6106 .field_inits_wip = false,
6107 .inits_resolved = ini.inits_resolved,
6108 .fully_resolved = false,
6109 .is_reified = ini.key == .reified,
6110 },
6111 });
57336112 try ip.items.append(gpa, .{
57346113 .tag = .type_struct,
5735 .data = ip.addExtraAssumeCapacity(Tag.TypeStruct{
5736 .decl = ini.decl,
5737 .zir_index = ini.zir_index,
5738 .fields_len = ini.fields_len,
5739 .size = std.math.maxInt(u32),
5740 .flags = .{
5741 .is_extern = is_extern,
5742 .known_non_opv = ini.known_non_opv,
5743 .requires_comptime = ini.requires_comptime,
5744 .is_tuple = ini.is_tuple,
5745 .assumed_runtime_bits = false,
5746 .assumed_pointer_aligned = false,
5747 .has_namespace = ini.namespace != .none,
5748 .any_comptime_fields = ini.any_comptime_fields,
5749 .any_default_inits = ini.any_default_inits,
5750 .any_aligned_fields = ini.any_aligned_fields,
5751 .alignment = .none,
5752 .alignment_wip = false,
5753 .field_types_wip = false,
5754 .layout_wip = false,
5755 .layout_resolved = false,
5756 .field_inits_wip = false,
5757 .inits_resolved = ini.inits_resolved,
5758 .fully_resolved = false,
5759 },
5760 }),
6114 .data = extra_index,
57616115 });
6116 switch (ini.key) {
6117 .declared => |d| if (d.captures.len != 0) {
6118 ip.extra.appendAssumeCapacity(@intCast(d.captures.len));
6119 ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures));
6120 },
6121 .reified => |r| {
6122 _ = ip.addExtraAssumeCapacity(PackedU64.init(r.type_hash));
6123 },
6124 }
57626125 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
57636126 if (!ini.is_tuple) {
57646127 ip.extra.appendAssumeCapacity(@intFromEnum(names_map));
......@@ -5767,9 +6130,10 @@ pub fn getStructType(
57676130 if (ini.any_default_inits) {
57686131 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
57696132 }
5770 if (ini.namespace.unwrap()) |namespace| {
5771 ip.extra.appendAssumeCapacity(@intFromEnum(namespace));
5772 }
6133 const namespace_extra_index: ?u32 = if (ini.has_namespace) i: {
6134 ip.extra.appendAssumeCapacity(undefined); // set by `finish`
6135 break :i @intCast(ip.extra.items.len - 1);
6136 } else null;
57736137 if (ini.any_aligned_fields) {
57746138 ip.extra.appendNTimesAssumeCapacity(align_element, align_elements_len);
57756139 }
......@@ -5777,10 +6141,14 @@ pub fn getStructType(
57776141 ip.extra.appendNTimesAssumeCapacity(0, comptime_elements_len);
57786142 }
57796143 if (ini.layout == .Auto) {
5780 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Key.StructType.RuntimeOrder.unresolved), ini.fields_len);
6144 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(LoadedStructType.RuntimeOrder.unresolved), ini.fields_len);
57816145 }
57826146 ip.extra.appendNTimesAssumeCapacity(std.math.maxInt(u32), ini.fields_len);
5783 return @enumFromInt(ip.items.len - 1);
6147 return .{ .wip = .{
6148 .index = @enumFromInt(ip.items.len - 1),
6149 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "decl").?,
6150 .namespace_extra_index = namespace_extra_index,
6151 } };
57846152}
57856153
57866154pub const AnonStructTypeInit = struct {
......@@ -6395,7 +6763,6 @@ fn finishFuncInstance(
63956763 .@"addrspace" = fn_owner_decl.@"addrspace",
63966764 .analysis = .complete,
63976765 .zir_decl_index = fn_owner_decl.zir_decl_index,
6398 .src_scope = fn_owner_decl.src_scope,
63996766 .is_pub = fn_owner_decl.is_pub,
64006767 .is_exported = fn_owner_decl.is_exported,
64016768 .alive = true,
......@@ -6417,257 +6784,386 @@ fn finishFuncInstance(
64176784 return func_index;
64186785}
64196786
6420/// Provides API for completing an enum type after calling `getIncompleteEnum`.
6421pub const IncompleteEnumType = struct {
6787pub const EnumTypeInit = struct {
6788 has_namespace: bool,
6789 has_values: bool,
6790 tag_mode: LoadedEnumType.TagMode,
6791 fields_len: u32,
6792 key: union(enum) {
6793 declared: struct {
6794 zir_index: TrackedInst.Index,
6795 captures: []const CaptureValue,
6796 },
6797 reified: struct {
6798 zir_index: TrackedInst.Index,
6799 type_hash: u64,
6800 },
6801 },
6802};
6803
6804pub const WipEnumType = struct {
64226805 index: Index,
64236806 tag_ty_index: u32,
6807 decl_index: u32,
6808 namespace_index: ?u32,
64246809 names_map: MapIndex,
64256810 names_start: u32,
64266811 values_map: OptionalMapIndex,
64276812 values_start: u32,
64286813
6429 pub fn setTagType(self: @This(), ip: *InternPool, tag_ty: Index) void {
6430 assert(tag_ty == .noreturn_type or ip.isIntegerType(tag_ty));
6431 ip.extra.items[self.tag_ty_index] = @intFromEnum(tag_ty);
6814 pub fn prepare(
6815 wip: WipEnumType,
6816 ip: *InternPool,
6817 decl: DeclIndex,
6818 namespace: OptionalNamespaceIndex,
6819 ) void {
6820 ip.extra.items[wip.decl_index] = @intFromEnum(decl);
6821 if (wip.namespace_index) |i| {
6822 ip.extra.items[i] = @intFromEnum(namespace.unwrap().?);
6823 } else {
6824 assert(namespace == .none);
6825 }
64326826 }
64336827
6434 /// Returns the already-existing field with the same name, if any.
6435 pub fn addFieldName(
6436 self: @This(),
6437 ip: *InternPool,
6438 name: NullTerminatedString,
6439 ) ?u32 {
6440 return ip.addFieldName(self.names_map, self.names_start, name);
6828 pub fn setTagTy(wip: WipEnumType, ip: *InternPool, tag_ty: Index) void {
6829 assert(ip.isIntegerType(tag_ty));
6830 ip.extra.items[wip.tag_ty_index] = @intFromEnum(tag_ty);
64416831 }
64426832
6443 /// Returns the already-existing field with the same value, if any.
6444 /// Make sure the type of the value has the integer tag type of the enum.
6445 pub fn addFieldValue(
6446 self: @This(),
6447 ip: *InternPool,
6448 value: Index,
6449 ) ?u32 {
6450 assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[self.tag_ty_index])));
6451 const map = &ip.maps.items[@intFromEnum(self.values_map.unwrap().?)];
6833 pub const FieldConflict = struct {
6834 kind: enum { name, value },
6835 prev_field_idx: u32,
6836 };
6837
6838 /// Returns the already-existing field with the same name or value, if any.
6839 /// If the enum is automatially numbered, `value` must be `.none`.
6840 /// Otherwise, the type of `value` must be the integer tag type of the enum.
6841 pub fn nextField(wip: WipEnumType, ip: *InternPool, name: NullTerminatedString, value: Index) ?FieldConflict {
6842 if (ip.addFieldName(wip.names_map, wip.names_start, name)) |conflict| {
6843 return .{ .kind = .name, .prev_field_idx = conflict };
6844 }
6845 if (value == .none) {
6846 assert(wip.values_map == .none);
6847 return null;
6848 }
6849 assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[wip.tag_ty_index])));
6850 const map = &ip.maps.items[@intFromEnum(wip.values_map.unwrap().?)];
64526851 const field_index = map.count();
6453 const indexes = ip.extra.items[self.values_start..][0..field_index];
6852 const indexes = ip.extra.items[wip.values_start..][0..field_index];
64546853 const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) };
64556854 const gop = map.getOrPutAssumeCapacityAdapted(value, adapter);
6456 if (gop.found_existing) return @intCast(gop.index);
6457 ip.extra.items[self.values_start + field_index] = @intFromEnum(value);
6855 if (gop.found_existing) {
6856 return .{ .kind = .value, .prev_field_idx = @intCast(gop.index) };
6857 }
6858 ip.extra.items[wip.values_start + field_index] = @intFromEnum(value);
64586859 return null;
64596860 }
6460};
64616861
6462/// This is used to create an enum type in the `InternPool`, with the ability
6463/// to update the tag type, field names, and field values later.
6464pub fn getIncompleteEnum(
6465 ip: *InternPool,
6466 gpa: Allocator,
6467 enum_type: Key.IncompleteEnumType,
6468) Allocator.Error!IncompleteEnumType {
6469 switch (enum_type.tag_mode) {
6470 .auto => return getIncompleteEnumAuto(ip, gpa, enum_type),
6471 .explicit => return getIncompleteEnumExplicit(ip, gpa, enum_type, .type_enum_explicit),
6472 .nonexhaustive => return getIncompleteEnumExplicit(ip, gpa, enum_type, .type_enum_nonexhaustive),
6862 pub fn cancel(wip: WipEnumType, ip: *InternPool) void {
6863 ip.remove(wip.index);
64736864 }
6474}
6475
6476fn getIncompleteEnumAuto(
6477 ip: *InternPool,
6478 gpa: Allocator,
6479 enum_type: Key.IncompleteEnumType,
6480) Allocator.Error!IncompleteEnumType {
6481 const int_tag_type = if (enum_type.tag_ty != .none)
6482 enum_type.tag_ty
6483 else
6484 try ip.get(gpa, .{ .int_type = .{
6485 .bits = if (enum_type.fields_len == 0) 0 else std.math.log2_int_ceil(u32, enum_type.fields_len),
6486 .signedness = .unsigned,
6487 } });
6488
6489 // We must keep the map in sync with `items`. The hash and equality functions
6490 // for enum types only look at the decl field, which is present even in
6491 // an `IncompleteEnumType`.
6492 const adapter: KeyAdapter = .{ .intern_pool = ip };
6493 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
6494 assert(!gop.found_existing);
6495
6496 const names_map = try ip.addMap(gpa, enum_type.fields_len);
6497
6498 const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len;
6499 try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.fields_len);
6500 try ip.items.ensureUnusedCapacity(gpa, 1);
6501
6502 const extra_index = ip.addExtraAssumeCapacity(EnumAuto{
6503 .decl = enum_type.decl,
6504 .namespace = enum_type.namespace,
6505 .int_tag_type = int_tag_type,
6506 .names_map = names_map,
6507 .fields_len = enum_type.fields_len,
6508 .zir_index = enum_type.zir_index,
6509 });
65106865
6511 ip.items.appendAssumeCapacity(.{
6512 .tag = .type_enum_auto,
6513 .data = extra_index,
6514 });
6515 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), enum_type.fields_len);
6516 return .{
6517 .index = @enumFromInt(ip.items.len - 1),
6518 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
6519 .names_map = names_map,
6520 .names_start = extra_index + extra_fields_len,
6521 .values_map = .none,
6522 .values_start = undefined,
6866 pub const Result = union(enum) {
6867 wip: WipEnumType,
6868 existing: Index,
65236869 };
6524}
6870};
65256871
6526fn getIncompleteEnumExplicit(
6872pub fn getEnumType(
65276873 ip: *InternPool,
65286874 gpa: Allocator,
6529 enum_type: Key.IncompleteEnumType,
6530 tag: Tag,
6531) Allocator.Error!IncompleteEnumType {
6532 // We must keep the map in sync with `items`. The hash and equality functions
6533 // for enum types only look at the decl field, which is present even in
6534 // an `IncompleteEnumType`.
6875 ini: EnumTypeInit,
6876) Allocator.Error!WipEnumType.Result {
65356877 const adapter: KeyAdapter = .{ .intern_pool = ip };
6536 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
6537 assert(!gop.found_existing);
6538
6539 const names_map = try ip.addMap(gpa, enum_type.fields_len);
6540 const values_map: OptionalMapIndex = if (!enum_type.has_values) .none else m: {
6541 const values_map = try ip.addMap(gpa, enum_type.fields_len);
6542 break :m values_map.toOptional();
6543 };
6544
6545 const reserved_len = enum_type.fields_len +
6546 if (enum_type.has_values) enum_type.fields_len else 0;
6878 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .enum_type = switch (ini.key) {
6879 .declared => |d| .{ .declared = .{
6880 .zir_index = d.zir_index,
6881 .captures = .{ .external = d.captures },
6882 } },
6883 .reified => |r| .{ .reified = .{
6884 .zir_index = r.zir_index,
6885 .type_hash = r.type_hash,
6886 } },
6887 } }, adapter);
6888 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };
6889 assert(gop.index == ip.items.len);
6890 errdefer _ = ip.map.pop();
65476891
6548 const extra_fields_len: u32 = @typeInfo(EnumExplicit).Struct.fields.len;
6549 try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + reserved_len);
65506892 try ip.items.ensureUnusedCapacity(gpa, 1);
65516893
6552 const extra_index = ip.addExtraAssumeCapacity(EnumExplicit{
6553 .decl = enum_type.decl,
6554 .namespace = enum_type.namespace,
6555 .int_tag_type = enum_type.tag_ty,
6556 .fields_len = enum_type.fields_len,
6557 .names_map = names_map,
6558 .values_map = values_map,
6559 .zir_index = enum_type.zir_index,
6560 });
6894 const names_map = try ip.addMap(gpa, ini.fields_len);
6895 errdefer _ = ip.maps.pop();
65616896
6562 ip.items.appendAssumeCapacity(.{
6563 .tag = tag,
6564 .data = extra_index,
6565 });
6566 // This is both fields and values (if present).
6567 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), reserved_len);
6568 return .{
6569 .index = @enumFromInt(ip.items.len - 1),
6570 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,
6571 .names_map = names_map,
6572 .names_start = extra_index + extra_fields_len,
6573 .values_map = values_map,
6574 .values_start = extra_index + extra_fields_len + enum_type.fields_len,
6575 };
6897 switch (ini.tag_mode) {
6898 .auto => {
6899 assert(!ini.has_values);
6900 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
6901 // TODO: fmt bug
6902 // zig fmt: off
6903 switch (ini.key) {
6904 .declared => |d| d.captures.len,
6905 .reified => 2, // type_hash: PackedU64
6906 } +
6907 // zig fmt: on
6908 ini.fields_len); // field types
6909
6910 const extra_index = ip.addExtraAssumeCapacity(EnumAuto{
6911 .decl = undefined, // set by `prepare`
6912 .captures_len = switch (ini.key) {
6913 .declared => |d| @intCast(d.captures.len),
6914 .reified => std.math.maxInt(u32),
6915 },
6916 .namespace = .none,
6917 .int_tag_type = .none, // set by `prepare`
6918 .fields_len = ini.fields_len,
6919 .names_map = names_map,
6920 .zir_index = switch (ini.key) {
6921 inline else => |x| x.zir_index,
6922 }.toOptional(),
6923 });
6924 ip.items.appendAssumeCapacity(.{
6925 .tag = .type_enum_auto,
6926 .data = extra_index,
6927 });
6928 switch (ini.key) {
6929 .declared => |d| ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures)),
6930 .reified => |r| _ = ip.addExtraAssumeCapacity(PackedU64.init(r.type_hash)),
6931 }
6932 const names_start = ip.extra.items.len;
6933 ip.extra.appendNTimesAssumeCapacity(undefined, ini.fields_len);
6934 return .{ .wip = .{
6935 .index = @enumFromInt(gop.index),
6936 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
6937 .decl_index = extra_index + std.meta.fieldIndex(EnumAuto, "decl").?,
6938 .namespace_index = if (ini.has_namespace) extra_index + std.meta.fieldIndex(EnumAuto, "namespace").? else null,
6939 .names_map = names_map,
6940 .names_start = @intCast(names_start),
6941 .values_map = .none,
6942 .values_start = undefined,
6943 } };
6944 },
6945 .explicit, .nonexhaustive => {
6946 const values_map: OptionalMapIndex = if (!ini.has_values) .none else m: {
6947 const values_map = try ip.addMap(gpa, ini.fields_len);
6948 break :m values_map.toOptional();
6949 };
6950 errdefer if (ini.has_values) {
6951 _ = ip.map.pop();
6952 };
6953
6954 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +
6955 // TODO: fmt bug
6956 // zig fmt: off
6957 switch (ini.key) {
6958 .declared => |d| d.captures.len,
6959 .reified => 2, // type_hash: PackedU64
6960 } +
6961 // zig fmt: on
6962 ini.fields_len + // field types
6963 ini.fields_len * @intFromBool(ini.has_values)); // field values
6964
6965 const extra_index = ip.addExtraAssumeCapacity(EnumExplicit{
6966 .decl = undefined, // set by `prepare`
6967 .captures_len = switch (ini.key) {
6968 .declared => |d| @intCast(d.captures.len),
6969 .reified => std.math.maxInt(u32),
6970 },
6971 .namespace = .none,
6972 .int_tag_type = .none, // set by `prepare`
6973 .fields_len = ini.fields_len,
6974 .names_map = names_map,
6975 .values_map = values_map,
6976 .zir_index = switch (ini.key) {
6977 inline else => |x| x.zir_index,
6978 }.toOptional(),
6979 });
6980 ip.items.appendAssumeCapacity(.{
6981 .tag = switch (ini.tag_mode) {
6982 .auto => unreachable,
6983 .explicit => .type_enum_explicit,
6984 .nonexhaustive => .type_enum_nonexhaustive,
6985 },
6986 .data = extra_index,
6987 });
6988 switch (ini.key) {
6989 .declared => |d| ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures)),
6990 .reified => |r| _ = ip.addExtraAssumeCapacity(PackedU64.init(r.type_hash)),
6991 }
6992 const names_start = ip.extra.items.len;
6993 ip.extra.appendNTimesAssumeCapacity(undefined, ini.fields_len);
6994 const values_start = ip.extra.items.len;
6995 if (ini.has_values) {
6996 ip.extra.appendNTimesAssumeCapacity(undefined, ini.fields_len);
6997 }
6998 return .{ .wip = .{
6999 .index = @enumFromInt(gop.index),
7000 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
7001 .decl_index = extra_index + std.meta.fieldIndex(EnumAuto, "decl").?,
7002 .namespace_index = if (ini.has_namespace) extra_index + std.meta.fieldIndex(EnumAuto, "namespace").? else null,
7003 .names_map = names_map,
7004 .names_start = @intCast(names_start),
7005 .values_map = values_map,
7006 .values_start = @intCast(values_start),
7007 } };
7008 },
7009 }
65767010}
65777011
6578pub const GetEnumInit = struct {
7012const GeneratedTagEnumTypeInit = struct {
65797013 decl: DeclIndex,
6580 namespace: OptionalNamespaceIndex,
7014 owner_union_ty: Index,
65817015 tag_ty: Index,
65827016 names: []const NullTerminatedString,
65837017 values: []const Index,
6584 tag_mode: Key.EnumType.TagMode,
6585 zir_index: TrackedInst.Index.Optional,
7018 tag_mode: LoadedEnumType.TagMode,
65867019};
65877020
6588pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Error!Index {
6589 const adapter: KeyAdapter = .{ .intern_pool = ip };
6590 const gop = try ip.map.getOrPutAdapted(gpa, Key{
6591 .enum_type = .{
6592 // Only the decl is used for hashing and equality.
6593 .decl = ini.decl,
6594
6595 .namespace = undefined,
6596 .tag_ty = undefined,
6597 .names = undefined,
6598 .values = undefined,
6599 .tag_mode = undefined,
6600 .names_map = undefined,
6601 .values_map = undefined,
6602 .zir_index = undefined,
6603 },
6604 }, adapter);
6605 if (gop.found_existing) return @enumFromInt(gop.index);
6606 errdefer _ = ip.map.pop();
7021/// Creates an enum type which was automatically-generated as the tag type of a
7022/// `union` with no explicit tag type. Since this is only called once per union
7023/// type, it asserts that no matching type yet exists.
7024pub fn getGeneratedTagEnumType(ip: *InternPool, gpa: Allocator, ini: GeneratedTagEnumTypeInit) Allocator.Error!Index {
7025 assert(ip.isUnion(ini.owner_union_ty));
7026 assert(ip.isIntegerType(ini.tag_ty));
7027 for (ini.values) |val| assert(ip.typeOf(val) == ini.tag_ty);
7028
7029 try ip.map.ensureUnusedCapacity(gpa, 1);
66077030 try ip.items.ensureUnusedCapacity(gpa, 1);
66087031
6609 assert(ini.tag_ty == .noreturn_type or ip.isIntegerType(ini.tag_ty));
6610 for (ini.values) |value| assert(ip.typeOf(value) == ini.tag_ty);
7032 const names_map = try ip.addMap(gpa, ini.names.len);
7033 errdefer _ = ip.maps.pop();
7034 ip.addStringsToMap(names_map, ini.names);
7035
7036 const fields_len: u32 = @intCast(ini.names.len);
66117037
66127038 switch (ini.tag_mode) {
66137039 .auto => {
6614 const names_map = try ip.addMap(gpa, ini.names.len);
6615 addStringsToMap(ip, names_map, ini.names);
6616
6617 const fields_len: u32 = @intCast(ini.names.len);
66187040 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
6619 fields_len);
7041 1 + // owner_union
7042 fields_len); // field names
66207043 ip.items.appendAssumeCapacity(.{
66217044 .tag = .type_enum_auto,
66227045 .data = ip.addExtraAssumeCapacity(EnumAuto{
66237046 .decl = ini.decl,
6624 .namespace = ini.namespace,
7047 .captures_len = 0,
7048 .namespace = .none,
66257049 .int_tag_type = ini.tag_ty,
7050 .fields_len = fields_len,
66267051 .names_map = names_map,
7052 .zir_index = .none,
7053 }),
7054 });
7055 ip.extra.appendAssumeCapacity(@intFromEnum(ini.owner_union_ty));
7056 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
7057 },
7058 .explicit, .nonexhaustive => {
7059 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +
7060 1 + // owner_union
7061 fields_len + // field names
7062 ini.values.len); // field values
7063
7064 const values_map: OptionalMapIndex = if (ini.values.len != 0) m: {
7065 const map = try ip.addMap(gpa, ini.values.len);
7066 addIndexesToMap(ip, map, ini.values);
7067 break :m map.toOptional();
7068 } else .none;
7069 // We don't clean up the values map on error!
7070 errdefer @compileError("error path leaks values_map");
7071
7072 ip.items.appendAssumeCapacity(.{
7073 .tag = switch (ini.tag_mode) {
7074 .explicit => .type_enum_explicit,
7075 .nonexhaustive => .type_enum_nonexhaustive,
7076 .auto => unreachable,
7077 },
7078 .data = ip.addExtraAssumeCapacity(EnumExplicit{
7079 .decl = ini.decl,
7080 .captures_len = 0,
7081 .namespace = .none,
7082 .int_tag_type = ini.tag_ty,
66277083 .fields_len = fields_len,
6628 .zir_index = ini.zir_index,
7084 .names_map = names_map,
7085 .values_map = values_map,
7086 .zir_index = .none,
66297087 }),
66307088 });
7089 ip.extra.appendAssumeCapacity(@intFromEnum(ini.owner_union_ty));
66317090 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
6632 return @enumFromInt(ip.items.len - 1);
7091 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));
66337092 },
6634 .explicit => return finishGetEnum(ip, gpa, ini, .type_enum_explicit),
6635 .nonexhaustive => return finishGetEnum(ip, gpa, ini, .type_enum_nonexhaustive),
66367093 }
7094 // Same as above
7095 errdefer @compileError("error path leaks values_map and extra data");
7096
7097 // Capacity for this was ensured earlier
7098 const adapter: KeyAdapter = .{ .intern_pool = ip };
7099 const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{ .enum_type = .{
7100 .generated_tag = .{ .union_type = ini.owner_union_ty },
7101 } }, adapter);
7102 assert(!gop.found_existing);
7103 assert(gop.index == ip.items.len - 1);
7104 return @enumFromInt(gop.index);
66377105}
66387106
6639pub fn finishGetEnum(
6640 ip: *InternPool,
6641 gpa: Allocator,
6642 ini: GetEnumInit,
6643 tag: Tag,
6644) Allocator.Error!Index {
6645 const names_map = try ip.addMap(gpa, ini.names.len);
6646 addStringsToMap(ip, names_map, ini.names);
7107pub const OpaqueTypeIni = struct {
7108 has_namespace: bool,
7109 key: union(enum) {
7110 declared: struct {
7111 zir_index: TrackedInst.Index,
7112 captures: []const CaptureValue,
7113 },
7114 reified: struct {
7115 zir_index: TrackedInst.Index,
7116 // No type hash since reifid opaques have no data other than the `@Type` location
7117 },
7118 },
7119};
66477120
6648 const values_map: OptionalMapIndex = if (ini.values.len == 0) .none else m: {
6649 const values_map = try ip.addMap(gpa, ini.values.len);
6650 addIndexesToMap(ip, values_map, ini.values);
6651 break :m values_map.toOptional();
6652 };
6653 const fields_len: u32 = @intCast(ini.names.len);
6654 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +
6655 fields_len);
7121pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, ini: OpaqueTypeIni) Allocator.Error!WipNamespaceType.Result {
7122 const adapter: KeyAdapter = .{ .intern_pool = ip };
7123 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .opaque_type = switch (ini.key) {
7124 .declared => |d| .{ .declared = .{
7125 .zir_index = d.zir_index,
7126 .captures = .{ .external = d.captures },
7127 } },
7128 .reified => |r| .{ .reified = .{
7129 .zir_index = r.zir_index,
7130 .type_hash = 0,
7131 } },
7132 } }, adapter);
7133 if (gop.found_existing) return .{ .existing = @enumFromInt(gop.index) };
7134 errdefer _ = ip.map.pop();
7135 try ip.items.ensureUnusedCapacity(gpa, 1);
7136 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeOpaque).Struct.fields.len + switch (ini.key) {
7137 .declared => |d| d.captures.len,
7138 .reified => 0,
7139 });
7140 const extra_index = ip.addExtraAssumeCapacity(Tag.TypeOpaque{
7141 .decl = undefined, // set by `finish`
7142 .namespace = .none,
7143 .zir_index = switch (ini.key) {
7144 inline else => |x| x.zir_index,
7145 },
7146 .captures_len = switch (ini.key) {
7147 .declared => |d| @intCast(d.captures.len),
7148 .reified => std.math.maxInt(u32),
7149 },
7150 });
66567151 ip.items.appendAssumeCapacity(.{
6657 .tag = tag,
6658 .data = ip.addExtraAssumeCapacity(EnumExplicit{
6659 .decl = ini.decl,
6660 .namespace = ini.namespace,
6661 .int_tag_type = ini.tag_ty,
6662 .fields_len = fields_len,
6663 .names_map = names_map,
6664 .values_map = values_map,
6665 .zir_index = ini.zir_index,
6666 }),
7152 .tag = .type_opaque,
7153 .data = extra_index,
66677154 });
6668 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
6669 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));
6670 return @enumFromInt(ip.items.len - 1);
7155 switch (ini.key) {
7156 .declared => |d| ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures)),
7157 .reified => {},
7158 }
7159 return .{ .wip = .{
7160 .index = @enumFromInt(gop.index),
7161 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "decl").?,
7162 .namespace_extra_index = if (ini.has_namespace)
7163 extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?
7164 else
7165 null,
7166 } };
66717167}
66727168
66737169pub fn getIfExists(ip: *const InternPool, key: Key) ?Index {
......@@ -6716,8 +7212,34 @@ fn addMap(ip: *InternPool, gpa: Allocator, cap: usize) Allocator.Error!MapIndex
67167212
67177213/// This operation only happens under compile error conditions.
67187214/// Leak the index until the next garbage collection.
6719/// TODO: this is a bit problematic to implement, can we get away without it?
6720pub const remove = @compileError("InternPool.remove is not currently a supported operation; put a TODO there instead");
7215/// Invalidates all references to this index.
7216pub fn remove(ip: *InternPool, index: Index) void {
7217 if (@intFromEnum(index) < static_keys.len) {
7218 // The item being removed replaced a special index via `InternPool.resolveBuiltinType`.
7219 // Restore the original item at this index.
7220 switch (static_keys[@intFromEnum(index)]) {
7221 .simple_type => |s| {
7222 ip.items.set(@intFromEnum(index), .{
7223 .tag = .simple_type,
7224 .data = @intFromEnum(s),
7225 });
7226 },
7227 else => unreachable,
7228 }
7229 return;
7230 }
7231
7232 if (@intFromEnum(index) == ip.items.len - 1) {
7233 // Happy case - we can just drop the item without affecting any other indices.
7234 ip.items.len -= 1;
7235 _ = ip.map.pop();
7236 } else {
7237 // We must preserve the item so that indices following it remain valid.
7238 // Thus, we will rewrite the tag to `removed`, leaking the item until
7239 // next GC but causing `KeyAdapter` to ignore it.
7240 ip.items.set(@intFromEnum(index), .{ .tag = .removed, .data = undefined });
7241 }
7242}
67217243
67227244fn addInt(ip: *InternPool, gpa: Allocator, ty: Index, tag: Tag, limbs: []const Limb) !void {
67237245 const limbs_len = @as(u32, @intCast(limbs.len));
......@@ -7077,9 +7599,9 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
70777599 .func => unreachable,
70787600
70797601 .int => |int| switch (ip.indexToKey(new_ty)) {
7080 .enum_type => |enum_type| return ip.get(gpa, .{ .enum_tag = .{
7602 .enum_type => return ip.get(gpa, .{ .enum_tag = .{
70817603 .ty = new_ty,
7082 .int = try ip.getCoerced(gpa, val, enum_type.tag_ty),
7604 .int = try ip.getCoerced(gpa, val, ip.loadEnumType(new_ty).tag_ty),
70837605 } }),
70847606 .ptr_type => return ip.get(gpa, .{ .ptr = .{
70857607 .ty = new_ty,
......@@ -7108,7 +7630,8 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
71087630 .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))
71097631 return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty),
71107632 .enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) {
7111 .enum_type => |enum_type| {
7633 .enum_type => {
7634 const enum_type = ip.loadEnumType(new_ty);
71127635 const index = enum_type.nameIndex(ip, enum_literal).?;
71137636 return ip.get(gpa, .{ .enum_tag = .{
71147637 .ty = new_ty,
......@@ -7249,7 +7772,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
72497772 const new_elem_ty = switch (ip.indexToKey(new_ty)) {
72507773 inline .array_type, .vector_type => |seq_type| seq_type.child,
72517774 .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[i],
7252 .struct_type => |struct_type| struct_type.field_types.get(ip)[i],
7775 .struct_type => ip.loadStructType(new_ty).field_types.get(ip)[i],
72537776 else => unreachable,
72547777 };
72557778 elem.* = try ip.getCoerced(gpa, elem.*, new_elem_ty);
......@@ -7513,6 +8036,10 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
75138036 if (!gop.found_existing) gop.value_ptr.* = .{};
75148037 gop.value_ptr.count += 1;
75158038 gop.value_ptr.bytes += 1 + 4 + @as(usize, switch (tag) {
8039 // Note that in this case, we have technically leaked some extra data
8040 // bytes which we do not account for here.
8041 .removed => 0,
8042
75168043 .type_int_signed => 0,
75178044 .type_int_unsigned => 0,
75188045 .type_array_small => @sizeOf(Vector),
......@@ -7529,12 +8056,31 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
75298056 break :b @sizeOf(Tag.ErrorSet) + (@sizeOf(u32) * info.names_len);
75308057 },
75318058 .type_inferred_error_set => 0,
7532 .type_enum_explicit, .type_enum_nonexhaustive => @sizeOf(EnumExplicit),
7533 .type_enum_auto => @sizeOf(EnumAuto),
7534 .type_opaque => @sizeOf(Key.OpaqueType),
8059 .type_enum_explicit, .type_enum_nonexhaustive => b: {
8060 const info = ip.extraData(EnumExplicit, data);
8061 var ints = @typeInfo(EnumExplicit).Struct.fields.len + info.captures_len + info.fields_len;
8062 if (info.values_map != .none) ints += info.fields_len;
8063 break :b @sizeOf(u32) * ints;
8064 },
8065 .type_enum_auto => b: {
8066 const info = ip.extraData(EnumAuto, data);
8067 const ints = @typeInfo(EnumAuto).Struct.fields.len + info.captures_len + info.fields_len;
8068 break :b @sizeOf(u32) * ints;
8069 },
8070 .type_opaque => b: {
8071 const info = ip.extraData(Tag.TypeOpaque, data);
8072 const ints = @typeInfo(Tag.TypeOpaque).Struct.fields.len + info.captures_len;
8073 break :b @sizeOf(u32) * ints;
8074 },
75358075 .type_struct => b: {
7536 const info = ip.extraData(Tag.TypeStruct, data);
8076 if (data == 0) break :b 0;
8077 const extra = ip.extraDataTrail(Tag.TypeStruct, data);
8078 const info = extra.data;
75378079 var ints: usize = @typeInfo(Tag.TypeStruct).Struct.fields.len;
8080 if (info.flags.any_captures) {
8081 const captures_len = ip.extra.items[extra.end];
8082 ints += 1 + captures_len;
8083 }
75388084 ints += info.fields_len; // types
75398085 if (!info.flags.is_tuple) {
75408086 ints += 1; // names_map
......@@ -7552,20 +8098,29 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
75528098 ints += info.fields_len; // offsets
75538099 break :b @sizeOf(u32) * ints;
75548100 },
7555 .type_struct_ns => @sizeOf(Module.Namespace),
75568101 .type_struct_anon => b: {
75578102 const info = ip.extraData(TypeStructAnon, data);
75588103 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len);
75598104 },
75608105 .type_struct_packed => b: {
7561 const info = ip.extraData(Tag.TypeStructPacked, data);
8106 const extra = ip.extraDataTrail(Tag.TypeStructPacked, data);
8107 const captures_len = if (extra.data.flags.any_captures)
8108 ip.extra.items[extra.end]
8109 else
8110 0;
75628111 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +
7563 info.fields_len + info.fields_len);
8112 @intFromBool(extra.data.flags.any_captures) + captures_len +
8113 extra.data.fields_len * 2);
75648114 },
75658115 .type_struct_packed_inits => b: {
7566 const info = ip.extraData(Tag.TypeStructPacked, data);
8116 const extra = ip.extraDataTrail(Tag.TypeStructPacked, data);
8117 const captures_len = if (extra.data.flags.any_captures)
8118 ip.extra.items[extra.end]
8119 else
8120 0;
75678121 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +
7568 info.fields_len + info.fields_len + info.fields_len);
8122 @intFromBool(extra.data.flags.any_captures) + captures_len +
8123 extra.data.fields_len * 3);
75698124 },
75708125 .type_tuple_anon => b: {
75718126 const info = ip.extraData(TypeStructAnon, data);
......@@ -7573,16 +8128,20 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
75738128 },
75748129
75758130 .type_union => b: {
7576 const info = ip.extraData(Tag.TypeUnion, data);
7577 const enum_info = ip.indexToKey(info.tag_ty).enum_type;
7578 const fields_len: u32 = @intCast(enum_info.names.len);
8131 const extra = ip.extraDataTrail(Tag.TypeUnion, data);
8132 const captures_len = if (extra.data.flags.any_captures)
8133 ip.extra.items[extra.end]
8134 else
8135 0;
75798136 const per_field = @sizeOf(u32); // field type
75808137 // 1 byte per field for alignment, rounded up to the nearest 4 bytes
7581 const alignments = if (info.flags.any_aligned_fields)
7582 ((fields_len + 3) / 4) * 4
8138 const alignments = if (extra.data.flags.any_aligned_fields)
8139 ((extra.data.fields_len + 3) / 4) * 4
75838140 else
75848141 0;
7585 break :b @sizeOf(Tag.TypeUnion) + (fields_len * per_field) + alignments;
8142 break :b @sizeOf(Tag.TypeUnion) +
8143 4 * (@intFromBool(extra.data.flags.any_captures) + captures_len) +
8144 (extra.data.fields_len * per_field) + alignments;
75868145 },
75878146
75888147 .type_function => b: {
......@@ -7698,6 +8257,8 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
76988257 for (tags, datas, 0..) |tag, data, i| {
76998258 try w.print("${d} = {s}(", .{ i, @tagName(tag) });
77008259 switch (tag) {
8260 .removed => {},
8261
77018262 .simple_type => try w.print("{s}", .{@tagName(@as(SimpleType, @enumFromInt(data)))}),
77028263 .simple_value => try w.print("{s}", .{@tagName(@as(SimpleValue, @enumFromInt(data)))}),
77038264
......@@ -7718,7 +8279,6 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
77188279 .type_enum_auto,
77198280 .type_opaque,
77208281 .type_struct,
7721 .type_struct_ns,
77228282 .type_struct_anon,
77238283 .type_struct_packed,
77248284 .type_struct_packed_inits,
......@@ -8105,6 +8665,8 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
81058665 // This optimization on tags is needed so that indexToKey can call
81068666 // typeOf without being recursive.
81078667 _ => switch (ip.items.items(.tag)[@intFromEnum(index)]) {
8668 .removed => unreachable,
8669
81088670 .type_int_signed,
81098671 .type_int_unsigned,
81108672 .type_array_big,
......@@ -8124,7 +8686,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
81248686 .simple_type,
81258687 .type_opaque,
81268688 .type_struct,
8127 .type_struct_ns,
81288689 .type_struct_anon,
81298690 .type_struct_packed,
81308691 .type_struct_packed_inits,
......@@ -8218,7 +8779,7 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E {
82188779
82198780pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
82208781 return switch (ip.indexToKey(ty)) {
8221 .struct_type => |struct_type| struct_type.field_types.len,
8782 .struct_type => ip.loadStructType(ty).field_types.len,
82228783 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
82238784 .array_type => |array_type| array_type.len,
82248785 .vector_type => |vector_type| vector_type.len,
......@@ -8228,7 +8789,7 @@ pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
82288789
82298790pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {
82308791 return switch (ip.indexToKey(ty)) {
8231 .struct_type => |struct_type| struct_type.field_types.len,
8792 .struct_type => ip.loadStructType(ty).field_types.len,
82328793 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
82338794 .array_type => |array_type| array_type.len + @intFromBool(array_type.sentinel != .none),
82348795 .vector_type => |vector_type| vector_type.len,
......@@ -8423,6 +8984,8 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
84238984 .var_args_param_type => unreachable, // special tag
84248985
84258986 _ => switch (ip.items.items(.tag)[@intFromEnum(index)]) {
8987 .removed => unreachable,
8988
84268989 .type_int_signed,
84278990 .type_int_unsigned,
84288991 => .Int,
......@@ -8458,7 +9021,6 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
84589021 .type_opaque => .Opaque,
84599022
84609023 .type_struct,
8461 .type_struct_ns,
84629024 .type_struct_anon,
84639025 .type_struct_packed,
84649026 .type_struct_packed_inits,
src/Liveness.zig+2-2
......@@ -131,7 +131,7 @@ fn LivenessPassData(comptime pass: LivenessPass) type {
131131 };
132132}
133133
134pub fn analyze(gpa: Allocator, air: Air, intern_pool: *const InternPool) Allocator.Error!Liveness {
134pub fn analyze(gpa: Allocator, air: Air, intern_pool: *InternPool) Allocator.Error!Liveness {
135135 const tracy = trace(@src());
136136 defer tracy.end();
137137
......@@ -836,7 +836,7 @@ pub const BigTomb = struct {
836836const Analysis = struct {
837837 gpa: Allocator,
838838 air: Air,
839 intern_pool: *const InternPool,
839 intern_pool: *InternPool,
840840 tomb_bits: []usize,
841841 special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32),
842842 extra: std.ArrayListUnmanaged(u32),
src/Module.zig+101-138
......@@ -101,17 +101,6 @@ embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .{},
101101/// is not yet implemented.
102102intern_pool: InternPool = .{},
103103
104/// The index type for this array is `CaptureScope.Index` and the elements here are
105/// the indexes of the parent capture scopes.
106/// Memory is owned by gpa; garbage collected.
107capture_scope_parents: std.ArrayListUnmanaged(CaptureScope.Index) = .{},
108/// Value is index of type
109/// Memory is owned by gpa; garbage collected.
110runtime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternPool.Index) = .{},
111/// Value is index of value
112/// Memory is owned by gpa; garbage collected.
113comptime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternPool.Index) = .{},
114
115104/// To be eliminated in a future commit by moving more data into InternPool.
116105/// Current uses that must be eliminated:
117106/// * comptime pointer mutation
......@@ -305,28 +294,6 @@ pub const Export = struct {
305294 }
306295};
307296
308pub const CaptureScope = struct {
309 pub const Key = extern struct {
310 zir_index: Zir.Inst.Index,
311 index: Index,
312 };
313
314 /// Index into `capture_scope_parents` which uniquely identifies a capture scope.
315 pub const Index = enum(u32) {
316 none = std.math.maxInt(u32),
317 _,
318
319 pub fn parent(i: Index, mod: *Module) Index {
320 return mod.capture_scope_parents.items[@intFromEnum(i)];
321 }
322 };
323};
324
325pub fn createCaptureScope(mod: *Module, parent: CaptureScope.Index) error{OutOfMemory}!CaptureScope.Index {
326 try mod.capture_scope_parents.append(mod.gpa, parent);
327 return @enumFromInt(mod.capture_scope_parents.items.len - 1);
328}
329
330297const ValueArena = struct {
331298 state: std.heap.ArenaAllocator.State,
332299 state_acquired: ?*std.heap.ArenaAllocator.State = null,
......@@ -386,9 +353,6 @@ pub const Decl = struct {
386353 /// there is no parent.
387354 src_namespace: Namespace.Index,
388355
389 /// The scope which lexically contains this decl.
390 src_scope: CaptureScope.Index,
391
392356 /// The AST node index of this declaration.
393357 /// Must be recomputed when the corresponding source file is modified.
394358 src_node: Ast.Node.Index,
......@@ -563,7 +527,7 @@ pub const Decl = struct {
563527
564528 /// If the Decl owns its value and it is a union, return it,
565529 /// otherwise null.
566 pub fn getOwnedUnion(decl: Decl, zcu: *Zcu) ?InternPool.UnionType {
530 pub fn getOwnedUnion(decl: Decl, zcu: *Zcu) ?InternPool.LoadedUnionType {
567531 if (!decl.owns_tv) return null;
568532 if (decl.val.ip_index == .none) return null;
569533 return zcu.typeToUnion(decl.val.toType());
......@@ -599,14 +563,15 @@ pub const Decl = struct {
599563 /// enum, or opaque.
600564 pub fn getInnerNamespaceIndex(decl: Decl, zcu: *Zcu) Namespace.OptionalIndex {
601565 if (!decl.has_tv) return .none;
566 const ip = &zcu.intern_pool;
602567 return switch (decl.val.ip_index) {
603568 .empty_struct_type => .none,
604569 .none => .none,
605 else => switch (zcu.intern_pool.indexToKey(decl.val.toIntern())) {
606 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
607 .struct_type => |struct_type| struct_type.namespace,
608 .union_type => |union_type| union_type.namespace.toOptional(),
609 .enum_type => |enum_type| enum_type.namespace,
570 else => switch (ip.indexToKey(decl.val.toIntern())) {
571 .opaque_type => ip.loadOpaqueType(decl.val.toIntern()).namespace,
572 .struct_type => ip.loadStructType(decl.val.toIntern()).namespace,
573 .union_type => ip.loadUnionType(decl.val.toIntern()).namespace,
574 .enum_type => ip.loadEnumType(decl.val.toIntern()).namespace,
610575 else => .none,
611576 },
612577 };
......@@ -792,7 +757,6 @@ pub const Namespace = struct {
792757 /// These are only declarations named directly by the AST; anonymous
793758 /// declarations are not stored here.
794759 decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{},
795
796760 /// Key is usingnamespace Decl itself. To find the namespace being included,
797761 /// the Decl Value has to be resolved as a Type which has a Namespace.
798762 /// Value is whether the usingnamespace decl is marked `pub`.
......@@ -2140,10 +2104,6 @@ pub fn deinit(zcu: *Zcu) void {
21402104
21412105 zcu.intern_pool.deinit(gpa);
21422106 zcu.tmp_hack_arena.deinit();
2143
2144 zcu.capture_scope_parents.deinit(gpa);
2145 zcu.runtime_capture_scopes.deinit(gpa);
2146 zcu.comptime_capture_scopes.deinit(gpa);
21472107}
21482108
21492109pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
......@@ -3342,6 +3302,70 @@ pub fn semaPkg(mod: *Module, pkg: *Package.Module) !void {
33423302 return mod.semaFile(file);
33433303}
33443304
3305fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespace.Index, file: *File) Allocator.Error!InternPool.Index {
3306 const gpa = zcu.gpa;
3307 const ip = &zcu.intern_pool;
3308 const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
3309 assert(extended.opcode == .struct_decl);
3310 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3311 assert(!small.has_captures_len);
3312 assert(!small.has_backing_int);
3313 assert(small.layout == .Auto);
3314 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
3315 const fields_len = if (small.has_fields_len) blk: {
3316 const fields_len = file.zir.extra[extra_index];
3317 extra_index += 1;
3318 break :blk fields_len;
3319 } else 0;
3320 const decls_len = if (small.has_decls_len) blk: {
3321 const decls_len = file.zir.extra[extra_index];
3322 extra_index += 1;
3323 break :blk decls_len;
3324 } else 0;
3325 const decls = file.zir.bodySlice(extra_index, decls_len);
3326 extra_index += decls_len;
3327
3328 const tracked_inst = try ip.trackZir(gpa, file, .main_struct_inst);
3329 const wip_ty = switch (try ip.getStructType(gpa, .{
3330 .layout = .Auto,
3331 .fields_len = fields_len,
3332 .known_non_opv = small.known_non_opv,
3333 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
3334 .is_tuple = small.is_tuple,
3335 .any_comptime_fields = small.any_comptime_fields,
3336 .any_default_inits = small.any_default_inits,
3337 .inits_resolved = false,
3338 .any_aligned_fields = small.any_aligned_fields,
3339 .has_namespace = true,
3340 .key = .{ .declared = .{
3341 .zir_index = tracked_inst,
3342 .captures = &.{},
3343 } },
3344 })) {
3345 .existing => unreachable, // we wouldn't be analysing the file root if this type existed
3346 .wip => |wip| wip,
3347 };
3348 errdefer wip_ty.cancel(ip);
3349
3350 if (zcu.comp.debug_incremental) {
3351 try ip.addDependency(
3352 gpa,
3353 InternPool.Depender.wrap(.{ .decl = decl_index }),
3354 .{ .src_hash = tracked_inst },
3355 );
3356 }
3357
3358 const decl = zcu.declPtr(decl_index);
3359 decl.val = Value.fromInterned(wip_ty.index);
3360 decl.has_tv = true;
3361 decl.owns_tv = true;
3362 decl.analysis = .complete;
3363
3364 try zcu.scanNamespace(namespace_index, decls, decl);
3365
3366 return wip_ty.finish(ip, decl_index, namespace_index.toOptional());
3367}
3368
33453369/// Regardless of the file status, will create a `Decl` so that we
33463370/// can track dependencies and re-analyze when the file becomes outdated.
33473371pub fn semaFile(mod: *Module, file: *File) SemaError!void {
......@@ -3363,15 +3387,14 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
33633387 .decl_index = undefined,
33643388 .file_scope = file,
33653389 });
3366 const new_namespace = mod.namespacePtr(new_namespace_index);
33673390 errdefer mod.destroyNamespace(new_namespace_index);
33683391
3369 const new_decl_index = try mod.allocateNewDecl(new_namespace_index, 0, .none);
3392 const new_decl_index = try mod.allocateNewDecl(new_namespace_index, 0);
33703393 const new_decl = mod.declPtr(new_decl_index);
33713394 errdefer @panic("TODO error handling");
33723395
33733396 file.root_decl = new_decl_index.toOptional();
3374 new_namespace.decl_index = new_decl_index;
3397 mod.namespacePtr(new_namespace_index).decl_index = new_decl_index;
33753398
33763399 new_decl.name = try file.fullyQualifiedName(mod);
33773400 new_decl.name_fully_qualified = true;
......@@ -3390,54 +3413,10 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
33903413 }
33913414 assert(file.zir_loaded);
33923415
3393 var sema_arena = std.heap.ArenaAllocator.init(gpa);
3394 defer sema_arena.deinit();
3395 const sema_arena_allocator = sema_arena.allocator();
3396
3397 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
3398 defer comptime_mutable_decls.deinit();
3399
3400 var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
3401 defer comptime_err_ret_trace.deinit();
3416 const struct_ty = try mod.getFileRootStruct(new_decl_index, new_namespace_index, file);
3417 errdefer mod.intern_pool.remove(struct_ty);
34023418
3403 var sema: Sema = .{
3404 .mod = mod,
3405 .gpa = gpa,
3406 .arena = sema_arena_allocator,
3407 .code = file.zir,
3408 .owner_decl = new_decl,
3409 .owner_decl_index = new_decl_index,
3410 .func_index = .none,
3411 .func_is_naked = false,
3412 .fn_ret_ty = Type.void,
3413 .fn_ret_ty_ies = null,
3414 .owner_func_index = .none,
3415 .comptime_mutable_decls = &comptime_mutable_decls,
3416 .comptime_err_ret_trace = &comptime_err_ret_trace,
3417 };
3418 defer sema.deinit();
3419
3420 const struct_ty = sema.getStructType(
3421 new_decl_index,
3422 new_namespace_index,
3423 try mod.intern_pool.trackZir(gpa, file, .main_struct_inst),
3424 ) catch |err| switch (err) {
3425 error.OutOfMemory => return error.OutOfMemory,
3426 };
3427 // TODO: figure out InternPool removals for incremental compilation
3428 //errdefer ip.remove(struct_ty);
3429 for (comptime_mutable_decls.items) |decl_index| {
3430 const decl = mod.declPtr(decl_index);
3431 _ = try decl.internValue(mod);
3432 }
3433
3434 new_decl.val = Value.fromInterned(struct_ty);
3435 new_decl.has_tv = true;
3436 new_decl.owns_tv = true;
3437 new_decl.analysis = .complete;
3438
3439 const comp = mod.comp;
3440 switch (comp.cache_use) {
3419 switch (mod.comp.cache_use) {
34413420 .whole => |whole| if (whole.cache_manifest) |man| {
34423421 const source = file.getSource(gpa) catch |err| {
34433422 try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)});
......@@ -3573,7 +3552,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
35733552 .sema = &sema,
35743553 .src_decl = decl_index,
35753554 .namespace = decl.src_namespace,
3576 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
35773555 .instructions = .{},
35783556 .inlining = null,
35793557 .is_comptime = true,
......@@ -4205,7 +4183,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
42054183 );
42064184 const comp = zcu.comp;
42074185 if (!gop.found_existing) {
4208 const new_decl_index = try zcu.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope);
4186 const new_decl_index = try zcu.allocateNewDecl(namespace_index, decl_node);
42094187 const new_decl = zcu.declPtr(new_decl_index);
42104188 new_decl.kind = kind;
42114189 new_decl.name = decl_name;
......@@ -4438,7 +4416,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
44384416 .sema = &sema,
44394417 .src_decl = decl_index,
44404418 .namespace = decl.src_namespace,
4441 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
44424419 .instructions = .{},
44434420 .inlining = null,
44444421 .is_comptime = false,
......@@ -4639,7 +4616,6 @@ pub fn allocateNewDecl(
46394616 mod: *Module,
46404617 namespace: Namespace.Index,
46414618 src_node: Ast.Node.Index,
4642 src_scope: CaptureScope.Index,
46434619) !Decl.Index {
46444620 const ip = &mod.intern_pool;
46454621 const gpa = mod.gpa;
......@@ -4657,7 +4633,6 @@ pub fn allocateNewDecl(
46574633 .@"addrspace" = .generic,
46584634 .analysis = .unreferenced,
46594635 .zir_decl_index = .none,
4660 .src_scope = src_scope,
46614636 .is_pub = false,
46624637 .is_exported = false,
46634638 .alive = false,
......@@ -4697,17 +4672,16 @@ pub fn errorSetBits(mod: *Module) u16 {
46974672
46984673pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index {
46994674 const src_decl = mod.declPtr(block.src_decl);
4700 return mod.createAnonymousDeclFromDecl(src_decl, block.namespace, block.wip_capture_scope, typed_value);
4675 return mod.createAnonymousDeclFromDecl(src_decl, block.namespace, typed_value);
47014676}
47024677
47034678pub fn createAnonymousDeclFromDecl(
47044679 mod: *Module,
47054680 src_decl: *Decl,
47064681 namespace: Namespace.Index,
4707 src_scope: CaptureScope.Index,
47084682 tv: TypedValue,
47094683) !Decl.Index {
4710 const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node, src_scope);
4684 const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node);
47114685 errdefer mod.destroyDecl(new_decl_index);
47124686 const name = try mod.intern_pool.getOrPutStringFmt(mod.gpa, "{}__anon_{d}", .{
47134687 src_decl.name.fmt(&mod.intern_pool), @intFromEnum(new_decl_index),
......@@ -5276,7 +5250,7 @@ pub fn populateTestFunctions(
52765250 .len = test_decl_name.len,
52775251 .child = .u8_type,
52785252 });
5279 const test_name_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, .none, .{
5253 const test_name_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, .{
52805254 .ty = test_name_decl_ty,
52815255 .val = Value.fromInterned((try mod.intern(.{ .aggregate = .{
52825256 .ty = test_name_decl_ty.toIntern(),
......@@ -5322,7 +5296,7 @@ pub fn populateTestFunctions(
53225296 .child = test_fn_ty.toIntern(),
53235297 .sentinel = .none,
53245298 });
5325 const array_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, .none, .{
5299 const array_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, .{
53265300 .ty = array_decl_ty,
53275301 .val = Value.fromInterned((try mod.intern(.{ .aggregate = .{
53285302 .ty = array_decl_ty.toIntern(),
......@@ -5686,7 +5660,7 @@ pub fn enumValue(mod: *Module, ty: Type, tag_int: InternPool.Index) Allocator.Er
56865660pub fn enumValueFieldIndex(mod: *Module, ty: Type, field_index: u32) Allocator.Error!Value {
56875661 const ip = &mod.intern_pool;
56885662 const gpa = mod.gpa;
5689 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
5663 const enum_type = ip.loadEnumType(ty.toIntern());
56905664
56915665 if (enum_type.values.len == 0) {
56925666 // Auto-numbered fields.
......@@ -5976,14 +5950,6 @@ pub fn atomicPtrAlignment(
59765950 return .none;
59775951}
59785952
5979pub fn opaqueSrcLoc(mod: *Module, opaque_type: InternPool.Key.OpaqueType) SrcLoc {
5980 return mod.declPtr(opaque_type.decl).srcLoc(mod);
5981}
5982
5983pub fn opaqueFullyQualifiedName(mod: *Module, opaque_type: InternPool.Key.OpaqueType) !InternPool.NullTerminatedString {
5984 return mod.declPtr(opaque_type.decl).fullyQualifiedName(mod);
5985}
5986
59875953pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {
59885954 return mod.declPtr(decl_index).getFileScope(mod);
59895955}
......@@ -5992,28 +5958,26 @@ pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {
59925958/// * `@TypeOf(.{})`
59935959/// * A struct which has no fields (`struct {}`).
59945960/// * Not a struct.
5995pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.Key.StructType {
5961pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {
59965962 if (ty.ip_index == .none) return null;
5997 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
5998 .struct_type => |t| t,
5963 const ip = &mod.intern_pool;
5964 return switch (ip.indexToKey(ty.ip_index)) {
5965 .struct_type => ip.loadStructType(ty.ip_index),
59995966 else => null,
60005967 };
60015968}
60025969
6003pub fn typeToPackedStruct(mod: *Module, ty: Type) ?InternPool.Key.StructType {
6004 if (ty.ip_index == .none) return null;
6005 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
6006 .struct_type => |t| if (t.layout == .Packed) t else null,
6007 else => null,
6008 };
5970pub fn typeToPackedStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {
5971 const s = mod.typeToStruct(ty) orelse return null;
5972 if (s.layout != .Packed) return null;
5973 return s;
60095974}
60105975
6011/// This asserts that the union's enum tag type has been resolved.
6012pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType {
5976pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.LoadedUnionType {
60135977 if (ty.ip_index == .none) return null;
60145978 const ip = &mod.intern_pool;
60155979 return switch (ip.indexToKey(ty.ip_index)) {
6016 .union_type => |k| ip.loadUnionType(k),
5980 .union_type => ip.loadUnionType(ty.ip_index),
60175981 else => null,
60185982 };
60195983}
......@@ -6115,7 +6079,7 @@ pub const UnionLayout = struct {
61156079 padding: u32,
61166080};
61176081
6118pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
6082pub fn getUnionLayout(mod: *Module, u: InternPool.LoadedUnionType) UnionLayout {
61196083 const ip = &mod.intern_pool;
61206084 assert(u.haveLayout(ip));
61216085 var most_aligned_field: u32 = undefined;
......@@ -6161,7 +6125,7 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
61616125 const tag_size = Type.fromInterned(u.enum_tag_ty).abiSize(mod);
61626126 const tag_align = Type.fromInterned(u.enum_tag_ty).abiAlignment(mod).max(.@"1");
61636127 return .{
6164 .abi_size = u.size,
6128 .abi_size = u.size(ip).*,
61656129 .abi_align = tag_align.max(payload_align),
61666130 .most_aligned_field = most_aligned_field,
61676131 .most_aligned_field_size = most_aligned_field_size,
......@@ -6170,16 +6134,16 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
61706134 .payload_align = payload_align,
61716135 .tag_align = tag_align,
61726136 .tag_size = tag_size,
6173 .padding = u.padding,
6137 .padding = u.padding(ip).*,
61746138 };
61756139}
61766140
6177pub fn unionAbiSize(mod: *Module, u: InternPool.UnionType) u64 {
6141pub fn unionAbiSize(mod: *Module, u: InternPool.LoadedUnionType) u64 {
61786142 return mod.getUnionLayout(u).abi_size;
61796143}
61806144
61816145/// Returns 0 if the union is represented with 0 bits at runtime.
6182pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) Alignment {
6146pub fn unionAbiAlignment(mod: *Module, u: InternPool.LoadedUnionType) Alignment {
61836147 const ip = &mod.intern_pool;
61846148 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
61856149 var max_align: Alignment = .none;
......@@ -6196,7 +6160,7 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) Alignment {
61966160/// Returns the field alignment, assuming the union is not packed.
61976161/// Keep implementation in sync with `Sema.unionFieldAlignment`.
61986162/// Prefer to call that function instead of this one during Sema.
6199pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) Alignment {
6163pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.LoadedUnionType, field_index: u32) Alignment {
62006164 const ip = &mod.intern_pool;
62016165 const field_align = u.fieldAlign(ip, field_index);
62026166 if (field_align != .none) return field_align;
......@@ -6205,12 +6169,11 @@ pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_in
62056169}
62066170
62076171/// Returns the index of the active field, given the current tag value
6208pub fn unionTagFieldIndex(mod: *Module, u: InternPool.UnionType, enum_tag: Value) ?u32 {
6172pub fn unionTagFieldIndex(mod: *Module, u: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {
62096173 const ip = &mod.intern_pool;
62106174 if (enum_tag.toIntern() == .none) return null;
62116175 assert(ip.typeOf(enum_tag.toIntern()) == u.enum_tag_ty);
6212 const enum_type = ip.indexToKey(u.enum_tag_ty).enum_type;
6213 return enum_type.tagValueIndex(ip, enum_tag.toIntern());
6176 return u.loadTagType(ip).tagValueIndex(ip, enum_tag.toIntern());
62146177}
62156178
62166179/// Returns the field alignment of a non-packed struct in byte units.
......@@ -6257,7 +6220,7 @@ pub fn structFieldAlignmentExtern(mod: *Module, field_ty: Type) Alignment {
62576220/// projects.
62586221pub fn structPackedFieldBitOffset(
62596222 mod: *Module,
6260 struct_type: InternPool.Key.StructType,
6223 struct_type: InternPool.LoadedStructType,
62616224 field_index: u32,
62626225) u16 {
62636226 const ip = &mod.intern_pool;
src/Package/Module.zig+37-3
......@@ -63,6 +63,11 @@ pub const CreateOptions = struct {
6363
6464 builtin_mod: ?*Package.Module,
6565
66 /// Allocated into the given `arena`. Should be shared across all module creations in a Compilation.
67 /// Ignored if `builtin_mod` is passed or if `!have_zcu`.
68 /// Otherwise, may be `null` only if this Compilation consists of a single module.
69 builtin_modules: ?*std.StringHashMapUnmanaged(*Module),
70
6671 pub const Paths = struct {
6772 root: Package.Path,
6873 /// Relative to `root`. May contain path separators.
......@@ -364,11 +369,37 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
364369 .wasi_exec_model = options.global.wasi_exec_model,
365370 }, arena);
366371
372 const new = if (options.builtin_modules) |builtins| new: {
373 const gop = try builtins.getOrPut(arena, generated_builtin_source);
374 if (gop.found_existing) break :b gop.value_ptr.*;
375 errdefer builtins.removeByPtr(gop.key_ptr);
376 const new = try arena.create(Module);
377 gop.value_ptr.* = new;
378 break :new new;
379 } else try arena.create(Module);
380 errdefer if (options.builtin_modules) |builtins| assert(builtins.remove(generated_builtin_source));
381
367382 const new_file = try arena.create(File);
368383
369 const digest = Cache.HashHelper.oneShot(generated_builtin_source);
370 const builtin_sub_path = try arena.dupe(u8, "b" ++ std.fs.path.sep_str ++ digest);
371 const new = try arena.create(Module);
384 const bin_digest, const hex_digest = digest: {
385 var hasher: Cache.Hasher = Cache.hasher_init;
386 hasher.update(generated_builtin_source);
387
388 var bin_digest: Cache.BinDigest = undefined;
389 hasher.final(&bin_digest);
390
391 var hex_digest: Cache.HexDigest = undefined;
392 _ = std.fmt.bufPrint(
393 &hex_digest,
394 "{s}",
395 .{std.fmt.fmtSliceHexLower(&bin_digest)},
396 ) catch unreachable;
397
398 break :digest .{ bin_digest, hex_digest };
399 };
400
401 const builtin_sub_path = try arena.dupe(u8, "b" ++ std.fs.path.sep_str ++ hex_digest);
402
372403 new.* = .{
373404 .root = .{
374405 .root_dir = options.global_cache_directory,
......@@ -415,6 +446,9 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
415446 .status = .never_loaded,
416447 .mod = new,
417448 .root_decl = .none,
449 // We might as well use this digest for the File `path digest`, since there's a
450 // one-to-one correspondence here between distinct paths and distinct contents.
451 .path_digest = bin_digest,
418452 };
419453 break :b new;
420454 };
src/Sema.zig+993-922
......@@ -155,7 +155,6 @@ const Namespace = Module.Namespace;
155155const CompileError = Module.CompileError;
156156const SemaError = Module.SemaError;
157157const Decl = Module.Decl;
158const CaptureScope = Module.CaptureScope;
159158const LazySrcLoc = std.zig.LazySrcLoc;
160159const RangeSet = @import("RangeSet.zig");
161160const target_util = @import("target.zig");
......@@ -331,8 +330,6 @@ pub const Block = struct {
331330 /// used to add a `func_instance` into the `InternPool`.
332331 params: std.MultiArrayList(Param) = .{},
333332
334 wip_capture_scope: CaptureScope.Index,
335
336333 label: ?*Label = null,
337334 inlining: ?*Inlining,
338335 /// If runtime_index is not 0 then one of these is guaranteed to be non null.
......@@ -475,7 +472,6 @@ pub const Block = struct {
475472 .src_decl = parent.src_decl,
476473 .namespace = parent.namespace,
477474 .instructions = .{},
478 .wip_capture_scope = parent.wip_capture_scope,
479475 .label = null,
480476 .inlining = parent.inlining,
481477 .is_comptime = parent.is_comptime,
......@@ -974,12 +970,6 @@ fn analyzeBodyInner(
974970
975971 try sema.inst_map.ensureSpaceForInstructions(sema.gpa, body);
976972
977 // Most of the time, we don't need to construct a new capture scope for a
978 // block. However, successive iterations of comptime loops can capture
979 // different values for the same Zir.Inst.Index, so in those cases, we will
980 // have to create nested capture scopes; see the `.repeat` case below.
981 const parent_capture_scope = block.wip_capture_scope;
982
983973 const mod = sema.mod;
984974 const map = &sema.inst_map;
985975 const tags = sema.code.instructions.items(.tag);
......@@ -1028,7 +1018,6 @@ fn analyzeBodyInner(
10281018 .c_import => try sema.zirCImport(block, inst),
10291019 .call => try sema.zirCall(block, inst, .direct),
10301020 .field_call => try sema.zirCall(block, inst, .field),
1031 .closure_get => try sema.zirClosureGet(block, inst),
10321021 .cmp_lt => try sema.zirCmp(block, inst, .lt),
10331022 .cmp_lte => try sema.zirCmp(block, inst, .lte),
10341023 .cmp_eq => try sema.zirCmpEq(block, inst, .eq, Air.Inst.Tag.fromCmpOp(.eq, block.float_mode == .Optimized)),
......@@ -1275,6 +1264,7 @@ fn analyzeBodyInner(
12751264 .work_group_size => try sema.zirWorkItem( block, extended, extended.opcode),
12761265 .work_group_id => try sema.zirWorkItem( block, extended, extended.opcode),
12771266 .in_comptime => try sema.zirInComptime( block),
1267 .closure_get => try sema.zirClosureGet( block, extended),
12781268 // zig fmt: on
12791269
12801270 .fence => {
......@@ -1453,11 +1443,6 @@ fn analyzeBodyInner(
14531443 i += 1;
14541444 continue;
14551445 },
1456 .closure_capture => {
1457 try sema.zirClosureCapture(block, inst);
1458 i += 1;
1459 continue;
1460 },
14611446 .memcpy => {
14621447 try sema.zirMemcpy(block, inst);
14631448 i += 1;
......@@ -1534,11 +1519,6 @@ fn analyzeBodyInner(
15341519 // Send comptime control flow back to the beginning of this block.
15351520 const src = LazySrcLoc.nodeOffset(datas[@intFromEnum(inst)].node);
15361521 try sema.emitBackwardBranch(block, src);
1537
1538 // We need to construct new capture scopes for the next loop iteration so it
1539 // can capture values without clobbering the earlier iteration's captures.
1540 block.wip_capture_scope = try mod.createCaptureScope(parent_capture_scope);
1541
15421522 i = 0;
15431523 continue;
15441524 } else {
......@@ -1552,11 +1532,6 @@ fn analyzeBodyInner(
15521532 // Send comptime control flow back to the beginning of this block.
15531533 const src = LazySrcLoc.nodeOffset(datas[@intFromEnum(inst)].node);
15541534 try sema.emitBackwardBranch(block, src);
1555
1556 // We need to construct new capture scopes for the next loop iteration so it
1557 // can capture values without clobbering the earlier iteration's captures.
1558 block.wip_capture_scope = try mod.createCaptureScope(parent_capture_scope);
1559
15601535 i = 0;
15611536 continue;
15621537 },
......@@ -1855,10 +1830,6 @@ fn analyzeBodyInner(
18551830 map.putAssumeCapacity(inst, air_inst);
18561831 i += 1;
18571832 }
1858
1859 // We may have overwritten the capture scope due to a `repeat` instruction where
1860 // the body had a capture; restore it now.
1861 block.wip_capture_scope = parent_capture_scope;
18621833}
18631834
18641835pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
......@@ -2698,21 +2669,61 @@ fn analyzeAsInt(
26982669 return (try val.getUnsignedIntAdvanced(mod, sema)).?;
26992670}
27002671
2701pub fn getStructType(
2672/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,
2673/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.
2674fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {
2675 const zcu = sema.mod;
2676 const ip = &zcu.intern_pool;
2677 const parent_captures: InternPool.CaptureValue.Slice = zcu.namespacePtr(block.namespace).getType(zcu).getCaptures(zcu);
2678
2679 const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len);
2680
2681 for (sema.code.extra[extra_index..][0..captures_len], captures) |raw, *capture| {
2682 const zir_capture: Zir.Inst.Capture = @bitCast(raw);
2683 capture.* = switch (zir_capture.unwrap()) {
2684 .nested => |parent_idx| parent_captures.get(ip)[parent_idx],
2685 .instruction => |inst| InternPool.CaptureValue.wrap(capture: {
2686 const air_ref = try sema.resolveInst(inst.toRef());
2687 if (try sema.resolveValueResolveLazy(air_ref)) |val| {
2688 break :capture .{ .@"comptime" = val.toIntern() };
2689 }
2690 break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() };
2691 }),
2692 .decl_val => |str| capture: {
2693 const decl_name = try ip.getOrPutString(sema.gpa, sema.code.nullTerminatedString(str));
2694 const decl = try sema.lookupIdentifier(block, .unneeded, decl_name); // TODO: could we need this src loc?
2695 break :capture InternPool.CaptureValue.wrap(.{ .decl_val = decl });
2696 },
2697 .decl_ref => |str| capture: {
2698 const decl_name = try ip.getOrPutString(sema.gpa, sema.code.nullTerminatedString(str));
2699 const decl = try sema.lookupIdentifier(block, .unneeded, decl_name); // TODO: could we need this src loc?
2700 break :capture InternPool.CaptureValue.wrap(.{ .decl_ref = decl });
2701 },
2702 };
2703 }
2704
2705 return captures;
2706}
2707
2708fn zirStructDecl(
27022709 sema: *Sema,
2703 decl: InternPool.DeclIndex,
2704 namespace: InternPool.NamespaceIndex,
2705 tracked_inst: InternPool.TrackedInst.Index,
2706) !InternPool.Index {
2710 block: *Block,
2711 extended: Zir.Inst.Extended.InstData,
2712 inst: Zir.Inst.Index,
2713) CompileError!Air.Inst.Ref {
27072714 const mod = sema.mod;
27082715 const gpa = sema.gpa;
27092716 const ip = &mod.intern_pool;
2710 const zir_index = tracked_inst.resolve(ip);
2711 const extended = sema.code.instructions.items(.data)[@intFromEnum(zir_index)].extended;
2712 assert(extended.opcode == .struct_decl);
27132717 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
2718 const extra = sema.code.extraData(Zir.Inst.StructDecl, extended.operand);
2719 const src = extra.data.src();
2720 var extra_index = extra.end;
27142721
2715 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
2722 const captures_len = if (small.has_captures_len) blk: {
2723 const captures_len = sema.code.extra[extra_index];
2724 extra_index += 1;
2725 break :blk captures_len;
2726 } else 0;
27162727 const fields_len = if (small.has_fields_len) blk: {
27172728 const fields_len = sema.code.extra[extra_index];
27182729 extra_index += 1;
......@@ -2724,6 +2735,9 @@ pub fn getStructType(
27242735 break :blk decls_len;
27252736 } else 0;
27262737
2738 const captures = try sema.getCaptures(block, extra_index, captures_len);
2739 extra_index += captures_len;
2740
27272741 if (small.has_backing_int) {
27282742 const backing_int_body_len = sema.code.extra[extra_index];
27292743 extra_index += 1; // backing_int_body_len
......@@ -2734,49 +2748,38 @@ pub fn getStructType(
27342748 }
27352749 }
27362750
2737 const decls = sema.code.bodySlice(extra_index, decls_len);
2738 try mod.scanNamespace(namespace, decls, mod.declPtr(decl));
2739 extra_index += decls_len;
2740
2741 const ty = try ip.getStructType(gpa, .{
2742 .decl = decl,
2743 .namespace = namespace.toOptional(),
2744 .zir_index = tracked_inst.toOptional(),
2751 const wip_ty = switch (try ip.getStructType(gpa, .{
27452752 .layout = small.layout,
2746 .known_non_opv = small.known_non_opv,
2747 .is_tuple = small.is_tuple,
27482753 .fields_len = fields_len,
2754 .known_non_opv = small.known_non_opv,
27492755 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
2750 .any_default_inits = small.any_default_inits,
2756 .is_tuple = small.is_tuple,
27512757 .any_comptime_fields = small.any_comptime_fields,
2758 .any_default_inits = small.any_default_inits,
27522759 .inits_resolved = false,
27532760 .any_aligned_fields = small.any_aligned_fields,
2754 });
2755
2756 return ty;
2757}
2758
2759fn zirStructDecl(
2760 sema: *Sema,
2761 block: *Block,
2762 extended: Zir.Inst.Extended.InstData,
2763 inst: Zir.Inst.Index,
2764) CompileError!Air.Inst.Ref {
2765 const mod = sema.mod;
2766 const ip = &mod.intern_pool;
2767 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
2768 const src = sema.code.extraData(Zir.Inst.StructDecl, extended.operand).data.src();
2769
2770 // Because these three things each reference each other, `undefined`
2771 // placeholders are used before being set after the struct type gains an
2772 // InternPool index.
2761 .has_namespace = true or decls_len > 0, // TODO: see below
2762 .key = .{ .declared = .{
2763 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
2764 .captures = captures,
2765 } },
2766 })) {
2767 .existing => |ty| return Air.internedToRef(ty),
2768 .wip => |wip| wip: {
2769 if (sema.builtin_type_target_index == .none) break :wip wip;
2770 var new = wip;
2771 new.index = sema.builtin_type_target_index;
2772 ip.resolveBuiltinType(new.index, wip.index);
2773 break :wip new;
2774 },
2775 };
2776 errdefer wip_ty.cancel(ip);
27732777
27742778 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2775 .ty = Type.noreturn,
2776 .val = Value.@"unreachable",
2779 .ty = Type.type,
2780 .val = Value.fromInterned(wip_ty.index),
27772781 }, small.name_strategy, "struct", inst);
2778 const new_decl = mod.declPtr(new_decl_index);
2779 new_decl.owns_tv = true;
2782 mod.declPtr(new_decl_index).owns_tv = true;
27802783 errdefer mod.abortAnonDecl(new_decl_index);
27812784
27822785 if (sema.mod.comp.debug_incremental) {
......@@ -2787,31 +2790,21 @@ fn zirStructDecl(
27872790 );
27882791 }
27892792
2790 const new_namespace_index = try mod.createNamespace(.{
2793 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
2794 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{
27912795 .parent = block.namespace.toOptional(),
27922796 .decl_index = new_decl_index,
27932797 .file_scope = block.getFileScope(mod),
2794 });
2795 errdefer mod.destroyNamespace(new_namespace_index);
2796
2797 const struct_ty = ty: {
2798 const tracked_inst = try ip.trackZir(mod.gpa, block.getFileScope(mod), inst);
2799 const ty = try sema.getStructType(new_decl_index, new_namespace_index, tracked_inst);
2800 if (sema.builtin_type_target_index != .none) {
2801 ip.resolveBuiltinType(sema.builtin_type_target_index, ty);
2802 break :ty sema.builtin_type_target_index;
2803 }
2804 break :ty ty;
2805 };
2806 // TODO: figure out InternPool removals for incremental compilation
2807 //errdefer ip.remove(struct_ty);
2798 })).toOptional() else .none;
2799 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
28082800
2809 new_decl.ty = Type.type;
2810 new_decl.val = Value.fromInterned(struct_ty);
2801 if (new_namespace_index.unwrap()) |ns| {
2802 const decls = sema.code.bodySlice(extra_index, decls_len);
2803 try mod.scanNamespace(ns, decls, mod.declPtr(new_decl_index));
2804 }
28112805
2812 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
28132806 try mod.finalizeAnonDecl(new_decl_index);
2814 return decl_val;
2807 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
28152808}
28162809
28172810fn createAnonymousDeclTypeNamed(
......@@ -2827,10 +2820,9 @@ fn createAnonymousDeclTypeNamed(
28272820 const ip = &mod.intern_pool;
28282821 const gpa = sema.gpa;
28292822 const namespace = block.namespace;
2830 const src_scope = block.wip_capture_scope;
28312823 const src_decl = mod.declPtr(block.src_decl);
28322824 const src_node = src_decl.relativeToNodeIndex(src.node_offset.x);
2833 const new_decl_index = try mod.allocateNewDecl(namespace, src_node, src_scope);
2825 const new_decl_index = try mod.allocateNewDecl(namespace, src_node);
28342826 errdefer mod.destroyDecl(new_decl_index);
28352827
28362828 switch (name_strategy) {
......@@ -2922,6 +2914,7 @@ fn zirEnumDecl(
29222914
29232915 const mod = sema.mod;
29242916 const gpa = sema.gpa;
2917 const ip = &mod.intern_pool;
29252918 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
29262919 const extra = sema.code.extraData(Zir.Inst.EnumDecl, extended.operand);
29272920 var extra_index: usize = extra.end;
......@@ -2935,6 +2928,12 @@ fn zirEnumDecl(
29352928 break :blk tag_type_ref;
29362929 } else .none;
29372930
2931 const captures_len = if (small.has_captures_len) blk: {
2932 const captures_len = sema.code.extra[extra_index];
2933 extra_index += 1;
2934 break :blk captures_len;
2935 } else 0;
2936
29382937 const body_len = if (small.has_body_len) blk: {
29392938 const body_len = sema.code.extra[extra_index];
29402939 extra_index += 1;
......@@ -2953,14 +2952,57 @@ fn zirEnumDecl(
29532952 break :blk decls_len;
29542953 } else 0;
29552954
2956 // Because these three things each reference each other, `undefined`
2957 // placeholders are used before being set after the enum type gains an
2958 // InternPool index.
2955 const captures = try sema.getCaptures(block, extra_index, captures_len);
2956 extra_index += captures_len;
2957
2958 const decls = sema.code.bodySlice(extra_index, decls_len);
2959 extra_index += decls_len;
2960
2961 const body = sema.code.bodySlice(extra_index, body_len);
2962 extra_index += body.len;
2963
2964 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
2965 const body_end = extra_index;
2966 extra_index += bit_bags_count;
2967
2968 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
2969 if (bag != 0) break true;
2970 } else false;
2971
2972 const wip_ty = switch (try ip.getEnumType(gpa, .{
2973 .has_namespace = true or decls_len > 0, // TODO: see below
2974 .has_values = any_values,
2975 .tag_mode = if (small.nonexhaustive)
2976 .nonexhaustive
2977 else if (tag_type_ref == .none)
2978 .auto
2979 else
2980 .explicit,
2981 .fields_len = fields_len,
2982 .key = .{ .declared = .{
2983 .zir_index = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst),
2984 .captures = captures,
2985 } },
2986 })) {
2987 .wip => |wip| wip: {
2988 if (sema.builtin_type_target_index == .none) break :wip wip;
2989 var new = wip;
2990 new.index = sema.builtin_type_target_index;
2991 ip.resolveBuiltinType(new.index, wip.index);
2992 break :wip new;
2993 },
2994 .existing => |ty| return Air.internedToRef(ty),
2995 };
29592996
2997 // Once this is `true`, we will not delete the decl or type even upon failure, since we
2998 // have finished constructing the type and are in the process of analyzing it.
29602999 var done = false;
3000
3001 errdefer if (!done) wip_ty.cancel(ip);
3002
29613003 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2962 .ty = Type.noreturn,
2963 .val = Value.@"unreachable",
3004 .ty = Type.type,
3005 .val = Value.fromInterned(wip_ty.index),
29643006 }, small.name_strategy, "enum", inst);
29653007 const new_decl = mod.declPtr(new_decl_index);
29663008 new_decl.owns_tv = true;
......@@ -2974,56 +3016,21 @@ fn zirEnumDecl(
29743016 );
29753017 }
29763018
2977 const new_namespace_index = try mod.createNamespace(.{
3019 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
3020 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{
29783021 .parent = block.namespace.toOptional(),
29793022 .decl_index = new_decl_index,
29803023 .file_scope = block.getFileScope(mod),
2981 });
2982 errdefer if (!done) mod.destroyNamespace(new_namespace_index);
2983
2984 const decls = sema.code.bodySlice(extra_index, decls_len);
2985 try mod.scanNamespace(new_namespace_index, decls, new_decl);
2986 extra_index += decls_len;
3024 })).toOptional() else .none;
3025 errdefer if (!done) if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
29873026
2988 const body = sema.code.bodySlice(extra_index, body_len);
2989 extra_index += body.len;
2990
2991 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
2992 const body_end = extra_index;
2993 extra_index += bit_bags_count;
2994
2995 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
2996 if (bag != 0) break true;
2997 } else false;
2998
2999 const incomplete_enum = incomplete_enum: {
3000 var incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{
3001 .decl = new_decl_index,
3002 .namespace = new_namespace_index.toOptional(),
3003 .fields_len = fields_len,
3004 .has_values = any_values,
3005 .tag_mode = if (small.nonexhaustive)
3006 .nonexhaustive
3007 else if (tag_type_ref == .none)
3008 .auto
3009 else
3010 .explicit,
3011 .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
3012 });
3013 if (sema.builtin_type_target_index != .none) {
3014 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index);
3015 incomplete_enum.index = sema.builtin_type_target_index;
3016 }
3017 break :incomplete_enum incomplete_enum;
3018 };
3019 // TODO: figure out InternPool removals for incremental compilation
3020 //errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index);
3021
3022 new_decl.ty = Type.type;
3023 new_decl.val = Value.fromInterned(incomplete_enum.index);
3027 if (new_namespace_index.unwrap()) |ns| {
3028 try mod.scanNamespace(ns, decls, new_decl);
3029 }
30243030
3025 const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);
3026 try mod.finalizeAnonDecl(new_decl_index);
3031 // We've finished the initial construction of this type, and are about to perform analysis.
3032 // Set the decl and namespace appropriately, and don't destroy anything on failure.
3033 wip_ty.prepare(ip, new_decl_index, new_namespace_index);
30273034 done = true;
30283035
30293036 const int_tag_ty = ty: {
......@@ -3053,8 +3060,7 @@ fn zirEnumDecl(
30533060 .parent = null,
30543061 .sema = sema,
30553062 .src_decl = new_decl_index,
3056 .namespace = new_namespace_index,
3057 .wip_capture_scope = try mod.createCaptureScope(new_decl.src_scope),
3063 .namespace = new_namespace_index.unwrap() orelse block.namespace,
30583064 .instructions = .{},
30593065 .inlining = null,
30603066 .is_comptime = true,
......@@ -3070,7 +3076,6 @@ fn zirEnumDecl(
30703076 if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) {
30713077 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
30723078 }
3073 incomplete_enum.setTagType(&mod.intern_pool, ty.toIntern());
30743079 break :ty ty;
30753080 } else if (fields_len == 0) {
30763081 break :ty try mod.intType(.unsigned, 0);
......@@ -3080,6 +3085,8 @@ fn zirEnumDecl(
30803085 }
30813086 };
30823087
3088 wip_ty.setTagTy(ip, int_tag_ty.toIntern());
3089
30833090 if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
30843091 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(mod)) {
30853092 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
......@@ -3103,7 +3110,6 @@ fn zirEnumDecl(
31033110 extra_index += 2; // field name, doc comment
31043111
31053112 const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir);
3106 assert(incomplete_enum.addFieldName(&mod.intern_pool, field_name) == null);
31073113
31083114 const tag_overflow = if (has_tag_value) overflow: {
31093115 const tag_val_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
......@@ -3124,12 +3130,13 @@ fn zirEnumDecl(
31243130 };
31253131 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;
31263132 last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty);
3127 if (incomplete_enum.addFieldValue(&mod.intern_pool, last_tag_val.?.toIntern())) |other_index| {
3133 if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| {
3134 assert(conflict.kind == .value); // AstGen validated names are unique
31283135 const value_src = mod.fieldSrcLoc(new_decl_index, .{
31293136 .index = field_i,
31303137 .range = .value,
31313138 }).lazy;
3132 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
3139 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
31333140 const msg = msg: {
31343141 const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});
31353142 errdefer msg.destroy(gpa);
......@@ -3146,9 +3153,10 @@ fn zirEnumDecl(
31463153 else
31473154 try mod.intValue(int_tag_ty, 0);
31483155 if (overflow != null) break :overflow true;
3149 if (incomplete_enum.addFieldValue(&mod.intern_pool, last_tag_val.?.toIntern())) |other_index| {
3156 if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| {
3157 assert(conflict.kind == .value); // AstGen validated names are unique
31503158 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
3151 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
3159 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
31523160 const msg = msg: {
31533161 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});
31543162 errdefer msg.destroy(gpa);
......@@ -3159,6 +3167,7 @@ fn zirEnumDecl(
31593167 }
31603168 break :overflow false;
31613169 } else overflow: {
3170 assert(wip_ty.nextField(&mod.intern_pool, field_name, .none) == null);
31623171 last_tag_val = try mod.intValue(Type.comptime_int, field_i);
31633172 if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true;
31643173 last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty);
......@@ -3176,7 +3185,9 @@ fn zirEnumDecl(
31763185 return sema.failWithOwnedErrorMsg(block, msg);
31773186 }
31783187 }
3179 return decl_val;
3188
3189 try mod.finalizeAnonDecl(new_decl_index);
3190 return Air.internedToRef(wip_ty.index);
31803191}
31813192
31823193fn zirUnionDecl(
......@@ -3190,6 +3201,7 @@ fn zirUnionDecl(
31903201
31913202 const mod = sema.mod;
31923203 const gpa = sema.gpa;
3204 const ip = &mod.intern_pool;
31933205 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
31943206 const extra = sema.code.extraData(Zir.Inst.UnionDecl, extended.operand);
31953207 var extra_index: usize = extra.end;
......@@ -3197,6 +3209,11 @@ fn zirUnionDecl(
31973209 const src = extra.data.src();
31983210
31993211 extra_index += @intFromBool(small.has_tag_type);
3212 const captures_len = if (small.has_captures_len) blk: {
3213 const captures_len = sema.code.extra[extra_index];
3214 extra_index += 1;
3215 break :blk captures_len;
3216 } else 0;
32003217 extra_index += @intFromBool(small.has_body_len);
32013218 const fields_len = if (small.has_fields_len) blk: {
32023219 const fields_len = sema.code.extra[extra_index];
......@@ -3210,16 +3227,53 @@ fn zirUnionDecl(
32103227 break :blk decls_len;
32113228 } else 0;
32123229
3213 // Because these three things each reference each other, `undefined`
3214 // placeholders are used before being set after the union type gains an
3215 // InternPool index.
3230 const captures = try sema.getCaptures(block, extra_index, captures_len);
3231 extra_index += captures_len;
3232
3233 const wip_ty = switch (try ip.getUnionType(gpa, .{
3234 .flags = .{
3235 .layout = small.layout,
3236 .status = .none,
3237 .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
3238 .tagged
3239 else if (small.layout != .Auto)
3240 .none
3241 else switch (block.wantSafety()) {
3242 true => .safety,
3243 false => .none,
3244 },
3245 .any_aligned_fields = small.any_aligned_fields,
3246 .requires_comptime = .unknown,
3247 .assumed_runtime_bits = false,
3248 .assumed_pointer_aligned = false,
3249 .alignment = .none,
3250 },
3251 .has_namespace = true or decls_len != 0, // TODO: see below
3252 .fields_len = fields_len,
3253 .enum_tag_ty = .none, // set later
3254 .field_types = &.{}, // set later
3255 .field_aligns = &.{}, // set later
3256 .key = .{ .declared = .{
3257 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
3258 .captures = captures,
3259 } },
3260 })) {
3261 .wip => |wip| wip: {
3262 if (sema.builtin_type_target_index == .none) break :wip wip;
3263 var new = wip;
3264 new.index = sema.builtin_type_target_index;
3265 ip.resolveBuiltinType(new.index, wip.index);
3266 break :wip new;
3267 },
3268 .existing => |ty| return Air.internedToRef(ty),
3269 };
3270 errdefer wip_ty.cancel(ip);
32163271
32173272 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
3218 .ty = Type.noreturn,
3219 .val = Value.@"unreachable",
3273 .ty = Type.type,
3274 .val = Value.fromInterned(wip_ty.index),
32203275 }, small.name_strategy, "union", inst);
3221 const new_decl = mod.declPtr(new_decl_index);
3222 new_decl.owns_tv = true;
3276 mod.declPtr(new_decl_index).owns_tv = true;
32233277 errdefer mod.abortAnonDecl(new_decl_index);
32243278
32253279 if (sema.mod.comp.debug_incremental) {
......@@ -3230,58 +3284,22 @@ fn zirUnionDecl(
32303284 );
32313285 }
32323286
3233 const new_namespace_index = try mod.createNamespace(.{
3287 // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
3288 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{
32343289 .parent = block.namespace.toOptional(),
32353290 .decl_index = new_decl_index,
32363291 .file_scope = block.getFileScope(mod),
3237 });
3238 errdefer mod.destroyNamespace(new_namespace_index);
3292 })).toOptional() else .none;
3293 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
32393294
3240 const union_ty = ty: {
3241 const ty = try mod.intern_pool.getUnionType(gpa, .{
3242 .flags = .{
3243 .layout = small.layout,
3244 .status = .none,
3245 .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
3246 .tagged
3247 else if (small.layout != .Auto)
3248 .none
3249 else switch (block.wantSafety()) {
3250 true => .safety,
3251 false => .none,
3252 },
3253 .any_aligned_fields = small.any_aligned_fields,
3254 .requires_comptime = .unknown,
3255 .assumed_runtime_bits = false,
3256 .assumed_pointer_aligned = false,
3257 .alignment = .none,
3258 },
3259 .decl = new_decl_index,
3260 .namespace = new_namespace_index,
3261 .zir_index = (try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst)).toOptional(),
3262 .fields_len = fields_len,
3263 .enum_tag_ty = .none,
3264 .field_types = &.{},
3265 .field_aligns = &.{},
3266 });
3267 if (sema.builtin_type_target_index != .none) {
3268 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty);
3269 break :ty sema.builtin_type_target_index;
3270 }
3271 break :ty ty;
3272 };
3273 // TODO: figure out InternPool removals for incremental compilation
3274 //errdefer mod.intern_pool.remove(union_ty);
3275
3276 new_decl.ty = Type.type;
3277 new_decl.val = Value.fromInterned(union_ty);
3278
3279 const decls = sema.code.bodySlice(extra_index, decls_len);
3280 try mod.scanNamespace(new_namespace_index, decls, new_decl);
3295 if (new_namespace_index.unwrap()) |ns| {
3296 const decls = sema.code.bodySlice(extra_index, decls_len);
3297 try mod.scanNamespace(ns, decls, mod.declPtr(new_decl_index));
3298 }
32813299
3282 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
32833300 try mod.finalizeAnonDecl(new_decl_index);
3284 return decl_val;
3301
3302 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
32853303}
32863304
32873305fn zirOpaqueDecl(
......@@ -3294,62 +3312,72 @@ fn zirOpaqueDecl(
32943312 defer tracy.end();
32953313
32963314 const mod = sema.mod;
3315 const gpa = sema.gpa;
3316 const ip = &mod.intern_pool;
3317
32973318 const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
32983319 const extra = sema.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
32993320 var extra_index: usize = extra.end;
33003321
33013322 const src = extra.data.src();
33023323
3324 const captures_len = if (small.has_captures_len) blk: {
3325 const captures_len = sema.code.extra[extra_index];
3326 extra_index += 1;
3327 break :blk captures_len;
3328 } else 0;
3329
33033330 const decls_len = if (small.has_decls_len) blk: {
33043331 const decls_len = sema.code.extra[extra_index];
33053332 extra_index += 1;
33063333 break :blk decls_len;
33073334 } else 0;
33083335
3309 // Because these three things each reference each other, `undefined`
3310 // placeholders are used in two places before being set after the opaque
3311 // type gains an InternPool index.
3336 const captures = try sema.getCaptures(block, extra_index, captures_len);
3337 extra_index += captures_len;
3338
3339 const wip_ty = switch (try ip.getOpaqueType(gpa, .{
3340 .has_namespace = decls_len != 0,
3341 .key = .{ .declared = .{
3342 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
3343 .captures = captures,
3344 } },
3345 })) {
3346 .wip => |wip| wip,
3347 .existing => |ty| return Air.internedToRef(ty),
3348 };
3349 errdefer wip_ty.cancel(ip);
33123350
33133351 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
3314 .ty = Type.noreturn,
3315 .val = Value.@"unreachable",
3352 .ty = Type.type,
3353 .val = Value.fromInterned(wip_ty.index),
33163354 }, small.name_strategy, "opaque", inst);
3317 const new_decl = mod.declPtr(new_decl_index);
3318 new_decl.owns_tv = true;
3355 mod.declPtr(new_decl_index).owns_tv = true;
33193356 errdefer mod.abortAnonDecl(new_decl_index);
33203357
33213358 if (sema.mod.comp.debug_incremental) {
3322 try mod.intern_pool.addDependency(
3323 sema.gpa,
3359 try ip.addDependency(
3360 gpa,
33243361 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
3325 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
3362 .{ .src_hash = try ip.trackZir(gpa, block.getFileScope(mod), inst) },
33263363 );
33273364 }
33283365
3329 const new_namespace_index = try mod.createNamespace(.{
3366 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (decls_len > 0) (try mod.createNamespace(.{
33303367 .parent = block.namespace.toOptional(),
33313368 .decl_index = new_decl_index,
33323369 .file_scope = block.getFileScope(mod),
3333 });
3334 errdefer mod.destroyNamespace(new_namespace_index);
3370 })).toOptional() else .none;
3371 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
33353372
3336 const opaque_ty = try mod.intern(.{ .opaque_type = .{
3337 .decl = new_decl_index,
3338 .namespace = new_namespace_index,
3339 .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
3340 } });
3341 // TODO: figure out InternPool removals for incremental compilation
3342 //errdefer mod.intern_pool.remove(opaque_ty);
3343
3344 new_decl.ty = Type.type;
3345 new_decl.val = Value.fromInterned(opaque_ty);
3346
3347 const decls = sema.code.bodySlice(extra_index, decls_len);
3348 try mod.scanNamespace(new_namespace_index, decls, new_decl);
3373 if (new_namespace_index.unwrap()) |ns| {
3374 const decls = sema.code.bodySlice(extra_index, decls_len);
3375 try mod.scanNamespace(ns, decls, mod.declPtr(new_decl_index));
3376 }
33493377
3350 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
33513378 try mod.finalizeAnonDecl(new_decl_index);
3352 return decl_val;
3379
3380 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
33533381}
33543382
33553383fn zirErrorSetDecl(
......@@ -5333,7 +5361,7 @@ fn failWithBadMemberAccess(
53335361fn failWithBadStructFieldAccess(
53345362 sema: *Sema,
53355363 block: *Block,
5336 struct_type: InternPool.Key.StructType,
5364 struct_type: InternPool.LoadedStructType,
53375365 field_src: LazySrcLoc,
53385366 field_name: InternPool.NullTerminatedString,
53395367) CompileError {
......@@ -5359,7 +5387,7 @@ fn failWithBadStructFieldAccess(
53595387fn failWithBadUnionFieldAccess(
53605388 sema: *Sema,
53615389 block: *Block,
5362 union_obj: InternPool.UnionType,
5390 union_obj: InternPool.LoadedUnionType,
53635391 field_src: LazySrcLoc,
53645392 field_name: InternPool.NullTerminatedString,
53655393) CompileError {
......@@ -5780,7 +5808,6 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
57805808 .sema = sema,
57815809 .src_decl = parent_block.src_decl,
57825810 .namespace = parent_block.namespace,
5783 .wip_capture_scope = parent_block.wip_capture_scope,
57845811 .instructions = .{},
57855812 .inlining = parent_block.inlining,
57865813 .is_comptime = true,
......@@ -5831,6 +5858,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
58315858 .global = comp.config,
58325859 .parent = parent_mod,
58335860 .builtin_mod = parent_mod.getBuiltinDependency(),
5861 .builtin_modules = null, // `builtin_mod` is set
58345862 }) catch |err| switch (err) {
58355863 // None of these are possible because we are creating a package with
58365864 // the exact same configuration as the parent package, which already
......@@ -5900,7 +5928,6 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index, force_compt
59005928 .sema = sema,
59015929 .src_decl = parent_block.src_decl,
59025930 .namespace = parent_block.namespace,
5903 .wip_capture_scope = parent_block.wip_capture_scope,
59045931 .instructions = .{},
59055932 .label = &label,
59065933 .inlining = parent_block.inlining,
......@@ -7515,7 +7542,6 @@ fn analyzeCall(
75157542 .sema = sema,
75167543 .src_decl = module_fn.owner_decl,
75177544 .namespace = fn_owner_decl.src_namespace,
7518 .wip_capture_scope = try mod.createCaptureScope(fn_owner_decl.src_scope),
75197545 .instructions = .{},
75207546 .label = null,
75217547 .inlining = &inlining,
......@@ -8036,7 +8062,6 @@ fn instantiateGenericCall(
80368062 .sema = &child_sema,
80378063 .src_decl = generic_owner_func.owner_decl,
80388064 .namespace = namespace_index,
8039 .wip_capture_scope = try mod.createCaptureScope(fn_owner_decl.src_scope),
80408065 .instructions = .{},
80418066 .inlining = null,
80428067 .is_comptime = true,
......@@ -11409,7 +11434,6 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
1140911434 .sema = sema,
1141011435 .src_decl = block.src_decl,
1141111436 .namespace = block.namespace,
11412 .wip_capture_scope = block.wip_capture_scope,
1141311437 .instructions = .{},
1141411438 .label = &label,
1141511439 .inlining = block.inlining,
......@@ -12117,7 +12141,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1211712141 .sema = sema,
1211812142 .src_decl = block.src_decl,
1211912143 .namespace = block.namespace,
12120 .wip_capture_scope = block.wip_capture_scope,
1212112144 .instructions = .{},
1212212145 .label = &label,
1212312146 .inlining = block.inlining,
......@@ -12281,7 +12304,6 @@ fn analyzeSwitchRuntimeBlock(
1228112304 extra_index += info.body_len;
1228212305
1228312306 case_block.instructions.shrinkRetainingCapacity(0);
12284 case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
1228512307
1228612308 const item = case_vals.items[scalar_i];
1228712309 // `item` is already guaranteed to be constant known.
......@@ -12339,7 +12361,6 @@ fn analyzeSwitchRuntimeBlock(
1233912361 case_val_idx += items_len;
1234012362
1234112363 case_block.instructions.shrinkRetainingCapacity(0);
12342 case_block.wip_capture_scope = child_block.wip_capture_scope;
1234312364
1234412365 // Generate all possible cases as scalar prongs.
1234512366 if (info.is_inline) {
......@@ -12371,7 +12392,6 @@ fn analyzeSwitchRuntimeBlock(
1237112392 const item_ref = Air.internedToRef(item.toIntern());
1237212393
1237312394 case_block.instructions.shrinkRetainingCapacity(0);
12374 case_block.wip_capture_scope = child_block.wip_capture_scope;
1237512395
1237612396 if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) {
1237712397 error.NeededSourceLocation => {
......@@ -12411,7 +12431,6 @@ fn analyzeSwitchRuntimeBlock(
1241112431 cases_len += 1;
1241212432
1241312433 case_block.instructions.shrinkRetainingCapacity(0);
12414 case_block.wip_capture_scope = child_block.wip_capture_scope;
1241512434
1241612435 const analyze_body = if (union_originally) blk: {
1241712436 const item_val = sema.resolveConstDefinedValue(block, .unneeded, item, undefined) catch unreachable;
......@@ -12557,7 +12576,6 @@ fn analyzeSwitchRuntimeBlock(
1255712576 defer gpa.free(cond_body);
1255812577
1255912578 case_block.instructions.shrinkRetainingCapacity(0);
12560 case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
1256112579
1256212580 const body = sema.code.bodySlice(extra_index, info.body_len);
1256312581 extra_index += info.body_len;
......@@ -12618,7 +12636,6 @@ fn analyzeSwitchRuntimeBlock(
1261812636 const item_ref = Air.internedToRef(item_val.toIntern());
1261912637
1262012638 case_block.instructions.shrinkRetainingCapacity(0);
12621 case_block.wip_capture_scope = child_block.wip_capture_scope;
1262212639
1262312640 const analyze_body = if (union_originally) blk: {
1262412641 const field_ty = maybe_union_ty.unionFieldType(item_val, mod).?;
......@@ -12669,7 +12686,6 @@ fn analyzeSwitchRuntimeBlock(
1266912686 const item_ref = Air.internedToRef(item_val);
1267012687
1267112688 case_block.instructions.shrinkRetainingCapacity(0);
12672 case_block.wip_capture_scope = child_block.wip_capture_scope;
1267312689
1267412690 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
1267512691 emit_bb = true;
......@@ -12700,7 +12716,6 @@ fn analyzeSwitchRuntimeBlock(
1270012716 const item_ref = Air.internedToRef(cur);
1270112717
1270212718 case_block.instructions.shrinkRetainingCapacity(0);
12703 case_block.wip_capture_scope = child_block.wip_capture_scope;
1270412719
1270512720 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
1270612721 emit_bb = true;
......@@ -12728,7 +12743,6 @@ fn analyzeSwitchRuntimeBlock(
1272812743 cases_len += 1;
1272912744
1273012745 case_block.instructions.shrinkRetainingCapacity(0);
12731 case_block.wip_capture_scope = child_block.wip_capture_scope;
1273212746
1273312747 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
1273412748 emit_bb = true;
......@@ -12754,7 +12768,6 @@ fn analyzeSwitchRuntimeBlock(
1275412768 cases_len += 1;
1275512769
1275612770 case_block.instructions.shrinkRetainingCapacity(0);
12757 case_block.wip_capture_scope = child_block.wip_capture_scope;
1275812771
1275912772 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
1276012773 emit_bb = true;
......@@ -12783,7 +12796,6 @@ fn analyzeSwitchRuntimeBlock(
1278312796 };
1278412797
1278512798 case_block.instructions.shrinkRetainingCapacity(0);
12786 case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
1278712799
1278812800 if (mod.backendSupportsFeature(.is_named_enum_value) and
1278912801 special.body.len != 0 and block.wantSafety() and
......@@ -13327,7 +13339,7 @@ fn validateSwitchItemEnum(
1332713339 const ip = &sema.mod.intern_pool;
1332813340 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
1332913341 const int = ip.indexToKey(item.val).enum_tag.int;
13330 const field_index = ip.indexToKey(ip.typeOf(item.val)).enum_type.tagValueIndex(ip, int) orelse {
13342 const field_index = ip.loadEnumType(ip.typeOf(item.val)).tagValueIndex(ip, int) orelse {
1333113343 const maybe_prev_src = try range_set.add(int, int, switch_prong_src);
1333213344 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
1333313345 return item.ref;
......@@ -13607,15 +13619,15 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1360713619 break :hf field_index < ty.structFieldCount(mod);
1360813620 }
1360913621 },
13610 .struct_type => |struct_type| {
13611 break :hf struct_type.nameIndex(ip, field_name) != null;
13622 .struct_type => {
13623 break :hf ip.loadStructType(ty.toIntern()).nameIndex(ip, field_name) != null;
1361213624 },
13613 .union_type => |union_type| {
13614 const union_obj = ip.loadUnionType(union_type);
13615 break :hf union_obj.nameIndex(ip, field_name) != null;
13625 .union_type => {
13626 const union_type = ip.loadUnionType(ty.toIntern());
13627 break :hf union_type.loadTagType(ip).nameIndex(ip, field_name) != null;
1361613628 },
13617 .enum_type => |enum_type| {
13618 break :hf enum_type.nameIndex(ip, field_name) != null;
13629 .enum_type => {
13630 break :hf ip.loadEnumType(ty.toIntern()).nameIndex(ip, field_name) != null;
1361913631 },
1362013632 .array_type => break :hf ip.stringEqlSlice(field_name, "len"),
1362113633 else => {},
......@@ -17264,49 +17276,19 @@ fn zirThis(
1726417276 return sema.analyzeDeclVal(block, src, this_decl_index);
1726517277}
1726617278
17267fn zirClosureCapture(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
17279fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
1726817280 const mod = sema.mod;
17269 const gpa = sema.gpa;
17270 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_tok;
17271 // Closures are not necessarily constant values. For example, the
17272 // code might do something like this:
17273 // fn foo(x: anytype) void { const S = struct {field: @TypeOf(x)}; }
17274 // ...in which case the closure_capture instruction has access to a runtime
17275 // value only. In such case only the type is saved into the scope.
17276 const operand = try sema.resolveInst(inst_data.operand);
17277 const ty = sema.typeOf(operand);
17278 const key: CaptureScope.Key = .{
17279 .zir_index = inst,
17280 .index = block.wip_capture_scope,
17281 };
17282 if (try sema.resolveValue(operand)) |val| {
17283 try mod.comptime_capture_scopes.put(gpa, key, try val.intern(ty, mod));
17284 } else {
17285 try mod.runtime_capture_scopes.put(gpa, key, ty.toIntern());
17286 }
17287}
17281 const ip = &mod.intern_pool;
17282 const captures = mod.namespacePtr(block.namespace).getType(mod).getCaptures(mod);
1728817283
17289fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
17290 const mod = sema.mod;
17291 //const ip = &mod.intern_pool;
17292 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].inst_node;
17293 var scope: CaptureScope.Index = mod.declPtr(block.src_decl).src_scope;
17294 assert(scope != .none);
17295 // Note: The target closure must be in this scope list.
17296 // If it's not here, the zir is invalid, or the list is broken.
17297 const capture_ty = while (true) {
17298 // Note: We don't need to add a dependency here, because
17299 // decls always depend on their lexical parents.
17300 const key: CaptureScope.Key = .{
17301 .zir_index = inst_data.inst,
17302 .index = scope,
17303 };
17304 if (mod.comptime_capture_scopes.get(key)) |val|
17305 return Air.internedToRef(val);
17306 if (mod.runtime_capture_scopes.get(key)) |ty|
17307 break ty;
17308 scope = scope.parent(mod);
17309 assert(scope != .none);
17284 const src_node: i32 = @bitCast(extended.operand);
17285 const src = LazySrcLoc.nodeOffset(src_node);
17286
17287 const capture_ty = switch (captures.get(ip)[extended.small].unwrap()) {
17288 .@"comptime" => |index| return Air.internedToRef(index),
17289 .runtime => |index| index,
17290 .decl_val => |decl_index| return sema.analyzeDeclVal(block, src, decl_index),
17291 .decl_ref => |decl_index| return sema.analyzeDeclRef(decl_index),
1731017292 };
1731117293
1731217294 // The comptime case is handled already above. Runtime case below.
......@@ -17322,15 +17304,15 @@ fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1732217304 });
1732317305 break :name null;
1732417306 };
17325 const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node);
17307 const node = sema.owner_decl.relativeToNodeIndex(src_node);
1732617308 const token = tree.nodes.items(.main_token)[node];
1732717309 break :name tree.tokenSlice(token);
1732817310 };
1732917311
1733017312 const msg = if (name) |some|
17331 try sema.errMsg(block, inst_data.src(), "'{s}' not accessible outside function scope", .{some})
17313 try sema.errMsg(block, src, "'{s}' not accessible outside function scope", .{some})
1733217314 else
17333 try sema.errMsg(block, inst_data.src(), "variable not accessible outside function scope", .{});
17315 try sema.errMsg(block, src, "variable not accessible outside function scope", .{});
1733417316 errdefer msg.destroy(sema.gpa);
1733517317
1733617318 // TODO add "declared here" note
......@@ -17350,15 +17332,15 @@ fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1735017332 });
1735117333 break :name null;
1735217334 };
17353 const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node);
17335 const node = sema.owner_decl.relativeToNodeIndex(src_node);
1735417336 const token = tree.nodes.items(.main_token)[node];
1735517337 break :name tree.tokenSlice(token);
1735617338 };
1735717339
1735817340 const msg = if (name) |some|
17359 try sema.errMsg(block, inst_data.src(), "'{s}' not accessible from inner function", .{some})
17341 try sema.errMsg(block, src, "'{s}' not accessible from inner function", .{some})
1736017342 else
17361 try sema.errMsg(block, inst_data.src(), "variable not accessible from inner function", .{});
17343 try sema.errMsg(block, src, "variable not accessible from inner function", .{});
1736217344 errdefer msg.destroy(sema.gpa);
1736317345
1736417346 try sema.errNote(block, LazySrcLoc.nodeOffset(0), msg, "crossed function definition here", .{});
......@@ -17954,7 +17936,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1795417936 } })));
1795517937 },
1795617938 .Enum => {
17957 const is_exhaustive = Value.makeBool(ip.indexToKey(ty.toIntern()).enum_type.tag_mode != .nonexhaustive);
17939 const is_exhaustive = Value.makeBool(ip.loadEnumType(ty.toIntern()).tag_mode != .nonexhaustive);
1795817940
1795917941 const enum_field_ty = t: {
1796017942 const enum_field_ty_decl_index = (try sema.namespaceLookup(
......@@ -17968,9 +17950,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1796817950 break :t enum_field_ty_decl.val.toType();
1796917951 };
1797017952
17971 const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.indexToKey(ty.toIntern()).enum_type.names.len);
17953 const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.loadEnumType(ty.toIntern()).names.len);
1797217954 for (enum_field_vals, 0..) |*field_val, i| {
17973 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
17955 const enum_type = ip.loadEnumType(ty.toIntern());
1797417956 const value_val = if (enum_type.values.len > 0)
1797517957 try mod.intern_pool.getCoercedInts(
1797617958 mod.gpa,
......@@ -18045,7 +18027,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1804518027 } });
1804618028 };
1804718029
18048 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ip.indexToKey(ty.toIntern()).enum_type.namespace);
18030 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ip.loadEnumType(ty.toIntern()).namespace);
1804918031
1805018032 const type_enum_ty = t: {
1805118033 const type_enum_ty_decl_index = (try sema.namespaceLookup(
......@@ -18061,7 +18043,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1806118043
1806218044 const field_values = .{
1806318045 // tag_type: type,
18064 ip.indexToKey(ty.toIntern()).enum_type.tag_ty,
18046 ip.loadEnumType(ty.toIntern()).tag_ty,
1806518047 // fields: []const EnumField,
1806618048 fields_val,
1806718049 // decls: []const Declaration,
......@@ -18105,14 +18087,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1810518087
1810618088 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
1810718089 const union_obj = mod.typeToUnion(ty).?;
18090 const tag_type = union_obj.loadTagType(ip);
1810818091 const layout = union_obj.getLayout(ip);
1810918092
18110 const union_field_vals = try gpa.alloc(InternPool.Index, union_obj.field_names.len);
18093 const union_field_vals = try gpa.alloc(InternPool.Index, tag_type.names.len);
1811118094 defer gpa.free(union_field_vals);
1811218095
1811318096 for (union_field_vals, 0..) |*field_val, i| {
1811418097 // TODO: write something like getCoercedInts to avoid needing to dupe
18115 const name = try sema.arena.dupeZ(u8, ip.stringToSlice(union_obj.field_names.get(ip)[i]));
18098 const name = try sema.arena.dupeZ(u8, ip.stringToSlice(tag_type.names.get(ip)[i]));
1811618099 const name_val = v: {
1811718100 const new_decl_ty = try mod.arrayType(.{
1811818101 .len = name.len,
......@@ -18314,7 +18297,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1831418297 }
1831518298 break :fv;
1831618299 },
18317 .struct_type => |s| s,
18300 .struct_type => ip.loadStructType(ty.toIntern()),
1831818301 else => unreachable,
1831918302 };
1832018303 struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);
......@@ -18631,7 +18614,6 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
1863118614 .sema = sema,
1863218615 .src_decl = block.src_decl,
1863318616 .namespace = block.namespace,
18634 .wip_capture_scope = block.wip_capture_scope,
1863518617 .instructions = .{},
1863618618 .inlining = block.inlining,
1863718619 .is_comptime = false,
......@@ -18710,7 +18692,6 @@ fn zirTypeofPeer(
1871018692 .sema = sema,
1871118693 .src_decl = block.src_decl,
1871218694 .namespace = block.namespace,
18713 .wip_capture_scope = block.wip_capture_scope,
1871418695 .instructions = .{},
1871518696 .inlining = block.inlining,
1871618697 .is_comptime = false,
......@@ -19186,7 +19167,6 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label
1918619167 .sema = sema,
1918719168 .src_decl = block.src_decl,
1918819169 .namespace = block.namespace,
19189 .wip_capture_scope = block.wip_capture_scope,
1919019170 .instructions = .{},
1919119171 .label = &labeled_block.label,
1919219172 .inlining = block.inlining,
......@@ -20082,7 +20062,8 @@ fn finishStructInit(
2008220062 }
2008320063 }
2008420064 },
20085 .struct_type => |struct_type| {
20065 .struct_type => {
20066 const struct_type = ip.loadStructType(struct_ty.toIntern());
2008620067 for (0..struct_type.field_types.len) |i| {
2008720068 if (field_inits[i] != .none) {
2008820069 // Coerce the init value to the field type.
......@@ -20683,7 +20664,8 @@ fn fieldType(
2068320664 try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);
2068420665 return Air.internedToRef(anon_struct.types.get(ip)[field_index]);
2068520666 },
20686 .struct_type => |struct_type| {
20667 .struct_type => {
20668 const struct_type = ip.loadStructType(cur_ty.toIntern());
2068720669 const field_index = struct_type.nameIndex(ip, field_name) orelse
2068820670 return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name);
2068920671 const field_ty = struct_type.field_types.get(ip)[field_index];
......@@ -20693,7 +20675,7 @@ fn fieldType(
2069320675 },
2069420676 .Union => {
2069520677 const union_obj = mod.typeToUnion(cur_ty).?;
20696 const field_index = union_obj.nameIndex(ip, field_name) orelse
20678 const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse
2069720679 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
2069820680 const field_ty = union_obj.field_types.get(ip)[field_index];
2069920681 return Air.internedToRef(field_ty);
......@@ -21022,7 +21004,7 @@ fn zirReify(
2102221004 .AnyFrame => return sema.failWithUseOfAsync(block, src),
2102321005 .EnumLiteral => return .enum_literal_type,
2102421006 .Int => {
21025 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21007 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2102621008 const signedness_val = try Value.fromInterned(union_val.val).fieldValue(
2102721009 mod,
2102821010 struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "signedness")).?,
......@@ -21038,7 +21020,7 @@ fn zirReify(
2103821020 return Air.internedToRef(ty.toIntern());
2103921021 },
2104021022 .Vector => {
21041 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21023 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2104221024 const len_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2104321025 ip,
2104421026 try ip.getOrPutString(gpa, "len"),
......@@ -21060,7 +21042,7 @@ fn zirReify(
2106021042 return Air.internedToRef(ty.toIntern());
2106121043 },
2106221044 .Float => {
21063 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21045 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2106421046 const bits_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2106521047 ip,
2106621048 try ip.getOrPutString(gpa, "bits"),
......@@ -21078,7 +21060,7 @@ fn zirReify(
2107821060 return Air.internedToRef(ty.toIntern());
2107921061 },
2108021062 .Pointer => {
21081 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21063 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2108221064 const size_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2108321065 ip,
2108421066 try ip.getOrPutString(gpa, "size"),
......@@ -21190,7 +21172,7 @@ fn zirReify(
2119021172 return Air.internedToRef(ty.toIntern());
2119121173 },
2119221174 .Array => {
21193 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21175 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2119421176 const len_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2119521177 ip,
2119621178 try ip.getOrPutString(gpa, "len"),
......@@ -21219,7 +21201,7 @@ fn zirReify(
2121921201 return Air.internedToRef(ty.toIntern());
2122021202 },
2122121203 .Optional => {
21222 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21204 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2122321205 const child_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2122421206 ip,
2122521207 try ip.getOrPutString(gpa, "child"),
......@@ -21231,7 +21213,7 @@ fn zirReify(
2123121213 return Air.internedToRef(ty.toIntern());
2123221214 },
2123321215 .ErrorUnion => {
21234 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21216 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2123521217 const error_set_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2123621218 ip,
2123721219 try ip.getOrPutString(gpa, "error_set"),
......@@ -21260,7 +21242,7 @@ fn zirReify(
2126021242 try names.ensureUnusedCapacity(sema.arena, len);
2126121243 for (0..len) |i| {
2126221244 const elem_val = try payload_val.elemValue(mod, i);
21263 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
21245 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
2126421246 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
2126521247 ip,
2126621248 try ip.getOrPutString(gpa, "name"),
......@@ -21280,7 +21262,7 @@ fn zirReify(
2128021262 return Air.internedToRef(ty.toIntern());
2128121263 },
2128221264 .Struct => {
21283 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21265 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2128421266 const layout_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2128521267 ip,
2128621268 try ip.getOrPutString(gpa, "layout"),
......@@ -21316,7 +21298,7 @@ fn zirReify(
2131621298 return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());
2131721299 },
2131821300 .Enum => {
21319 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21301 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2132021302 const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2132121303 ip,
2132221304 try ip.getOrPutString(gpa, "tag_type"),
......@@ -21334,105 +21316,14 @@ fn zirReify(
2133421316 try ip.getOrPutString(gpa, "is_exhaustive"),
2133521317 ).?);
2133621318
21337 // Decls
2133821319 if (decls_val.sliceLen(mod) > 0) {
2133921320 return sema.fail(block, src, "reified enums must have no decls", .{});
2134021321 }
2134121322
21342 const int_tag_ty = tag_type_val.toType();
21343 if (int_tag_ty.zigTypeTag(mod) != .Int) {
21344 return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
21345 }
21346
21347 // Because these things each reference each other, `undefined`
21348 // placeholders are used before being set after the enum type gains
21349 // an InternPool index.
21350
21351 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21352 .ty = Type.noreturn,
21353 .val = Value.@"unreachable",
21354 }, name_strategy, "enum", inst);
21355 const new_decl = mod.declPtr(new_decl_index);
21356 new_decl.owns_tv = true;
21357 errdefer {
21358 new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
21359 mod.abortAnonDecl(new_decl_index);
21360 }
21361
21362 // Define our empty enum decl
21363 const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
21364 const incomplete_enum = try ip.getIncompleteEnum(gpa, .{
21365 .decl = new_decl_index,
21366 .namespace = .none,
21367 .fields_len = fields_len,
21368 .has_values = true,
21369 .tag_mode = if (!is_exhaustive_val.toBool())
21370 .nonexhaustive
21371 else
21372 .explicit,
21373 .tag_ty = int_tag_ty.toIntern(),
21374 .zir_index = .none,
21375 });
21376 // TODO: figure out InternPool removals for incremental compilation
21377 //errdefer ip.remove(incomplete_enum.index);
21378
21379 new_decl.ty = Type.type;
21380 new_decl.val = Value.fromInterned(incomplete_enum.index);
21381
21382 for (0..fields_len) |field_i| {
21383 const elem_val = try fields_val.elemValue(mod, field_i);
21384 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
21385 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21386 ip,
21387 try ip.getOrPutString(gpa, "name"),
21388 ).?);
21389 const value_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21390 ip,
21391 try ip.getOrPutString(gpa, "value"),
21392 ).?);
21393
21394 const field_name = try name_val.toIpString(Type.slice_const_u8, mod);
21395
21396 if (!try sema.intFitsInType(value_val, int_tag_ty, null)) {
21397 // TODO: better source location
21398 return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{
21399 field_name.fmt(ip),
21400 value_val.fmtValue(Type.comptime_int, mod),
21401 int_tag_ty.fmt(mod),
21402 });
21403 }
21404
21405 if (incomplete_enum.addFieldName(ip, field_name)) |other_index| {
21406 const msg = msg: {
21407 const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{
21408 field_name.fmt(ip),
21409 });
21410 errdefer msg.destroy(gpa);
21411 _ = other_index; // TODO: this note is incorrect
21412 try sema.errNote(block, src, msg, "other field here", .{});
21413 break :msg msg;
21414 };
21415 return sema.failWithOwnedErrorMsg(block, msg);
21416 }
21417
21418 if (incomplete_enum.addFieldValue(ip, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| {
21419 const msg = msg: {
21420 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)});
21421 errdefer msg.destroy(gpa);
21422 _ = other; // TODO: this note is incorrect
21423 try sema.errNote(block, src, msg, "other enum tag value here", .{});
21424 break :msg msg;
21425 };
21426 return sema.failWithOwnedErrorMsg(block, msg);
21427 }
21428 }
21429
21430 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
21431 try mod.finalizeAnonDecl(new_decl_index);
21432 return decl_val;
21323 return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_val, name_strategy);
2143321324 },
2143421325 .Opaque => {
21435 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21326 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2143621327 const decls_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2143721328 ip,
2143821329 try ip.getOrPutString(gpa, "decls"),
......@@ -21443,45 +21334,30 @@ fn zirReify(
2144321334 return sema.fail(block, src, "reified opaque must have no decls", .{});
2144421335 }
2144521336
21446 // Because these three things each reference each other,
21447 // `undefined` placeholders are used in two places before being set
21448 // after the opaque type gains an InternPool index.
21337 const wip_ty = switch (try ip.getOpaqueType(gpa, .{
21338 .has_namespace = false,
21339 .key = .{ .reified = .{
21340 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
21341 } },
21342 })) {
21343 .existing => |ty| return Air.internedToRef(ty),
21344 .wip => |wip| wip,
21345 };
21346 errdefer wip_ty.cancel(ip);
2144921347
2145021348 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21451 .ty = Type.noreturn,
21452 .val = Value.@"unreachable",
21349 .ty = Type.type,
21350 .val = Value.fromInterned(wip_ty.index),
2145321351 }, name_strategy, "opaque", inst);
21454 const new_decl = mod.declPtr(new_decl_index);
21455 new_decl.owns_tv = true;
21456 errdefer {
21457 new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
21458 mod.abortAnonDecl(new_decl_index);
21459 }
21460
21461 const new_namespace_index = try mod.createNamespace(.{
21462 .parent = block.namespace.toOptional(),
21463 .decl_index = new_decl_index,
21464 .file_scope = block.getFileScope(mod),
21465 });
21466 errdefer mod.destroyNamespace(new_namespace_index);
21467
21468 const opaque_ty = try mod.intern(.{ .opaque_type = .{
21469 .decl = new_decl_index,
21470 .namespace = new_namespace_index,
21471 .zir_index = .none,
21472 } });
21473 // TODO: figure out InternPool removals for incremental compilation
21474 //errdefer ip.remove(opaque_ty);
21475
21476 new_decl.ty = Type.type;
21477 new_decl.val = Value.fromInterned(opaque_ty);
21352 mod.declPtr(new_decl_index).owns_tv = true;
21353 errdefer mod.abortAnonDecl(new_decl_index);
2147821354
21479 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
2148021355 try mod.finalizeAnonDecl(new_decl_index);
21481 return decl_val;
21356
21357 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
2148221358 },
2148321359 .Union => {
21484 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21360 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2148521361 const layout_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2148621362 ip,
2148721363 try ip.getOrPutString(gpa, "layout"),
......@@ -21499,216 +21375,15 @@ fn zirReify(
2149921375 try ip.getOrPutString(gpa, "decls"),
2150021376 ).?);
2150121377
21502 // Decls
2150321378 if (decls_val.sliceLen(mod) > 0) {
2150421379 return sema.fail(block, src, "reified unions must have no decls", .{});
2150521380 }
2150621381 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
21507 const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
21508
21509 // Tag type
21510 var explicit_tags_seen: []bool = &.{};
21511 var enum_field_names: []InternPool.NullTerminatedString = &.{};
21512 var enum_tag_ty: InternPool.Index = .none;
21513 if (tag_type_val.optionalValue(mod)) |payload_val| {
21514 enum_tag_ty = payload_val.toType().toIntern();
21515
21516 const enum_type = switch (ip.indexToKey(enum_tag_ty)) {
21517 .enum_type => |x| x,
21518 else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
21519 };
21520
21521 explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
21522 @memset(explicit_tags_seen, false);
21523 } else {
21524 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
21525 }
21526
21527 // Fields
21528 var any_aligned_fields: bool = false;
21529 var union_fields: std.MultiArrayList(struct {
21530 type: InternPool.Index,
21531 alignment: InternPool.Alignment,
21532 }) = .{};
21533 var field_name_table: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
21534 try field_name_table.ensureTotalCapacity(sema.arena, fields_len);
21535
21536 for (0..fields_len) |i| {
21537 const elem_val = try fields_val.elemValue(mod, i);
21538 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
21539 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21540 ip,
21541 try ip.getOrPutString(gpa, "name"),
21542 ).?);
21543 const type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21544 ip,
21545 try ip.getOrPutString(gpa, "type"),
21546 ).?);
21547 const alignment_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21548 ip,
21549 try ip.getOrPutString(gpa, "alignment"),
21550 ).?);
21551
21552 const field_name = try name_val.toIpString(Type.slice_const_u8, mod);
21553
21554 if (enum_field_names.len != 0) {
21555 enum_field_names[i] = field_name;
21556 }
21557
21558 if (enum_tag_ty != .none) {
21559 const tag_info = ip.indexToKey(enum_tag_ty).enum_type;
21560 const enum_index = tag_info.nameIndex(ip, field_name) orelse {
21561 return sema.fail(block, src, "no field named '{}' in enum '{}'", .{
21562 field_name.fmt(ip), Type.fromInterned(enum_tag_ty).fmt(mod),
21563 });
21564 };
21565 assert(explicit_tags_seen.len == tag_info.names.len);
21566 // No check for duplicate because the check already happened in order
21567 // to create the enum type in the first place.
21568 assert(!explicit_tags_seen[enum_index]);
21569 explicit_tags_seen[enum_index] = true;
21570 }
21571
21572 const gop = field_name_table.getOrPutAssumeCapacity(field_name);
21573 if (gop.found_existing) {
21574 // TODO: better source location
21575 return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
21576 }
21577
21578 const field_ty = type_val.toType();
21579 const alignment_val_int = (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?;
21580 if (alignment_val_int > 0 and !math.isPowerOfTwo(alignment_val_int)) {
21581 // TODO: better source location
21582 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{
21583 alignment_val_int,
21584 });
21585 }
21586 const field_align = Alignment.fromByteUnits(alignment_val_int);
21587 any_aligned_fields = any_aligned_fields or field_align != .none;
21588
21589 try union_fields.append(sema.arena, .{
21590 .type = field_ty.toIntern(),
21591 .alignment = field_align,
21592 });
2159321382
21594 if (field_ty.zigTypeTag(mod) == .Opaque) {
21595 const msg = msg: {
21596 const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
21597 errdefer msg.destroy(gpa);
21598
21599 try sema.addDeclaredHereNote(msg, field_ty);
21600 break :msg msg;
21601 };
21602 return sema.failWithOwnedErrorMsg(block, msg);
21603 }
21604 if (layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
21605 const msg = msg: {
21606 const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
21607 errdefer msg.destroy(gpa);
21608
21609 const src_decl = mod.declPtr(block.src_decl);
21610 try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), field_ty, .union_field);
21611
21612 try sema.addDeclaredHereNote(msg, field_ty);
21613 break :msg msg;
21614 };
21615 return sema.failWithOwnedErrorMsg(block, msg);
21616 } else if (layout == .Packed and !try sema.validatePackedType(field_ty)) {
21617 const msg = msg: {
21618 const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
21619 errdefer msg.destroy(gpa);
21620
21621 const src_decl = mod.declPtr(block.src_decl);
21622 try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(src, mod), field_ty);
21623
21624 try sema.addDeclaredHereNote(msg, field_ty);
21625 break :msg msg;
21626 };
21627 return sema.failWithOwnedErrorMsg(block, msg);
21628 }
21629 }
21630
21631 if (enum_tag_ty != .none) {
21632 const tag_info = ip.indexToKey(enum_tag_ty).enum_type;
21633 if (tag_info.names.len > fields_len) {
21634 const msg = msg: {
21635 const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});
21636 errdefer msg.destroy(gpa);
21637
21638 assert(explicit_tags_seen.len == tag_info.names.len);
21639 for (tag_info.names.get(ip), 0..) |field_name, field_index| {
21640 if (explicit_tags_seen[field_index]) continue;
21641 try sema.addFieldErrNote(Type.fromInterned(enum_tag_ty), field_index, msg, "field '{}' missing, declared here", .{
21642 field_name.fmt(ip),
21643 });
21644 }
21645 try sema.addDeclaredHereNote(msg, Type.fromInterned(enum_tag_ty));
21646 break :msg msg;
21647 };
21648 return sema.failWithOwnedErrorMsg(block, msg);
21649 }
21650 } else {
21651 enum_tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, .none);
21652 }
21653
21654 // Because these three things each reference each other, `undefined`
21655 // placeholders are used before being set after the union type gains an
21656 // InternPool index.
21657
21658 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21659 .ty = Type.noreturn,
21660 .val = Value.@"unreachable",
21661 }, name_strategy, "union", inst);
21662 const new_decl = mod.declPtr(new_decl_index);
21663 new_decl.owns_tv = true;
21664 errdefer {
21665 new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
21666 mod.abortAnonDecl(new_decl_index);
21667 }
21668
21669 const new_namespace_index = try mod.createNamespace(.{
21670 .parent = block.namespace.toOptional(),
21671 .decl_index = new_decl_index,
21672 .file_scope = block.getFileScope(mod),
21673 });
21674 errdefer mod.destroyNamespace(new_namespace_index);
21675
21676 const union_ty = try ip.getUnionType(gpa, .{
21677 .decl = new_decl_index,
21678 .namespace = new_namespace_index,
21679 .enum_tag_ty = enum_tag_ty,
21680 .fields_len = fields_len,
21681 .zir_index = .none,
21682 .flags = .{
21683 .layout = layout,
21684 .status = .have_field_types,
21685 .runtime_tag = if (!tag_type_val.isNull(mod))
21686 .tagged
21687 else if (layout != .Auto)
21688 .none
21689 else switch (block.wantSafety()) {
21690 true => .safety,
21691 false => .none,
21692 },
21693 .any_aligned_fields = any_aligned_fields,
21694 .requires_comptime = .unknown,
21695 .assumed_runtime_bits = false,
21696 .assumed_pointer_aligned = false,
21697 .alignment = .none,
21698 },
21699 .field_types = union_fields.items(.type),
21700 .field_aligns = if (any_aligned_fields) union_fields.items(.alignment) else &.{},
21701 });
21702
21703 new_decl.ty = Type.type;
21704 new_decl.val = Value.fromInterned(union_ty);
21705
21706 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
21707 try mod.finalizeAnonDecl(new_decl_index);
21708 return decl_val;
21383 return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_val, name_strategy);
2170921384 },
2171021385 .Fn => {
21711 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
21386 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
2171221387 const calling_convention_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2171321388 ip,
2171421389 try ip.getOrPutString(gpa, "calling_convention"),
......@@ -21759,7 +21434,7 @@ fn zirReify(
2175921434 var noalias_bits: u32 = 0;
2176021435 for (param_types, 0..) |*param_type, i| {
2176121436 const elem_val = try params_val.elemValue(mod, i);
21762 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
21437 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
2176321438 const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
2176421439 ip,
2176521440 try ip.getOrPutString(gpa, "is_generic"),
......@@ -21804,126 +21479,492 @@ fn zirReify(
2180421479 }
2180521480}
2180621481
21807fn reifyStruct(
21482fn reifyEnum(
2180821483 sema: *Sema,
2180921484 block: *Block,
2181021485 inst: Zir.Inst.Index,
2181121486 src: LazySrcLoc,
21812 layout: std.builtin.Type.ContainerLayout,
21813 backing_int_val: Value,
21487 tag_ty: Type,
21488 is_exhaustive: bool,
2181421489 fields_val: Value,
2181521490 name_strategy: Zir.Inst.NameStrategy,
21816 is_tuple: bool,
2181721491) CompileError!Air.Inst.Ref {
2181821492 const mod = sema.mod;
2181921493 const gpa = sema.gpa;
2182021494 const ip = &mod.intern_pool;
2182121495
21822 if (is_tuple) switch (layout) {
21823 .Extern => return sema.fail(block, src, "extern tuples are not supported", .{}),
21824 .Packed => return sema.fail(block, src, "packed tuples are not supported", .{}),
21825 .Auto => {},
21496 // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`.
21497
21498 const fields_len: u32 = @intCast(fields_val.sliceLen(mod));
21499
21500 // The validation work here is non-trivial, and it's possible the type already exists.
21501 // So in this first pass, let's just construct a hash to optimize for this case. If the
21502 // inputs turn out to be invalid, we can cancel the WIP type later.
21503
21504 // For deduplication purposes, we must create a hash including all details of this type.
21505 // TODO: use a longer hash!
21506 var hasher = std.hash.Wyhash.init(0);
21507 std.hash.autoHash(&hasher, tag_ty.toIntern());
21508 std.hash.autoHash(&hasher, is_exhaustive);
21509 std.hash.autoHash(&hasher, fields_len);
21510
21511 for (0..fields_len) |field_idx| {
21512 const field_info = try fields_val.elemValue(mod, field_idx);
21513
21514 const field_name_val = try field_info.fieldValue(mod, 0);
21515 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));
21516
21517 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21518
21519 std.hash.autoHash(&hasher, .{
21520 field_name,
21521 field_value_val.toIntern(),
21522 });
21523 }
21524
21525 const wip_ty = switch (try ip.getEnumType(gpa, .{
21526 .has_namespace = false,
21527 .has_values = true,
21528 .tag_mode = if (is_exhaustive) .explicit else .nonexhaustive,
21529 .fields_len = fields_len,
21530 .key = .{ .reified = .{
21531 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
21532 .type_hash = hasher.final(),
21533 } },
21534 })) {
21535 .wip => |wip| wip,
21536 .existing => |ty| return Air.internedToRef(ty),
2182621537 };
21538 errdefer wip_ty.cancel(ip);
21539
21540 if (tag_ty.zigTypeTag(mod) != .Int) {
21541 return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
21542 }
21543
21544 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21545 .ty = Type.type,
21546 .val = Value.fromInterned(wip_ty.index),
21547 }, name_strategy, "enum", inst);
21548 mod.declPtr(new_decl_index).owns_tv = true;
21549 errdefer mod.abortAnonDecl(new_decl_index);
21550
21551 wip_ty.prepare(ip, new_decl_index, .none);
21552 wip_ty.setTagTy(ip, tag_ty.toIntern());
21553
21554 for (0..fields_len) |field_idx| {
21555 const field_info = try fields_val.elemValue(mod, field_idx);
21556
21557 const field_name_val = try field_info.fieldValue(mod, 0);
21558 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));
21559
21560 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21561
21562 if (!try sema.intFitsInType(field_value_val, tag_ty, null)) {
21563 // TODO: better source location
21564 return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{
21565 field_name.fmt(ip),
21566 field_value_val.fmtValue(Type.comptime_int, mod),
21567 tag_ty.fmt(mod),
21568 });
21569 }
21570
21571 const coerced_field_val = try mod.getCoerced(field_value_val, tag_ty);
21572 if (wip_ty.nextField(ip, field_name, coerced_field_val.toIntern())) |conflict| {
21573 return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) {
21574 .name => msg: {
21575 const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{field_name.fmt(ip)});
21576 errdefer msg.destroy(gpa);
21577 _ = conflict.prev_field_idx; // TODO: this note is incorrect
21578 try sema.errNote(block, src, msg, "other field here", .{});
21579 break :msg msg;
21580 },
21581 .value => msg: {
21582 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{field_value_val.fmtValue(Type.comptime_int, mod)});
21583 errdefer msg.destroy(gpa);
21584 _ = conflict.prev_field_idx; // TODO: this note is incorrect
21585 try sema.errNote(block, src, msg, "other enum tag value here", .{});
21586 break :msg msg;
21587 },
21588 });
21589 }
21590 }
21591
21592 if (!is_exhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(mod)) {
21593 return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
21594 }
2182721595
21828 const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
21596 try mod.finalizeAnonDecl(new_decl_index);
21597 return Air.internedToRef(wip_ty.index);
21598}
2182921599
21830 // Because these three things each reference each other, `undefined`
21831 // placeholders are used before being set after the struct type gains an
21832 // InternPool index.
21600fn reifyUnion(
21601 sema: *Sema,
21602 block: *Block,
21603 inst: Zir.Inst.Index,
21604 src: LazySrcLoc,
21605 layout: std.builtin.Type.ContainerLayout,
21606 opt_tag_type_val: Value,
21607 fields_val: Value,
21608 name_strategy: Zir.Inst.NameStrategy,
21609) CompileError!Air.Inst.Ref {
21610 const mod = sema.mod;
21611 const gpa = sema.gpa;
21612 const ip = &mod.intern_pool;
21613
21614 // This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`.
21615
21616 const fields_len: u32 = @intCast(fields_val.sliceLen(mod));
21617
21618 // The validation work here is non-trivial, and it's possible the type already exists.
21619 // So in this first pass, let's just construct a hash to optimize for this case. If the
21620 // inputs turn out to be invalid, we can cancel the WIP type later.
21621
21622 // For deduplication purposes, we must create a hash including all details of this type.
21623 // TODO: use a longer hash!
21624 var hasher = std.hash.Wyhash.init(0);
21625 std.hash.autoHash(&hasher, layout);
21626 std.hash.autoHash(&hasher, opt_tag_type_val.toIntern());
21627 std.hash.autoHash(&hasher, fields_len);
21628
21629 var any_aligns = false;
21630
21631 for (0..fields_len) |field_idx| {
21632 const field_info = try fields_val.elemValue(mod, field_idx);
21633
21634 const field_name_val = try field_info.fieldValue(mod, 0);
21635 const field_type_val = try field_info.fieldValue(mod, 1);
21636 const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 2));
21637
21638 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21639
21640 std.hash.autoHash(&hasher, .{
21641 field_name,
21642 field_type_val.toIntern(),
21643 field_align_val.toIntern(),
21644 });
21645
21646 if (field_align_val.toUnsignedInt(mod) != 0) {
21647 any_aligns = true;
21648 }
21649 }
21650
21651 const wip_ty = switch (try ip.getUnionType(gpa, .{
21652 .flags = .{
21653 .layout = layout,
21654 .status = .none,
21655 .runtime_tag = if (opt_tag_type_val.optionalValue(mod) != null)
21656 .tagged
21657 else if (layout != .Auto)
21658 .none
21659 else switch (block.wantSafety()) {
21660 true => .safety,
21661 false => .none,
21662 },
21663 .any_aligned_fields = any_aligns,
21664 .requires_comptime = .unknown,
21665 .assumed_runtime_bits = false,
21666 .assumed_pointer_aligned = false,
21667 .alignment = .none,
21668 },
21669 .has_namespace = false,
21670 .fields_len = fields_len,
21671 .enum_tag_ty = .none, // set later because not yet validated
21672 .field_types = &.{}, // set later
21673 .field_aligns = &.{}, // set later
21674 .key = .{ .reified = .{
21675 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
21676 .type_hash = hasher.final(),
21677 } },
21678 })) {
21679 .wip => |wip| wip,
21680 .existing => |ty| return Air.internedToRef(ty),
21681 };
21682 errdefer wip_ty.cancel(ip);
2183321683
2183421684 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21835 .ty = Type.noreturn,
21836 .val = Value.@"unreachable",
21837 }, name_strategy, "struct", inst);
21838 const new_decl = mod.declPtr(new_decl_index);
21839 new_decl.owns_tv = true;
21840 errdefer {
21841 new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
21842 mod.abortAnonDecl(new_decl_index);
21685 .ty = Type.type,
21686 .val = Value.fromInterned(wip_ty.index),
21687 }, name_strategy, "union", inst);
21688 mod.declPtr(new_decl_index).owns_tv = true;
21689 errdefer mod.abortAnonDecl(new_decl_index);
21690
21691 const field_types = try sema.arena.alloc(InternPool.Index, fields_len);
21692 const field_aligns = if (any_aligns) try sema.arena.alloc(InternPool.Alignment, fields_len) else undefined;
21693
21694 const enum_tag_ty, const has_explicit_tag = if (opt_tag_type_val.optionalValue(mod)) |tag_type_val| tag_ty: {
21695 switch (ip.indexToKey(tag_type_val.toIntern())) {
21696 .enum_type => {},
21697 else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
21698 }
21699 const enum_tag_ty = tag_type_val.toType();
21700
21701 // We simply track which fields of the tag type have been seen.
21702 const tag_ty_fields_len = enum_tag_ty.enumFieldCount(mod);
21703 var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);
21704
21705 for (field_types, 0..) |*field_ty, field_idx| {
21706 const field_info = try fields_val.elemValue(mod, field_idx);
21707
21708 const field_name_val = try field_info.fieldValue(mod, 0);
21709 const field_type_val = try field_info.fieldValue(mod, 1);
21710
21711 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21712
21713 const enum_index = enum_tag_ty.enumFieldIndex(field_name, mod) orelse {
21714 // TODO: better source location
21715 return sema.fail(block, src, "no field named '{}' in enum '{}'", .{
21716 field_name.fmt(ip), enum_tag_ty.fmt(mod),
21717 });
21718 };
21719 if (seen_tags.isSet(enum_index)) {
21720 // TODO: better source location
21721 return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
21722 }
21723 seen_tags.set(enum_index);
21724
21725 field_ty.* = field_type_val.toIntern();
21726 if (any_aligns) {
21727 const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntAdvanced(sema);
21728 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
21729 // TODO: better source location
21730 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21731 }
21732 field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
21733 }
21734 }
21735
21736 if (tag_ty_fields_len > fields_len) return sema.failWithOwnedErrorMsg(block, msg: {
21737 const msg = try sema.errMsg(block, src, "enum fields missing in union", .{});
21738 errdefer msg.destroy(gpa);
21739 var it = seen_tags.iterator(.{ .kind = .unset });
21740 while (it.next()) |enum_index| {
21741 const field_name = enum_tag_ty.enumFieldName(enum_index, mod);
21742 try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{}' missing, declared here", .{
21743 field_name.fmt(ip),
21744 });
21745 }
21746 try sema.addDeclaredHereNote(msg, enum_tag_ty);
21747 break :msg msg;
21748 });
21749
21750 break :tag_ty .{ enum_tag_ty.toIntern(), true };
21751 } else tag_ty: {
21752 // We must track field names and set up the tag type ourselves.
21753 var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
21754 try field_names.ensureTotalCapacity(sema.arena, fields_len);
21755
21756 for (field_types, 0..) |*field_ty, field_idx| {
21757 const field_info = try fields_val.elemValue(mod, field_idx);
21758
21759 const field_name_val = try field_info.fieldValue(mod, 0);
21760 const field_type_val = try field_info.fieldValue(mod, 1);
21761
21762 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21763 const gop = field_names.getOrPutAssumeCapacity(field_name);
21764 if (gop.found_existing) {
21765 // TODO: better source location
21766 return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
21767 }
21768
21769 field_ty.* = field_type_val.toIntern();
21770 if (any_aligns) {
21771 const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntAdvanced(sema);
21772 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
21773 // TODO: better source location
21774 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21775 }
21776 field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
21777 }
21778 }
21779
21780 const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), mod.declPtr(new_decl_index));
21781 break :tag_ty .{ enum_tag_ty, false };
21782 };
21783 errdefer if (!has_explicit_tag) ip.remove(enum_tag_ty); // remove generated tag type on error
21784
21785 for (field_types) |field_ty_ip| {
21786 const field_ty = Type.fromInterned(field_ty_ip);
21787 if (field_ty.zigTypeTag(mod) == .Opaque) {
21788 return sema.failWithOwnedErrorMsg(block, msg: {
21789 const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
21790 errdefer msg.destroy(gpa);
21791
21792 try sema.addDeclaredHereNote(msg, field_ty);
21793 break :msg msg;
21794 });
21795 }
21796 if (layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
21797 return sema.failWithOwnedErrorMsg(block, msg: {
21798 const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
21799 errdefer msg.destroy(gpa);
21800
21801 const src_decl = mod.declPtr(block.src_decl);
21802 try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), field_ty, .union_field);
21803
21804 try sema.addDeclaredHereNote(msg, field_ty);
21805 break :msg msg;
21806 });
21807 } else if (layout == .Packed and !try sema.validatePackedType(field_ty)) {
21808 return sema.failWithOwnedErrorMsg(block, msg: {
21809 const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
21810 errdefer msg.destroy(gpa);
21811
21812 const src_decl = mod.declPtr(block.src_decl);
21813 try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(src, mod), field_ty);
21814
21815 try sema.addDeclaredHereNote(msg, field_ty);
21816 break :msg msg;
21817 });
21818 }
2184321819 }
2184421820
21845 const ty = try ip.getStructType(gpa, .{
21846 .decl = new_decl_index,
21847 .namespace = .none,
21848 .zir_index = .none,
21821 const loaded_union = ip.loadUnionType(wip_ty.index);
21822 loaded_union.setFieldTypes(ip, field_types);
21823 if (any_aligns) {
21824 loaded_union.setFieldAligns(ip, field_aligns);
21825 }
21826 loaded_union.tagTypePtr(ip).* = enum_tag_ty;
21827 loaded_union.flagsPtr(ip).status = .have_field_types;
21828
21829 try mod.finalizeAnonDecl(new_decl_index);
21830 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
21831}
21832
21833fn reifyStruct(
21834 sema: *Sema,
21835 block: *Block,
21836 inst: Zir.Inst.Index,
21837 src: LazySrcLoc,
21838 layout: std.builtin.Type.ContainerLayout,
21839 opt_backing_int_val: Value,
21840 fields_val: Value,
21841 name_strategy: Zir.Inst.NameStrategy,
21842 is_tuple: bool,
21843) CompileError!Air.Inst.Ref {
21844 const mod = sema.mod;
21845 const gpa = sema.gpa;
21846 const ip = &mod.intern_pool;
21847
21848 // This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`.
21849
21850 const fields_len: u32 = @intCast(fields_val.sliceLen(mod));
21851
21852 // The validation work here is non-trivial, and it's possible the type already exists.
21853 // So in this first pass, let's just construct a hash to optimize for this case. If the
21854 // inputs turn out to be invalid, we can cancel the WIP type later.
21855
21856 // For deduplication purposes, we must create a hash including all details of this type.
21857 // TODO: use a longer hash!
21858 var hasher = std.hash.Wyhash.init(0);
21859 std.hash.autoHash(&hasher, layout);
21860 std.hash.autoHash(&hasher, opt_backing_int_val.toIntern());
21861 std.hash.autoHash(&hasher, is_tuple);
21862 std.hash.autoHash(&hasher, fields_len);
21863
21864 var any_comptime_fields = false;
21865 var any_default_inits = false;
21866 var any_aligned_fields = false;
21867
21868 for (0..fields_len) |field_idx| {
21869 const field_info = try fields_val.elemValue(mod, field_idx);
21870
21871 const field_name_val = try field_info.fieldValue(mod, 0);
21872 const field_type_val = try field_info.fieldValue(mod, 1);
21873 const field_default_value_val = try field_info.fieldValue(mod, 2);
21874 const field_is_comptime_val = try field_info.fieldValue(mod, 3);
21875 const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 4));
21876
21877 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
21878 const field_is_comptime = field_is_comptime_val.toBool();
21879 const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(mod)) |ptr_val| d: {
21880 const ptr_ty = try mod.singleConstPtrType(field_type_val.toType());
21881 // We need to do this deref here, so we won't check for this error case later on.
21882 const val = try sema.pointerDeref(block, src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime(
21883 block,
21884 src,
21885 .{ .needed_comptime_reason = "struct field default value must be comptime-known" },
21886 );
21887 // Resolve the value so that lazy values do not create distinct types.
21888 break :d (try sema.resolveLazyValue(val)).toIntern();
21889 } else .none;
21890
21891 std.hash.autoHash(&hasher, .{
21892 field_name,
21893 field_type_val.toIntern(),
21894 field_default_value,
21895 field_is_comptime,
21896 field_alignment_val.toIntern(),
21897 });
21898
21899 if (field_is_comptime) any_comptime_fields = true;
21900 if (field_default_value != .none) any_default_inits = true;
21901 switch (try field_alignment_val.orderAgainstZeroAdvanced(mod, sema)) {
21902 .eq => {},
21903 .gt => any_aligned_fields = true,
21904 .lt => unreachable,
21905 }
21906 }
21907
21908 const wip_ty = switch (try ip.getStructType(gpa, .{
2184921909 .layout = layout,
21850 .known_non_opv = false,
2185121910 .fields_len = fields_len,
21911 .known_non_opv = false,
2185221912 .requires_comptime = .unknown,
2185321913 .is_tuple = is_tuple,
21854 // So that we don't have to scan ahead, we allocate space in the struct
21855 // type for alignments, comptime fields, and default inits. This might
21856 // result in wasted space, however, this is a permitted encoding of
21857 // struct types.
21858 .any_comptime_fields = true,
21859 .any_default_inits = true,
21914 .any_comptime_fields = any_comptime_fields,
21915 .any_default_inits = any_default_inits,
21916 .any_aligned_fields = any_aligned_fields,
2186021917 .inits_resolved = true,
21861 .any_aligned_fields = true,
21862 });
21863 // TODO: figure out InternPool removals for incremental compilation
21864 //errdefer ip.remove(ty);
21865 const struct_type = ip.indexToKey(ty).struct_type;
21918 .has_namespace = false,
21919 .key = .{ .reified = .{
21920 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
21921 .type_hash = hasher.final(),
21922 } },
21923 })) {
21924 .wip => |wip| wip,
21925 .existing => |ty| return Air.internedToRef(ty),
21926 };
21927 errdefer wip_ty.cancel(ip);
2186621928
21867 new_decl.ty = Type.type;
21868 new_decl.val = Value.fromInterned(ty);
21869
21870 // Fields
21871 for (0..fields_len) |i| {
21872 const elem_val = try fields_val.elemValue(mod, i);
21873 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
21874 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21875 ip,
21876 try ip.getOrPutString(gpa, "name"),
21877 ).?);
21878 const type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21879 ip,
21880 try ip.getOrPutString(gpa, "type"),
21881 ).?);
21882 const default_value_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21883 ip,
21884 try ip.getOrPutString(gpa, "default_value"),
21885 ).?);
21886 const is_comptime_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21887 ip,
21888 try ip.getOrPutString(gpa, "is_comptime"),
21889 ).?);
21890 const alignment_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21891 ip,
21892 try ip.getOrPutString(gpa, "alignment"),
21893 ).?);
21894
21895 if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {
21896 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
21897 }
21898 const abi_align = (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?;
21899
21900 if (layout == .Packed) {
21901 if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
21902 if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});
21903 } else {
21904 if (abi_align > 0 and !math.isPowerOfTwo(abi_align)) return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{abi_align});
21905 struct_type.field_aligns.get(ip)[i] = Alignment.fromByteUnits(abi_align);
21906 }
21907 if (layout == .Extern and is_comptime_val.toBool()) {
21908 return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{});
21909 }
21929 if (is_tuple) switch (layout) {
21930 .Extern => return sema.fail(block, src, "extern tuples are not supported", .{}),
21931 .Packed => return sema.fail(block, src, "packed tuples are not supported", .{}),
21932 .Auto => {},
21933 };
2191021934
21911 const field_name = try name_val.toIpString(Type.slice_const_u8, mod);
21935 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21936 .ty = Type.type,
21937 .val = Value.fromInterned(wip_ty.index),
21938 }, name_strategy, "struct", inst);
21939 mod.declPtr(new_decl_index).owns_tv = true;
21940 errdefer mod.abortAnonDecl(new_decl_index);
2191221941
21942 const struct_type = ip.loadStructType(wip_ty.index);
21943
21944 for (0..fields_len) |field_idx| {
21945 const field_info = try fields_val.elemValue(mod, field_idx);
21946
21947 const field_name_val = try field_info.fieldValue(mod, 0);
21948 const field_type_val = try field_info.fieldValue(mod, 1);
21949 const field_default_value_val = try field_info.fieldValue(mod, 2);
21950 const field_is_comptime_val = try field_info.fieldValue(mod, 3);
21951 const field_alignment_val = try field_info.fieldValue(mod, 4);
21952
21953 const field_ty = field_type_val.toType();
21954 const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
2191321955 if (is_tuple) {
21914 const field_index = field_name.toUnsigned(ip) orelse return sema.fail(
21956 const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail(
2191521957 block,
2191621958 src,
2191721959 "tuple cannot have non-numeric field '{}'",
2191821960 .{field_name.fmt(ip)},
2191921961 );
21920
21921 if (field_index >= fields_len) {
21962 if (field_name_index != field_idx) {
2192221963 return sema.fail(
2192321964 block,
2192421965 src,
21925 "tuple field {} exceeds tuple field count",
21926 .{field_index},
21966 "tuple field name '{}' does not match field index {}",
21967 .{ field_name_index, field_idx },
2192721968 );
2192821969 }
2192921970 } else if (struct_type.addFieldName(ip, field_name)) |prev_index| {
......@@ -21931,45 +21972,72 @@ fn reifyStruct(
2193121972 return sema.fail(block, src, "duplicate struct field name {}", .{field_name.fmt(ip)});
2193221973 }
2193321974
21934 const field_ty = type_val.toType();
21935 const default_val = if (default_value_val.optionalValue(mod)) |opt_val|
21936 (try sema.pointerDeref(block, src, opt_val, try mod.singleConstPtrType(field_ty)) orelse
21937 return sema.failWithNeededComptime(block, src, .{
21938 .needed_comptime_reason = "struct field default value must be comptime-known",
21939 })).toIntern()
21940 else
21941 .none;
21942 if (is_comptime_val.toBool() and default_val == .none) {
21975 if (any_aligned_fields) {
21976 if (!try sema.intFitsInType(field_alignment_val, Type.u32, null)) {
21977 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
21978 }
21979
21980 const byte_align = try field_alignment_val.toUnsignedIntAdvanced(sema);
21981 if (byte_align == 0) {
21982 if (layout != .Packed) {
21983 struct_type.field_aligns.get(ip)[field_idx] = .none;
21984 }
21985 } else {
21986 if (layout == .Packed) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
21987 if (!math.isPowerOfTwo(byte_align)) return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21988 struct_type.field_aligns.get(ip)[field_idx] = Alignment.fromNonzeroByteUnits(byte_align);
21989 }
21990 }
21991
21992 const field_is_comptime = field_is_comptime_val.toBool();
21993 if (field_is_comptime) {
21994 assert(any_comptime_fields);
21995 switch (layout) {
21996 .Extern => return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}),
21997 .Packed => return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{}),
21998 .Auto => struct_type.setFieldComptime(ip, field_idx),
21999 }
22000 }
22001
22002 const field_default: InternPool.Index = d: {
22003 if (!any_default_inits) break :d .none;
22004 const ptr_val = field_default_value_val.optionalValue(mod) orelse break :d .none;
22005 const ptr_ty = try mod.singleConstPtrType(field_ty);
22006 // Asserted comptime-dereferencable above.
22007 const val = (try sema.pointerDeref(block, src, ptr_val, ptr_ty)).?;
22008 // We already resolved this for deduplication, so we may as well do it now.
22009 break :d (try sema.resolveLazyValue(val)).toIntern();
22010 };
22011
22012 if (field_is_comptime and field_default == .none) {
2194322013 return sema.fail(block, src, "comptime field without default initialization value", .{});
2194422014 }
2194522015
21946 struct_type.field_types.get(ip)[i] = field_ty.toIntern();
21947 struct_type.field_inits.get(ip)[i] = default_val;
21948 if (is_comptime_val.toBool())
21949 struct_type.setFieldComptime(ip, i);
22016 struct_type.field_types.get(ip)[field_idx] = field_type_val.toIntern();
22017 if (field_default != .none) {
22018 struct_type.field_inits.get(ip)[field_idx] = field_default;
22019 }
2195022020
2195122021 if (field_ty.zigTypeTag(mod) == .Opaque) {
21952 const msg = msg: {
22022 return sema.failWithOwnedErrorMsg(block, msg: {
2195322023 const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
2195422024 errdefer msg.destroy(gpa);
2195522025
2195622026 try sema.addDeclaredHereNote(msg, field_ty);
2195722027 break :msg msg;
21958 };
21959 return sema.failWithOwnedErrorMsg(block, msg);
22028 });
2196022029 }
2196122030 if (field_ty.zigTypeTag(mod) == .NoReturn) {
21962 const msg = msg: {
22031 return sema.failWithOwnedErrorMsg(block, msg: {
2196322032 const msg = try sema.errMsg(block, src, "struct fields cannot be 'noreturn'", .{});
2196422033 errdefer msg.destroy(gpa);
2196522034
2196622035 try sema.addDeclaredHereNote(msg, field_ty);
2196722036 break :msg msg;
21968 };
21969 return sema.failWithOwnedErrorMsg(block, msg);
22037 });
2197022038 }
2197122039 if (layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) {
21972 const msg = msg: {
22040 return sema.failWithOwnedErrorMsg(block, msg: {
2197322041 const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2197422042 errdefer msg.destroy(gpa);
2197522043
......@@ -21978,10 +22046,9 @@ fn reifyStruct(
2197822046
2197922047 try sema.addDeclaredHereNote(msg, field_ty);
2198022048 break :msg msg;
21981 };
21982 return sema.failWithOwnedErrorMsg(block, msg);
22049 });
2198322050 } else if (layout == .Packed and !try sema.validatePackedType(field_ty)) {
21984 const msg = msg: {
22051 return sema.failWithOwnedErrorMsg(block, msg: {
2198522052 const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2198622053 errdefer msg.destroy(gpa);
2198722054
......@@ -21990,32 +22057,27 @@ fn reifyStruct(
2199022057
2199122058 try sema.addDeclaredHereNote(msg, field_ty);
2199222059 break :msg msg;
21993 };
21994 return sema.failWithOwnedErrorMsg(block, msg);
22060 });
2199522061 }
2199622062 }
2199722063
2199822064 if (layout == .Packed) {
21999 for (0..struct_type.field_types.len) |index| {
22000 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);
22065 var fields_bit_sum: u64 = 0;
22066 for (0..struct_type.field_types.len) |field_idx| {
22067 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_idx]);
2200122068 sema.resolveTypeLayout(field_ty) catch |err| switch (err) {
2200222069 error.AnalysisFail => {
2200322070 const msg = sema.err orelse return err;
22004 try sema.addFieldErrNote(Type.fromInterned(ty), index, msg, "while checking this field", .{});
22071 try sema.errNote(block, src, msg, "while checking a field of this struct", .{});
2200522072 return err;
2200622073 },
2200722074 else => return err,
2200822075 };
22009 }
22010
22011 var fields_bit_sum: u64 = 0;
22012 for (0..struct_type.field_types.len) |i| {
22013 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
2201422076 fields_bit_sum += field_ty.bitSize(mod);
2201522077 }
2201622078
22017 if (backing_int_val.optionalValue(mod)) |backing_int_ty_val| {
22018 const backing_int_ty = backing_int_ty_val.toType();
22079 if (opt_backing_int_val.optionalValue(mod)) |backing_int_val| {
22080 const backing_int_ty = backing_int_val.toType();
2201922081 try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
2202022082 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
2202122083 } else {
......@@ -22024,9 +22086,8 @@ fn reifyStruct(
2202422086 }
2202522087 }
2202622088
22027 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
2202822089 try mod.finalizeAnonDecl(new_decl_index);
22029 return decl_val;
22090 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
2203022091}
2203122092
2203222093fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
......@@ -23241,7 +23302,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
2324123302 switch (ty.containerLayout(mod)) {
2324223303 .Packed => {
2324323304 var bit_sum: u64 = 0;
23244 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
23305 const struct_type = ip.loadStructType(ty.toIntern());
2324523306 for (0..struct_type.field_types.len) |i| {
2324623307 if (i == field_index) {
2324723308 return bit_sum;
......@@ -25919,7 +25980,7 @@ fn zirBuiltinExtern(
2591925980
2592025981 // TODO check duplicate extern
2592125982
25922 const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, .none);
25983 const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node);
2592325984 errdefer mod.destroyDecl(new_decl_index);
2592425985 const new_decl = mod.declPtr(new_decl_index);
2592525986 new_decl.name = options.name;
......@@ -26515,7 +26576,6 @@ fn addSafetyCheck(
2651526576 .sema = sema,
2651626577 .src_decl = parent_block.src_decl,
2651726578 .namespace = parent_block.namespace,
26518 .wip_capture_scope = parent_block.wip_capture_scope,
2651926579 .instructions = .{},
2652026580 .inlining = parent_block.inlining,
2652126581 .is_comptime = false,
......@@ -26624,7 +26684,6 @@ fn panicUnwrapError(
2662426684 .sema = sema,
2662526685 .src_decl = parent_block.src_decl,
2662626686 .namespace = parent_block.namespace,
26627 .wip_capture_scope = parent_block.wip_capture_scope,
2662826687 .instructions = .{},
2662926688 .inlining = parent_block.inlining,
2663026689 .is_comptime = false,
......@@ -26741,7 +26800,6 @@ fn safetyCheckFormatted(
2674126800 .sema = sema,
2674226801 .src_decl = parent_block.src_decl,
2674326802 .namespace = parent_block.namespace,
26744 .wip_capture_scope = parent_block.wip_capture_scope,
2674526803 .instructions = .{},
2674626804 .inlining = parent_block.inlining,
2674726805 .is_comptime = false,
......@@ -27268,8 +27326,7 @@ fn fieldCallBind(
2726827326 .Union => {
2726927327 try sema.resolveTypeFields(concrete_ty);
2727027328 const union_obj = mod.typeToUnion(concrete_ty).?;
27271 _ = union_obj.nameIndex(ip, field_name) orelse break :find_field;
27272
27329 _ = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse break :find_field;
2727327330 const field_ptr = try unionFieldPtr(sema, block, src, object_ptr, field_name, field_name_src, concrete_ty, false);
2727427331 return .{ .direct = try sema.analyzeLoad(block, src, field_ptr, src) };
2727527332 },
......@@ -27643,7 +27700,8 @@ fn structFieldVal(
2764327700 try sema.resolveTypeFields(struct_ty);
2764427701
2764527702 switch (ip.indexToKey(struct_ty.toIntern())) {
27646 .struct_type => |struct_type| {
27703 .struct_type => {
27704 const struct_type = ip.loadStructType(struct_ty.toIntern());
2764727705 if (struct_type.isTuple(ip))
2764827706 return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);
2764927707
......@@ -27849,7 +27907,7 @@ fn unionFieldPtr(
2784927907
2785027908 try sema.requireRuntimeBlock(block, src, null);
2785127909 if (!initializing and union_obj.getLayout(ip) == .Auto and block.wantSafety() and
27852 union_ty.unionTagTypeSafety(mod) != null and union_obj.field_names.len > 1)
27910 union_ty.unionTagTypeSafety(mod) != null and union_obj.field_types.len > 1)
2785327911 {
2785427912 const wanted_tag_val = try mod.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
2785527913 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
......@@ -27927,7 +27985,7 @@ fn unionFieldVal(
2792727985
2792827986 try sema.requireRuntimeBlock(block, src, null);
2792927987 if (union_obj.getLayout(ip) == .Auto and block.wantSafety() and
27930 union_ty.unionTagTypeSafety(mod) != null and union_obj.field_names.len > 1)
27988 union_ty.unionTagTypeSafety(mod) != null and union_obj.field_types.len > 1)
2793127989 {
2793227990 const wanted_tag_val = try mod.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
2793327991 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
......@@ -31686,7 +31744,7 @@ fn coerceEnumToUnion(
3168631744 const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{});
3168731745 errdefer msg.destroy(sema.gpa);
3168831746
31689 const field_name = union_obj.field_names.get(ip)[field_index];
31747 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
3169031748 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{
3169131749 field_name.fmt(ip),
3169231750 });
......@@ -31697,7 +31755,7 @@ fn coerceEnumToUnion(
3169731755 }
3169831756 const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse {
3169931757 const msg = msg: {
31700 const field_name = union_obj.field_names.get(ip)[field_index];
31758 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
3170131759 const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{
3170231760 inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod),
3170331761 field_ty.fmt(sema.mod), field_name.fmt(ip),
......@@ -31769,8 +31827,8 @@ fn coerceEnumToUnion(
3176931827 );
3177031828 errdefer msg.destroy(sema.gpa);
3177131829
31772 for (0..union_obj.field_names.len) |field_index| {
31773 const field_name = union_obj.field_names.get(ip)[field_index];
31830 for (0..union_obj.field_types.len) |field_index| {
31831 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
3177431832 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
3177531833 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
3177631834 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' has type '{}'", .{
......@@ -31803,8 +31861,8 @@ fn coerceAnonStructToUnion(
3180331861 .{ .name = anon_struct_type.names.get(ip)[0] }
3180431862 else
3180531863 .{ .count = anon_struct_type.names.len },
31806 .struct_type => |struct_type| name: {
31807 const field_names = struct_type.field_names.get(ip);
31864 .struct_type => name: {
31865 const field_names = ip.loadStructType(inst_ty.toIntern()).field_names.get(ip);
3180831866 break :name if (field_names.len == 1)
3180931867 .{ .name = field_names[0] }
3181031868 else
......@@ -32113,7 +32171,7 @@ fn coerceTupleToStruct(
3211332171 var runtime_src: ?LazySrcLoc = null;
3211432172 const field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
3211532173 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
32116 .struct_type => |s| s.field_types.len,
32174 .struct_type => ip.loadStructType(inst_ty.toIntern()).field_types.len,
3211732175 else => unreachable,
3211832176 };
3211932177 for (0..field_count) |field_index_usize| {
......@@ -32125,7 +32183,7 @@ fn coerceTupleToStruct(
3212532183 anon_struct_type.names.get(ip)[field_i]
3212632184 else
3212732185 try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
32128 .struct_type => |s| s.field_names.get(ip)[field_i],
32186 .struct_type => ip.loadStructType(inst_ty.toIntern()).field_names.get(ip)[field_i],
3212932187 else => unreachable,
3213032188 };
3213132189 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
......@@ -32213,7 +32271,7 @@ fn coerceTupleToTuple(
3221332271 const ip = &mod.intern_pool;
3221432272 const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) {
3221532273 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
32216 .struct_type => |struct_type| struct_type.field_types.len,
32274 .struct_type => ip.loadStructType(tuple_ty.toIntern()).field_types.len,
3221732275 else => unreachable,
3221832276 };
3221932277 const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count);
......@@ -32223,7 +32281,7 @@ fn coerceTupleToTuple(
3222332281 const inst_ty = sema.typeOf(inst);
3222432282 const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
3222532283 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
32226 .struct_type => |struct_type| struct_type.field_types.len,
32284 .struct_type => ip.loadStructType(inst_ty.toIntern()).field_types.len,
3222732285 else => unreachable,
3222832286 };
3222932287 if (src_field_count > dest_field_count) return error.NotCoercible;
......@@ -32238,10 +32296,14 @@ fn coerceTupleToTuple(
3223832296 anon_struct_type.names.get(ip)[field_i]
3223932297 else
3224032298 try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
32241 .struct_type => |struct_type| if (struct_type.field_names.len > 0)
32242 struct_type.field_names.get(ip)[field_i]
32243 else
32244 try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
32299 .struct_type => s: {
32300 const struct_type = ip.loadStructType(inst_ty.toIntern());
32301 if (struct_type.field_names.len > 0) {
32302 break :s struct_type.field_names.get(ip)[field_i];
32303 } else {
32304 break :s try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i});
32305 }
32306 },
3224532307 else => unreachable,
3224632308 };
3224732309
......@@ -32250,12 +32312,12 @@ fn coerceTupleToTuple(
3225032312
3225132313 const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) {
3225232314 .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[field_index_usize],
32253 .struct_type => |struct_type| struct_type.field_types.get(ip)[field_index_usize],
32315 .struct_type => ip.loadStructType(tuple_ty.toIntern()).field_types.get(ip)[field_index_usize],
3225432316 else => unreachable,
3225532317 };
3225632318 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
3225732319 .anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[field_index_usize],
32258 .struct_type => |struct_type| struct_type.fieldInit(ip, field_index_usize),
32320 .struct_type => ip.loadStructType(tuple_ty.toIntern()).fieldInit(ip, field_index_usize),
3225932321 else => unreachable,
3226032322 };
3226132323
......@@ -32294,7 +32356,7 @@ fn coerceTupleToTuple(
3229432356
3229532357 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
3229632358 .anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[i],
32297 .struct_type => |struct_type| struct_type.fieldInit(ip, i),
32359 .struct_type => ip.loadStructType(tuple_ty.toIntern()).fieldInit(ip, i),
3229832360 else => unreachable,
3229932361 };
3230032362
......@@ -35534,7 +35596,7 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
3553435596pub fn resolveStructAlignment(
3553535597 sema: *Sema,
3553635598 ty: InternPool.Index,
35537 struct_type: InternPool.Key.StructType,
35599 struct_type: InternPool.LoadedStructType,
3553835600) CompileError!Alignment {
3553935601 const mod = sema.mod;
3554035602 const ip = &mod.intern_pool;
......@@ -35674,7 +35736,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
3567435736 }
3567535737 }
3567635738
35677 const RuntimeOrder = InternPool.Key.StructType.RuntimeOrder;
35739 const RuntimeOrder = InternPool.LoadedStructType.RuntimeOrder;
3567835740
3567935741 const AlignSortContext = struct {
3568035742 aligns: []const Alignment,
......@@ -35726,7 +35788,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
3572635788 _ = try sema.typeRequiresComptime(ty);
3572735789}
3572835790
35729fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) CompileError!void {
35791fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) CompileError!void {
3573035792 const gpa = mod.gpa;
3573135793 const ip = &mod.intern_pool;
3573235794
......@@ -35766,7 +35828,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
3576635828 .sema = &sema,
3576735829 .src_decl = decl_index,
3576835830 .namespace = struct_type.namespace.unwrap() orelse decl.src_namespace,
35769 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
3577035831 .instructions = .{},
3577135832 .inlining = null,
3577235833 .is_comptime = true,
......@@ -35789,9 +35850,16 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
3578935850
3579035851 if (small.has_backing_int) {
3579135852 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
35853 const captures_len = if (small.has_captures_len) blk: {
35854 const captures_len = zir.extra[extra_index];
35855 extra_index += 1;
35856 break :blk captures_len;
35857 } else 0;
3579235858 extra_index += @intFromBool(small.has_fields_len);
3579335859 extra_index += @intFromBool(small.has_decls_len);
3579435860
35861 extra_index += captures_len;
35862
3579535863 const backing_int_body_len = zir.extra[extra_index];
3579635864 extra_index += 1;
3579735865
......@@ -35879,7 +35947,7 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void
3587935947pub fn resolveUnionAlignment(
3588035948 sema: *Sema,
3588135949 ty: Type,
35882 union_type: InternPool.Key.UnionType,
35950 union_type: InternPool.LoadedUnionType,
3588335951) CompileError!Alignment {
3588435952 const mod = sema.mod;
3588535953 const ip = &mod.intern_pool;
......@@ -35899,13 +35967,12 @@ pub fn resolveUnionAlignment(
3589935967
3590035968 try sema.resolveTypeFieldsUnion(ty, union_type);
3590135969
35902 const union_obj = ip.loadUnionType(union_type);
3590335970 var max_align: Alignment = .@"1";
35904 for (0..union_obj.field_names.len) |field_index| {
35905 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
35971 for (0..union_type.field_types.len) |field_index| {
35972 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
3590635973 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
3590735974
35908 const explicit_align = union_obj.fieldAlign(ip, @intCast(field_index));
35975 const explicit_align = union_type.fieldAlign(ip, @intCast(field_index));
3590935976 const field_align = if (explicit_align != .none)
3591035977 explicit_align
3591135978 else
......@@ -35923,16 +35990,17 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
3592335990 const mod = sema.mod;
3592435991 const ip = &mod.intern_pool;
3592535992
35926 const union_type = ip.indexToKey(ty.ip_index).union_type;
35927 try sema.resolveTypeFieldsUnion(ty, union_type);
35993 try sema.resolveTypeFieldsUnion(ty, ip.loadUnionType(ty.ip_index));
3592835994
35929 const union_obj = ip.loadUnionType(union_type);
35930 switch (union_obj.flagsPtr(ip).status) {
35995 // Load again, since the tag type might have changed due to resolution.
35996 const union_type = ip.loadUnionType(ty.ip_index);
35997
35998 switch (union_type.flagsPtr(ip).status) {
3593135999 .none, .have_field_types => {},
3593236000 .field_types_wip, .layout_wip => {
3593336001 const msg = try Module.ErrorMsg.create(
3593436002 sema.gpa,
35935 mod.declPtr(union_obj.decl).srcLoc(mod),
36003 mod.declPtr(union_type.decl).srcLoc(mod),
3593636004 "union '{}' depends on itself",
3593736005 .{ty.fmt(mod)},
3593836006 );
......@@ -35941,17 +36009,17 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
3594136009 .have_layout, .fully_resolved_wip, .fully_resolved => return,
3594236010 }
3594336011
35944 const prev_status = union_obj.flagsPtr(ip).status;
35945 errdefer if (union_obj.flagsPtr(ip).status == .layout_wip) {
35946 union_obj.flagsPtr(ip).status = prev_status;
36012 const prev_status = union_type.flagsPtr(ip).status;
36013 errdefer if (union_type.flagsPtr(ip).status == .layout_wip) {
36014 union_type.flagsPtr(ip).status = prev_status;
3594736015 };
3594836016
35949 union_obj.flagsPtr(ip).status = .layout_wip;
36017 union_type.flagsPtr(ip).status = .layout_wip;
3595036018
3595136019 var max_size: u64 = 0;
3595236020 var max_align: Alignment = .@"1";
35953 for (0..union_obj.field_names.len) |field_index| {
35954 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
36021 for (0..union_type.field_types.len) |field_index| {
36022 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
3595536023 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
3595636024
3595736025 max_size = @max(max_size, sema.typeAbiSize(field_ty) catch |err| switch (err) {
......@@ -35963,7 +36031,7 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
3596336031 else => return err,
3596436032 });
3596536033
35966 const explicit_align = union_obj.fieldAlign(ip, @intCast(field_index));
36034 const explicit_align = union_type.fieldAlign(ip, @intCast(field_index));
3596736035 const field_align = if (explicit_align != .none)
3596836036 explicit_align
3596936037 else
......@@ -35972,10 +36040,10 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
3597236040 max_align = max_align.max(field_align);
3597336041 }
3597436042
35975 const flags = union_obj.flagsPtr(ip);
35976 const has_runtime_tag = flags.runtime_tag.hasTag() and try sema.typeHasRuntimeBits(Type.fromInterned(union_obj.enum_tag_ty));
36043 const flags = union_type.flagsPtr(ip);
36044 const has_runtime_tag = flags.runtime_tag.hasTag() and try sema.typeHasRuntimeBits(Type.fromInterned(union_type.enum_tag_ty));
3597736045 const size, const alignment, const padding = if (has_runtime_tag) layout: {
35978 const enum_tag_type = Type.fromInterned(union_obj.enum_tag_ty);
36046 const enum_tag_type = Type.fromInterned(union_type.enum_tag_ty);
3597936047 const tag_align = try sema.typeAbiAlignment(enum_tag_type);
3598036048 const tag_size = try sema.typeAbiSize(enum_tag_type);
3598136049
......@@ -36009,22 +36077,22 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
3600936077 flags.alignment = alignment;
3601036078 flags.status = .have_layout;
3601136079
36012 if (union_obj.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {
36080 if (union_type.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {
3601336081 const msg = try Module.ErrorMsg.create(
3601436082 sema.gpa,
36015 mod.declPtr(union_obj.decl).srcLoc(mod),
36083 mod.declPtr(union_type.decl).srcLoc(mod),
3601636084 "union layout depends on it having runtime bits",
3601736085 .{},
3601836086 );
3601936087 return sema.failWithOwnedErrorMsg(null, msg);
3602036088 }
3602136089
36022 if (union_obj.flagsPtr(ip).assumed_pointer_aligned and
36090 if (union_type.flagsPtr(ip).assumed_pointer_aligned and
3602336091 alignment.compareStrict(.neq, Alignment.fromByteUnits(@divExact(mod.getTarget().ptrBitWidth(), 8))))
3602436092 {
3602536093 const msg = try Module.ErrorMsg.create(
3602636094 sema.gpa,
36027 mod.declPtr(union_obj.decl).srcLoc(mod),
36095 mod.declPtr(union_type.decl).srcLoc(mod),
3602836096 "union layout depends on being pointer aligned",
3602936097 .{},
3603036098 );
......@@ -36212,12 +36280,11 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {
3621236280
3621336281 else => switch (ip.items.items(.tag)[@intFromEnum(ty_ip)]) {
3621436282 .type_struct,
36215 .type_struct_ns,
3621636283 .type_struct_packed,
3621736284 .type_struct_packed_inits,
36218 => try sema.resolveTypeFieldsStruct(ty_ip, ip.indexToKey(ty_ip).struct_type),
36285 => try sema.resolveTypeFieldsStruct(ty_ip, ip.loadStructType(ty_ip)),
3621936286
36220 .type_union => try sema.resolveTypeFieldsUnion(Type.fromInterned(ty_ip), ip.indexToKey(ty_ip).union_type),
36287 .type_union => try sema.resolveTypeFieldsUnion(Type.fromInterned(ty_ip), ip.loadUnionType(ty_ip)),
3622136288 .simple_type => try sema.resolveSimpleType(ip.indexToKey(ty_ip).simple_type),
3622236289 else => {},
3622336290 },
......@@ -36249,7 +36316,7 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr
3624936316pub fn resolveTypeFieldsStruct(
3625036317 sema: *Sema,
3625136318 ty: InternPool.Index,
36252 struct_type: InternPool.Key.StructType,
36319 struct_type: InternPool.LoadedStructType,
3625336320) CompileError!void {
3625436321 const mod = sema.mod;
3625536322 const ip = &mod.intern_pool;
......@@ -36309,7 +36376,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {
3630936376 struct_type.setHaveFieldInits(ip);
3631036377}
3631136378
36312pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {
36379pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.LoadedUnionType) CompileError!void {
3631336380 const mod = sema.mod;
3631436381 const ip = &mod.intern_pool;
3631536382 const owner_decl = mod.declPtr(union_type.decl);
......@@ -36500,6 +36567,12 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
3650036567 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3650136568 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
3650236569
36570 const captures_len = if (small.has_captures_len) blk: {
36571 const captures_len = zir.extra[extra_index];
36572 extra_index += 1;
36573 break :blk captures_len;
36574 } else 0;
36575
3650336576 const fields_len = if (small.has_fields_len) blk: {
3650436577 const fields_len = zir.extra[extra_index];
3650536578 extra_index += 1;
......@@ -36512,6 +36585,8 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
3651236585 break :decls_len decls_len;
3651336586 } else 0;
3651436587
36588 extra_index += captures_len;
36589
3651536590 // The backing integer cannot be handled until `resolveStructLayout()`.
3651636591 if (small.has_backing_int) {
3651736592 const backing_int_body_len = zir.extra[extra_index];
......@@ -36532,7 +36607,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
3653236607fn semaStructFields(
3653336608 mod: *Module,
3653436609 arena: Allocator,
36535 struct_type: InternPool.Key.StructType,
36610 struct_type: InternPool.LoadedStructType,
3653636611) CompileError!void {
3653736612 const gpa = mod.gpa;
3653836613 const ip = &mod.intern_pool;
......@@ -36584,7 +36659,6 @@ fn semaStructFields(
3658436659 .sema = &sema,
3658536660 .src_decl = decl_index,
3658636661 .namespace = namespace_index,
36587 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
3658836662 .instructions = .{},
3658936663 .inlining = null,
3659036664 .is_comptime = true,
......@@ -36800,7 +36874,7 @@ fn semaStructFields(
3680036874fn semaStructFieldInits(
3680136875 mod: *Module,
3680236876 arena: Allocator,
36803 struct_type: InternPool.Key.StructType,
36877 struct_type: InternPool.LoadedStructType,
3680436878) CompileError!void {
3680536879 const gpa = mod.gpa;
3680636880 const ip = &mod.intern_pool;
......@@ -36842,7 +36916,6 @@ fn semaStructFieldInits(
3684236916 .sema = &sema,
3684336917 .src_decl = decl_index,
3684436918 .namespace = namespace_index,
36845 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
3684636919 .instructions = .{},
3684736920 .inlining = null,
3684836921 .is_comptime = true,
......@@ -36952,15 +37025,15 @@ fn semaStructFieldInits(
3695237025 }
3695337026}
3695437027
36955fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.UnionType) CompileError!void {
37028fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.LoadedUnionType) CompileError!void {
3695637029 const tracy = trace(@src());
3695737030 defer tracy.end();
3695837031
3695937032 const gpa = mod.gpa;
3696037033 const ip = &mod.intern_pool;
3696137034 const decl_index = union_type.decl;
36962 const zir = mod.namespacePtr(union_type.namespace).file_scope.zir;
36963 const zir_index = union_type.zir_index.unwrap().?.resolve(ip);
37035 const zir = mod.namespacePtr(union_type.namespace.unwrap().?).file_scope.zir;
37036 const zir_index = union_type.zir_index.resolve(ip);
3696437037 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
3696537038 assert(extended.opcode == .union_decl);
3696637039 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
......@@ -36974,6 +37047,12 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3697437047 break :blk ty_ref;
3697537048 } else .none;
3697637049
37050 const captures_len = if (small.has_captures_len) blk: {
37051 const captures_len = zir.extra[extra_index];
37052 extra_index += 1;
37053 break :blk captures_len;
37054 } else 0;
37055
3697737056 const body_len = if (small.has_body_len) blk: {
3697837057 const body_len = zir.extra[extra_index];
3697937058 extra_index += 1;
......@@ -36992,8 +37071,8 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3699237071 break :decls_len decls_len;
3699337072 } else 0;
3699437073
36995 // Skip over decls.
36996 extra_index += decls_len;
37074 // Skip over captures and decls.
37075 extra_index += captures_len + decls_len;
3699737076
3699837077 const body = zir.bodySlice(extra_index, body_len);
3699937078 extra_index += body.len;
......@@ -37027,8 +37106,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3702737106 .parent = null,
3702837107 .sema = &sema,
3702937108 .src_decl = decl_index,
37030 .namespace = union_type.namespace,
37031 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
37109 .namespace = union_type.namespace.unwrap().?,
3703237110 .instructions = .{},
3703337111 .inlining = null,
3703437112 .is_comptime = true,
......@@ -37079,7 +37157,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3707937157 // The provided type is the enum tag type.
3708037158 union_type.tagTypePtr(ip).* = provided_ty.toIntern();
3708137159 const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) {
37082 .enum_type => |x| x,
37160 .enum_type => ip.loadEnumType(provided_ty.toIntern()),
3708337161 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{provided_ty.fmt(mod)}),
3708437162 };
3708537163 // The fields of the union must match the enum exactly.
......@@ -37216,7 +37294,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3721637294 }
3721737295
3721837296 if (explicit_tags_seen.len > 0) {
37219 const tag_info = ip.indexToKey(union_type.tagTypePtr(ip).*).enum_type;
37297 const tag_info = ip.loadEnumType(union_type.tagTypePtr(ip).*);
3722037298 const enum_index = tag_info.nameIndex(ip, field_name) orelse {
3722137299 const ty_src = mod.fieldSrcLoc(union_type.decl, .{
3722237300 .index = field_i,
......@@ -37327,7 +37405,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3732737405 union_type.setFieldAligns(ip, field_aligns.items);
3732837406
3732937407 if (explicit_tags_seen.len > 0) {
37330 const tag_info = ip.indexToKey(union_type.tagTypePtr(ip).*).enum_type;
37408 const tag_info = ip.loadEnumType(union_type.tagTypePtr(ip).*);
3733137409 if (tag_info.names.len > fields_len) {
3733237410 const msg = msg: {
3733337411 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});
......@@ -37348,7 +37426,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3734837426 const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), mod.declPtr(union_type.decl));
3734937427 union_type.tagTypePtr(ip).* = enum_ty;
3735037428 } else {
37351 const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_type.decl.toOptional());
37429 const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, mod.declPtr(union_type.decl));
3735237430 union_type.tagTypePtr(ip).* = enum_ty;
3735337431 }
3735437432}
......@@ -37365,16 +37443,16 @@ fn generateUnionTagTypeNumbered(
3736537443 block: *Block,
3736637444 enum_field_names: []const InternPool.NullTerminatedString,
3736737445 enum_field_vals: []const InternPool.Index,
37368 decl: *Module.Decl,
37446 union_owner_decl: *Module.Decl,
3736937447) !InternPool.Index {
3737037448 const mod = sema.mod;
3737137449 const gpa = sema.gpa;
3737237450 const ip = &mod.intern_pool;
3737337451
3737437452 const src_decl = mod.declPtr(block.src_decl);
37375 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
37453 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node);
3737637454 errdefer mod.destroyDecl(new_decl_index);
37377 const fqn = try decl.fullyQualifiedName(mod);
37455 const fqn = try union_owner_decl.fullyQualifiedName(mod);
3737837456 const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
3737937457 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
3738037458 .ty = Type.noreturn,
......@@ -37386,9 +37464,9 @@ fn generateUnionTagTypeNumbered(
3738637464 new_decl.owns_tv = true;
3738737465 new_decl.name_fully_qualified = true;
3738837466
37389 const enum_ty = try ip.getEnum(gpa, .{
37467 const enum_ty = try ip.getGeneratedTagEnumType(gpa, .{
3739037468 .decl = new_decl_index,
37391 .namespace = .none,
37469 .owner_union_ty = union_owner_decl.val.toIntern(),
3739237470 .tag_ty = if (enum_field_vals.len == 0)
3739337471 (try mod.intType(.unsigned, 0)).toIntern()
3739437472 else
......@@ -37396,7 +37474,6 @@ fn generateUnionTagTypeNumbered(
3739637474 .names = enum_field_names,
3739737475 .values = enum_field_vals,
3739837476 .tag_mode = .explicit,
37399 .zir_index = .none,
3740037477 });
3740137478
3740237479 new_decl.ty = Type.type;
......@@ -37410,22 +37487,16 @@ fn generateUnionTagTypeSimple(
3741037487 sema: *Sema,
3741137488 block: *Block,
3741237489 enum_field_names: []const InternPool.NullTerminatedString,
37413 maybe_decl_index: InternPool.OptionalDeclIndex,
37490 union_owner_decl: *Module.Decl,
3741437491) !InternPool.Index {
3741537492 const mod = sema.mod;
3741637493 const ip = &mod.intern_pool;
3741737494 const gpa = sema.gpa;
3741837495
3741937496 const new_decl_index = new_decl_index: {
37420 const decl_index = maybe_decl_index.unwrap() orelse {
37421 break :new_decl_index try mod.createAnonymousDecl(block, .{
37422 .ty = Type.noreturn,
37423 .val = Value.@"unreachable",
37424 });
37425 };
37426 const fqn = try mod.declPtr(decl_index).fullyQualifiedName(mod);
37497 const fqn = try union_owner_decl.fullyQualifiedName(mod);
3742737498 const src_decl = mod.declPtr(block.src_decl);
37428 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
37499 const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node);
3742937500 errdefer mod.destroyDecl(new_decl_index);
3743037501 const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
3743137502 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
......@@ -37437,9 +37508,9 @@ fn generateUnionTagTypeSimple(
3743737508 };
3743837509 errdefer mod.abortAnonDecl(new_decl_index);
3743937510
37440 const enum_ty = try ip.getEnum(gpa, .{
37511 const enum_ty = try ip.getGeneratedTagEnumType(gpa, .{
3744137512 .decl = new_decl_index,
37442 .namespace = .none,
37513 .owner_union_ty = union_owner_decl.val.toIntern(),
3744337514 .tag_ty = if (enum_field_names.len == 0)
3744437515 (try mod.intType(.unsigned, 0)).toIntern()
3744537516 else
......@@ -37447,7 +37518,6 @@ fn generateUnionTagTypeSimple(
3744737518 .names = enum_field_names,
3744837519 .values = &.{},
3744937520 .tag_mode = .auto,
37450 .zir_index = .none,
3745137521 });
3745237522
3745337523 const new_decl = mod.declPtr(new_decl_index);
......@@ -37460,7 +37530,6 @@ fn generateUnionTagTypeSimple(
3746037530}
3746137531
3746237532fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
37463 const mod = sema.mod;
3746437533 const gpa = sema.gpa;
3746537534 const src = LazySrcLoc.nodeOffset(0);
3746637535
......@@ -37469,7 +37538,6 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
3746937538 .sema = sema,
3747037539 .src_decl = sema.owner_decl_index,
3747137540 .namespace = sema.owner_decl.src_namespace,
37472 .wip_capture_scope = try mod.createCaptureScope(sema.owner_decl.src_scope),
3747337541 .instructions = .{},
3747437542 .inlining = null,
3747537543 .is_comptime = true,
......@@ -37510,7 +37578,6 @@ fn getBuiltinDecl(sema: *Sema, block: *Block, name: []const u8) CompileError!Int
3751037578}
3751137579
3751237580fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
37513 const mod = sema.mod;
3751437581 const ty_inst = try sema.getBuiltin(name);
3751537582
3751637583 var block: Block = .{
......@@ -37518,7 +37585,6 @@ fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
3751837585 .sema = sema,
3751937586 .src_decl = sema.owner_decl_index,
3752037587 .namespace = sema.owner_decl.src_namespace,
37521 .wip_capture_scope = try mod.createCaptureScope(sema.owner_decl.src_scope),
3752237588 .instructions = .{},
3752337589 .inlining = null,
3752437590 .is_comptime = true,
......@@ -37636,6 +37702,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3763637702 => unreachable,
3763737703
3763837704 _ => switch (ip.items.items(.tag)[@intFromEnum(ty.toIntern())]) {
37705 .removed => unreachable,
37706
3763937707 .type_int_signed, // i0 handled above
3764037708 .type_int_unsigned, // u0 handled above
3764137709 .type_pointer,
......@@ -37713,7 +37781,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3771337781 .type_enum_explicit,
3771437782 .type_enum_nonexhaustive,
3771537783 .type_struct,
37716 .type_struct_ns,
3771737784 .type_struct_anon,
3771837785 .type_struct_packed,
3771937786 .type_struct_packed_inits,
......@@ -37736,8 +37803,9 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3773637803 return null;
3773737804 },
3773837805
37739 .struct_type => |struct_type| {
37740 try sema.resolveTypeFields(ty);
37806 .struct_type => {
37807 const struct_type = ip.loadStructType(ty.toIntern());
37808 try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type);
3774137809
3774237810 if (struct_type.field_types.len == 0) {
3774337811 // In this case the struct has no fields at all and
......@@ -37795,10 +37863,10 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3779537863 } })));
3779637864 },
3779737865
37798 .union_type => |union_type| {
37799 try sema.resolveTypeFields(ty);
37800 const union_obj = ip.loadUnionType(union_type);
37801 const tag_val = (try sema.typeHasOnePossibleValue(Type.fromInterned(union_obj.enum_tag_ty))) orelse
37866 .union_type => {
37867 const union_obj = ip.loadUnionType(ty.toIntern());
37868 try sema.resolveTypeFieldsUnion(ty, union_obj);
37869 const tag_val = (try sema.typeHasOnePossibleValue(Type.fromInterned(union_obj.tagTypePtr(ip).*))) orelse
3780237870 return null;
3780337871 if (union_obj.field_types.len == 0) {
3780437872 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
......@@ -37825,39 +37893,42 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3782537893 return Value.fromInterned(only);
3782637894 },
3782737895
37828 .enum_type => |enum_type| switch (enum_type.tag_mode) {
37829 .nonexhaustive => {
37830 if (enum_type.tag_ty == .comptime_int_type) return null;
37896 .enum_type => {
37897 const enum_type = ip.loadEnumType(ty.toIntern());
37898 switch (enum_type.tag_mode) {
37899 .nonexhaustive => {
37900 if (enum_type.tag_ty == .comptime_int_type) return null;
3783137901
37832 if (try sema.typeHasOnePossibleValue(Type.fromInterned(enum_type.tag_ty))) |int_opv| {
37833 const only = try mod.intern(.{ .enum_tag = .{
37834 .ty = ty.toIntern(),
37835 .int = int_opv.toIntern(),
37836 } });
37837 return Value.fromInterned(only);
37838 }
37902 if (try sema.typeHasOnePossibleValue(Type.fromInterned(enum_type.tag_ty))) |int_opv| {
37903 const only = try mod.intern(.{ .enum_tag = .{
37904 .ty = ty.toIntern(),
37905 .int = int_opv.toIntern(),
37906 } });
37907 return Value.fromInterned(only);
37908 }
3783937909
37840 return null;
37841 },
37842 .auto, .explicit => {
37843 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;
37844
37845 return Value.fromInterned(switch (enum_type.names.len) {
37846 0 => try mod.intern(.{ .empty_enum_value = ty.toIntern() }),
37847 1 => try mod.intern(.{ .enum_tag = .{
37848 .ty = ty.toIntern(),
37849 .int = if (enum_type.values.len == 0)
37850 (try mod.intValue(Type.fromInterned(enum_type.tag_ty), 0)).toIntern()
37851 else
37852 try mod.intern_pool.getCoercedInts(
37853 mod.gpa,
37854 mod.intern_pool.indexToKey(enum_type.values.get(ip)[0]).int,
37855 enum_type.tag_ty,
37856 ),
37857 } }),
37858 else => return null,
37859 });
37860 },
37910 return null;
37911 },
37912 .auto, .explicit => {
37913 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;
37914
37915 return Value.fromInterned(switch (enum_type.names.len) {
37916 0 => try mod.intern(.{ .empty_enum_value = ty.toIntern() }),
37917 1 => try mod.intern(.{ .enum_tag = .{
37918 .ty = ty.toIntern(),
37919 .int = if (enum_type.values.len == 0)
37920 (try mod.intValue(Type.fromInterned(enum_type.tag_ty), 0)).toIntern()
37921 else
37922 try mod.intern_pool.getCoercedInts(
37923 mod.gpa,
37924 mod.intern_pool.indexToKey(enum_type.values.get(ip)[0]).int,
37925 enum_type.tag_ty,
37926 ),
37927 } }),
37928 else => return null,
37929 });
37930 },
37931 }
3786137932 },
3786237933
3786337934 else => unreachable,
......@@ -38189,7 +38260,7 @@ fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {
3818938260
3819038261/// Not valid to call for packed unions.
3819138262/// Keep implementation in sync with `Module.unionFieldNormalAlignment`.
38192fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !Alignment {
38263fn unionFieldAlignment(sema: *Sema, u: InternPool.LoadedUnionType, field_index: u32) !Alignment {
3819338264 const mod = sema.mod;
3819438265 const ip = &mod.intern_pool;
3819538266 const field_align = u.fieldAlign(ip, field_index);
......@@ -38237,7 +38308,7 @@ fn unionFieldIndex(
3823738308 const ip = &mod.intern_pool;
3823838309 try sema.resolveTypeFields(union_ty);
3823938310 const union_obj = mod.typeToUnion(union_ty).?;
38240 const field_index = union_obj.nameIndex(ip, field_name) orelse
38311 const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse
3824138312 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
3824238313 return @intCast(field_index);
3824338314}
......@@ -38274,7 +38345,7 @@ fn anonStructFieldIndex(
3827438345 .anon_struct_type => |anon_struct_type| for (anon_struct_type.names.get(ip), 0..) |name, i| {
3827538346 if (name == field_name) return @intCast(i);
3827638347 },
38277 .struct_type => |struct_type| if (struct_type.nameIndex(ip, field_name)) |i| return i,
38348 .struct_type => if (ip.loadStructType(struct_ty.toIntern()).nameIndex(ip, field_name)) |i| return i,
3827838349 else => unreachable,
3827938350 }
3828038351 return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{
......@@ -38710,7 +38781,7 @@ fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
3871038781/// Asserts the type is an enum.
3871138782fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
3871238783 const mod = sema.mod;
38713 const enum_type = mod.intern_pool.indexToKey(ty.toIntern()).enum_type;
38784 const enum_type = mod.intern_pool.loadEnumType(ty.toIntern());
3871438785 assert(enum_type.tag_mode != .nonexhaustive);
3871538786 // The `tagValueIndex` function call below relies on the type being the integer tag type.
3871638787 // `getCoerced` assumes the value will fit the new type.
src/TypedValue.zig+4-8
......@@ -89,7 +89,7 @@ pub fn print(
8989
9090 if (payload.tag) |tag| {
9191 try print(.{
92 .ty = Type.fromInterned(ip.indexToKey(ty.toIntern()).union_type.enum_tag_ty),
92 .ty = Type.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_ty),
9393 .val = tag,
9494 }, writer, level - 1, mod);
9595 try writer.writeAll(" = ");
......@@ -247,7 +247,7 @@ pub fn print(
247247 if (level == 0) {
248248 return writer.writeAll("(enum)");
249249 }
250 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
250 const enum_type = ip.loadEnumType(ty.toIntern());
251251 if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| {
252252 try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)});
253253 return;
......@@ -398,7 +398,7 @@ pub fn print(
398398 }
399399 },
400400 .Union => {
401 const field_name = mod.typeToUnion(container_ty).?.field_names.get(ip)[@intCast(field.index)];
401 const field_name = mod.typeToUnion(container_ty).?.loadTagType(ip).names.get(ip)[@intCast(field.index)];
402402 try writer.print(".{i}", .{field_name.fmt(ip)});
403403 },
404404 .Pointer => {
......@@ -482,11 +482,7 @@ fn printAggregate(
482482 for (0..max_len) |i| {
483483 if (i != 0) try writer.writeAll(", ");
484484
485 const field_name = switch (ip.indexToKey(ty.toIntern())) {
486 .struct_type => |x| x.fieldName(ip, i),
487 .anon_struct_type => |x| if (x.isTuple()) .none else x.names.get(ip)[i].toOptional(),
488 else => unreachable,
489 };
485 const field_name = ty.structFieldName(@intCast(i), mod);
490486
491487 if (field_name.unwrap()) |name| try writer.print(".{} = ", .{name.fmt(ip)});
492488 try print(.{
src/Value.zig+16-10
......@@ -424,22 +424,28 @@ pub fn toType(self: Value) Type {
424424
425425pub fn intFromEnum(val: Value, ty: Type, mod: *Module) Allocator.Error!Value {
426426 const ip = &mod.intern_pool;
427 return switch (ip.indexToKey(ip.typeOf(val.toIntern()))) {
427 const enum_ty = ip.typeOf(val.toIntern());
428 return switch (ip.indexToKey(enum_ty)) {
428429 // Assume it is already an integer and return it directly.
429430 .simple_type, .int_type => val,
430431 .enum_literal => |enum_literal| {
431432 const field_index = ty.enumFieldIndex(enum_literal, mod).?;
432 return switch (ip.indexToKey(ty.toIntern())) {
433 switch (ip.indexToKey(ty.toIntern())) {
433434 // Assume it is already an integer and return it directly.
434 .simple_type, .int_type => val,
435 .enum_type => |enum_type| if (enum_type.values.len != 0)
436 Value.fromInterned(enum_type.values.get(ip)[field_index])
437 else // Field index and integer values are the same.
438 mod.intValue(Type.fromInterned(enum_type.tag_ty), field_index),
435 .simple_type, .int_type => return val,
436 .enum_type => {
437 const enum_type = ip.loadEnumType(ty.toIntern());
438 if (enum_type.values.len != 0) {
439 return Value.fromInterned(enum_type.values.get(ip)[field_index]);
440 } else {
441 // Field index and integer values are the same.
442 return mod.intValue(Type.fromInterned(enum_type.tag_ty), field_index);
443 }
444 },
439445 else => unreachable,
440 };
446 }
441447 },
442 .enum_type => |enum_type| try mod.getCoerced(val, Type.fromInterned(enum_type.tag_ty)),
448 .enum_type => try mod.getCoerced(val, Type.fromInterned(ip.loadEnumType(enum_ty).tag_ty)),
443449 else => unreachable,
444450 };
445451}
......@@ -832,7 +838,7 @@ pub fn writeToPackedMemory(
832838 }
833839 },
834840 .Struct => {
835 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
841 const struct_type = ip.loadStructType(ty.toIntern());
836842 // Sema is supposed to have emitted a compile error already in the case of Auto,
837843 // and Extern is handled in non-packed writeToMemory.
838844 assert(struct_type.layout == .Packed);
src/arch/wasm/CodeGen.zig+3-2
......@@ -3354,7 +3354,8 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
33543354 val.writeToMemory(ty, mod, &buf) catch unreachable;
33553355 return func.storeSimdImmd(buf);
33563356 },
3357 .struct_type => |struct_type| {
3357 .struct_type => {
3358 const struct_type = ip.loadStructType(ty.toIntern());
33583359 // non-packed structs are not handled in this function because they
33593360 // are by-ref types.
33603361 assert(struct_type.layout == .Packed);
......@@ -5411,7 +5412,7 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
54115412 const layout = union_ty.unionGetLayout(mod);
54125413 const union_obj = mod.typeToUnion(union_ty).?;
54135414 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]);
5414 const field_name = union_obj.field_names.get(ip)[extra.field_index];
5415 const field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
54155416
54165417 const tag_int = blk: {
54175418 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
src/arch/wasm/abi.zig+1-1
......@@ -76,7 +76,7 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {
7676 }
7777 const layout = ty.unionGetLayout(mod);
7878 assert(layout.tag_size == 0);
79 if (union_obj.field_names.len > 1) return memory;
79 if (union_obj.field_types.len > 1) return memory;
8080 const first_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[0]);
8181 return classifyType(first_field_ty, mod);
8282 },
src/arch/x86_64/CodeGen.zig+1-1
......@@ -18183,7 +18183,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
1818318183 const dst_mcv = try self.allocRegOrMem(inst, false);
1818418184
1818518185 const union_obj = mod.typeToUnion(union_ty).?;
18186 const field_name = union_obj.field_names.get(ip)[extra.field_index];
18186 const field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
1818718187 const tag_ty = Type.fromInterned(union_obj.enum_tag_ty);
1818818188 const field_index = tag_ty.enumFieldIndex(field_name, mod).?;
1818918189 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
src/codegen.zig+73-70
......@@ -510,88 +510,91 @@ pub fn generateSymbol(
510510 }
511511 }
512512 },
513 .struct_type => |struct_type| switch (struct_type.layout) {
514 .Packed => {
515 const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse
516 return error.Overflow;
517 const current_pos = code.items.len;
518 try code.resize(current_pos + abi_size);
519 var bits: u16 = 0;
520
521 for (struct_type.field_types.get(ip), 0..) |field_ty, index| {
522 const field_val = switch (aggregate.storage) {
523 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
524 .ty = field_ty,
525 .storage = .{ .u64 = bytes[index] },
526 } }),
527 .elems => |elems| elems[index],
528 .repeated_elem => |elem| elem,
529 };
513 .struct_type => {
514 const struct_type = ip.loadStructType(typed_value.ty.toIntern());
515 switch (struct_type.layout) {
516 .Packed => {
517 const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse
518 return error.Overflow;
519 const current_pos = code.items.len;
520 try code.resize(current_pos + abi_size);
521 var bits: u16 = 0;
522
523 for (struct_type.field_types.get(ip), 0..) |field_ty, index| {
524 const field_val = switch (aggregate.storage) {
525 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
526 .ty = field_ty,
527 .storage = .{ .u64 = bytes[index] },
528 } }),
529 .elems => |elems| elems[index],
530 .repeated_elem => |elem| elem,
531 };
532
533 // pointer may point to a decl which must be marked used
534 // but can also result in a relocation. Therefore we handle those separately.
535 if (Type.fromInterned(field_ty).zigTypeTag(mod) == .Pointer) {
536 const field_size = math.cast(usize, Type.fromInterned(field_ty).abiSize(mod)) orelse
537 return error.Overflow;
538 var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size);
539 defer tmp_list.deinit();
540 switch (try generateSymbol(bin_file, src_loc, .{
541 .ty = Type.fromInterned(field_ty),
542 .val = Value.fromInterned(field_val),
543 }, &tmp_list, debug_output, reloc_info)) {
544 .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items),
545 .fail => |em| return Result{ .fail = em },
546 }
547 } else {
548 Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), mod, code.items[current_pos..], bits) catch unreachable;
549 }
550 bits += @as(u16, @intCast(Type.fromInterned(field_ty).bitSize(mod)));
551 }
552 },
553 .Auto, .Extern => {
554 const struct_begin = code.items.len;
555 const field_types = struct_type.field_types.get(ip);
556 const offsets = struct_type.offsets.get(ip);
557
558 var it = struct_type.iterateRuntimeOrder(ip);
559 while (it.next()) |field_index| {
560 const field_ty = field_types[field_index];
561 if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;
562
563 const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) {
564 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
565 .ty = field_ty,
566 .storage = .{ .u64 = bytes[field_index] },
567 } }),
568 .elems => |elems| elems[field_index],
569 .repeated_elem => |elem| elem,
570 };
571
572 const padding = math.cast(
573 usize,
574 offsets[field_index] - (code.items.len - struct_begin),
575 ) orelse return error.Overflow;
576 if (padding > 0) try code.appendNTimes(0, padding);
530577
531 // pointer may point to a decl which must be marked used
532 // but can also result in a relocation. Therefore we handle those separately.
533 if (Type.fromInterned(field_ty).zigTypeTag(mod) == .Pointer) {
534 const field_size = math.cast(usize, Type.fromInterned(field_ty).abiSize(mod)) orelse
535 return error.Overflow;
536 var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size);
537 defer tmp_list.deinit();
538578 switch (try generateSymbol(bin_file, src_loc, .{
539579 .ty = Type.fromInterned(field_ty),
540580 .val = Value.fromInterned(field_val),
541 }, &tmp_list, debug_output, reloc_info)) {
542 .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items),
581 }, code, debug_output, reloc_info)) {
582 .ok => {},
543583 .fail => |em| return Result{ .fail = em },
544584 }
545 } else {
546 Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), mod, code.items[current_pos..], bits) catch unreachable;
547585 }
548 bits += @as(u16, @intCast(Type.fromInterned(field_ty).bitSize(mod)));
549 }
550 },
551 .Auto, .Extern => {
552 const struct_begin = code.items.len;
553 const field_types = struct_type.field_types.get(ip);
554 const offsets = struct_type.offsets.get(ip);
555
556 var it = struct_type.iterateRuntimeOrder(ip);
557 while (it.next()) |field_index| {
558 const field_ty = field_types[field_index];
559 if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;
560
561 const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) {
562 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
563 .ty = field_ty,
564 .storage = .{ .u64 = bytes[field_index] },
565 } }),
566 .elems => |elems| elems[field_index],
567 .repeated_elem => |elem| elem,
568 };
586
587 const size = struct_type.size(ip).*;
588 const alignment = struct_type.flagsPtr(ip).alignment.toByteUnitsOptional().?;
569589
570590 const padding = math.cast(
571591 usize,
572 offsets[field_index] - (code.items.len - struct_begin),
592 std.mem.alignForward(u64, size, @max(alignment, 1)) -
593 (code.items.len - struct_begin),
573594 ) orelse return error.Overflow;
574595 if (padding > 0) try code.appendNTimes(0, padding);
575
576 switch (try generateSymbol(bin_file, src_loc, .{
577 .ty = Type.fromInterned(field_ty),
578 .val = Value.fromInterned(field_val),
579 }, code, debug_output, reloc_info)) {
580 .ok => {},
581 .fail => |em| return Result{ .fail = em },
582 }
583 }
584
585 const size = struct_type.size(ip).*;
586 const alignment = struct_type.flagsPtr(ip).alignment.toByteUnitsOptional().?;
587
588 const padding = math.cast(
589 usize,
590 std.mem.alignForward(u64, size, @max(alignment, 1)) -
591 (code.items.len - struct_begin),
592 ) orelse return error.Overflow;
593 if (padding > 0) try code.appendNTimes(0, padding);
594 },
596 },
597 }
595598 },
596599 else => unreachable,
597600 },
src/codegen/c.zig+113-110
......@@ -1376,70 +1376,24 @@ pub const DeclGen = struct {
13761376 }
13771377 try writer.writeByte('}');
13781378 },
1379 .struct_type => |struct_type| switch (struct_type.layout) {
1380 .Auto, .Extern => {
1381 if (!location.isInitializer()) {
1382 try writer.writeByte('(');
1383 try dg.renderType(writer, ty);
1384 try writer.writeByte(')');
1385 }
1386
1387 try writer.writeByte('{');
1388 var empty = true;
1389 for (0..struct_type.field_types.len) |field_index| {
1390 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1391 if (struct_type.fieldIsComptime(ip, field_index)) continue;
1392 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
1393
1394 if (!empty) try writer.writeByte(',');
1395 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1396 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1397 .ty = field_ty.toIntern(),
1398 .storage = .{ .u64 = bytes[field_index] },
1399 } }),
1400 .elems => |elems| elems[field_index],
1401 .repeated_elem => |elem| elem,
1402 };
1403 try dg.renderValue(writer, field_ty, Value.fromInterned(field_val), initializer_type);
1404
1405 empty = false;
1406 }
1407 try writer.writeByte('}');
1408 },
1409 .Packed => {
1410 const int_info = ty.intInfo(mod);
1411
1412 const bits = Type.smallestUnsignedBits(int_info.bits - 1);
1413 const bit_offset_ty = try mod.intType(.unsigned, bits);
1414
1415 var bit_offset: u64 = 0;
1416 var eff_num_fields: usize = 0;
1417
1418 for (0..struct_type.field_types.len) |field_index| {
1419 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1420 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
1421 eff_num_fields += 1;
1422 }
1423
1424 if (eff_num_fields == 0) {
1425 try writer.writeByte('(');
1426 try dg.renderValue(writer, ty, Value.undef, initializer_type);
1427 try writer.writeByte(')');
1428 } else if (ty.bitSize(mod) > 64) {
1429 // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
1430 var num_or = eff_num_fields - 1;
1431 while (num_or > 0) : (num_or -= 1) {
1432 try writer.writeAll("zig_or_");
1433 try dg.renderTypeForBuiltinFnName(writer, ty);
1379 .struct_type => {
1380 const struct_type = ip.loadStructType(ty.toIntern());
1381 switch (struct_type.layout) {
1382 .Auto, .Extern => {
1383 if (!location.isInitializer()) {
14341384 try writer.writeByte('(');
1385 try dg.renderType(writer, ty);
1386 try writer.writeByte(')');
14351387 }
14361388
1437 var eff_index: usize = 0;
1438 var needs_closing_paren = false;
1389 try writer.writeByte('{');
1390 var empty = true;
14391391 for (0..struct_type.field_types.len) |field_index| {
14401392 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1393 if (struct_type.fieldIsComptime(ip, field_index)) continue;
14411394 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
14421395
1396 if (!empty) try writer.writeByte(',');
14431397 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
14441398 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
14451399 .ty = field_ty.toIntern(),
......@@ -1448,64 +1402,113 @@ pub const DeclGen = struct {
14481402 .elems => |elems| elems[field_index],
14491403 .repeated_elem => |elem| elem,
14501404 };
1451 const cast_context = IntCastContext{ .value = .{ .value = Value.fromInterned(field_val) } };
1452 if (bit_offset != 0) {
1453 try writer.writeAll("zig_shl_");
1454 try dg.renderTypeForBuiltinFnName(writer, ty);
1455 try writer.writeByte('(');
1456 try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
1457 try writer.writeAll(", ");
1458 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
1459 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1460 try writer.writeByte(')');
1461 } else {
1462 try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
1463 }
1464
1465 if (needs_closing_paren) try writer.writeByte(')');
1466 if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
1405 try dg.renderValue(writer, field_ty, Value.fromInterned(field_val), initializer_type);
14671406
1468 bit_offset += field_ty.bitSize(mod);
1469 needs_closing_paren = true;
1470 eff_index += 1;
1407 empty = false;
14711408 }
1472 } else {
1473 try writer.writeByte('(');
1474 // a << a_off | b << b_off | c << c_off
1475 var empty = true;
1409 try writer.writeByte('}');
1410 },
1411 .Packed => {
1412 const int_info = ty.intInfo(mod);
1413
1414 const bits = Type.smallestUnsignedBits(int_info.bits - 1);
1415 const bit_offset_ty = try mod.intType(.unsigned, bits);
1416
1417 var bit_offset: u64 = 0;
1418 var eff_num_fields: usize = 0;
1419
14761420 for (0..struct_type.field_types.len) |field_index| {
14771421 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
14781422 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
1423 eff_num_fields += 1;
1424 }
14791425
1480 if (!empty) try writer.writeAll(" | ");
1426 if (eff_num_fields == 0) {
14811427 try writer.writeByte('(');
1482 try dg.renderType(writer, ty);
1428 try dg.renderValue(writer, ty, Value.undef, initializer_type);
14831429 try writer.writeByte(')');
1430 } else if (ty.bitSize(mod) > 64) {
1431 // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
1432 var num_or = eff_num_fields - 1;
1433 while (num_or > 0) : (num_or -= 1) {
1434 try writer.writeAll("zig_or_");
1435 try dg.renderTypeForBuiltinFnName(writer, ty);
1436 try writer.writeByte('(');
1437 }
14841438
1485 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1486 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1487 .ty = field_ty.toIntern(),
1488 .storage = .{ .u64 = bytes[field_index] },
1489 } }),
1490 .elems => |elems| elems[field_index],
1491 .repeated_elem => |elem| elem,
1492 };
1493
1494 if (bit_offset != 0) {
1495 try dg.renderValue(writer, field_ty, Value.fromInterned(field_val), .Other);
1496 try writer.writeAll(" << ");
1497 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
1498 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1499 } else {
1500 try dg.renderValue(writer, field_ty, Value.fromInterned(field_val), .Other);
1439 var eff_index: usize = 0;
1440 var needs_closing_paren = false;
1441 for (0..struct_type.field_types.len) |field_index| {
1442 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1443 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
1444
1445 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1446 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1447 .ty = field_ty.toIntern(),
1448 .storage = .{ .u64 = bytes[field_index] },
1449 } }),
1450 .elems => |elems| elems[field_index],
1451 .repeated_elem => |elem| elem,
1452 };
1453 const cast_context = IntCastContext{ .value = .{ .value = Value.fromInterned(field_val) } };
1454 if (bit_offset != 0) {
1455 try writer.writeAll("zig_shl_");
1456 try dg.renderTypeForBuiltinFnName(writer, ty);
1457 try writer.writeByte('(');
1458 try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
1459 try writer.writeAll(", ");
1460 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
1461 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1462 try writer.writeByte(')');
1463 } else {
1464 try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
1465 }
1466
1467 if (needs_closing_paren) try writer.writeByte(')');
1468 if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
1469
1470 bit_offset += field_ty.bitSize(mod);
1471 needs_closing_paren = true;
1472 eff_index += 1;
15011473 }
1474 } else {
1475 try writer.writeByte('(');
1476 // a << a_off | b << b_off | c << c_off
1477 var empty = true;
1478 for (0..struct_type.field_types.len) |field_index| {
1479 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1480 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
15021481
1503 bit_offset += field_ty.bitSize(mod);
1504 empty = false;
1482 if (!empty) try writer.writeAll(" | ");
1483 try writer.writeByte('(');
1484 try dg.renderType(writer, ty);
1485 try writer.writeByte(')');
1486
1487 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1488 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1489 .ty = field_ty.toIntern(),
1490 .storage = .{ .u64 = bytes[field_index] },
1491 } }),
1492 .elems => |elems| elems[field_index],
1493 .repeated_elem => |elem| elem,
1494 };
1495
1496 if (bit_offset != 0) {
1497 try dg.renderValue(writer, field_ty, Value.fromInterned(field_val), .Other);
1498 try writer.writeAll(" << ");
1499 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
1500 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1501 } else {
1502 try dg.renderValue(writer, field_ty, Value.fromInterned(field_val), .Other);
1503 }
1504
1505 bit_offset += field_ty.bitSize(mod);
1506 empty = false;
1507 }
1508 try writer.writeByte(')');
15051509 }
1506 try writer.writeByte(')');
1507 }
1508 },
1510 },
1511 }
15091512 },
15101513 else => unreachable,
15111514 },
......@@ -1547,7 +1550,7 @@ pub const DeclGen = struct {
15471550
15481551 const field_index = mod.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;
15491552 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
1550 const field_name = union_obj.field_names.get(ip)[field_index];
1553 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
15511554 if (union_obj.getLayout(ip) == .Packed) {
15521555 if (field_ty.hasRuntimeBits(mod)) {
15531556 if (field_ty.isPtrAtRuntime(mod)) {
......@@ -5502,7 +5505,7 @@ fn fieldLocation(
55025505 .{ .field = .{ .identifier = "payload" } }
55035506 else
55045507 .begin;
5505 const field_name = union_obj.field_names.get(ip)[field_index];
5508 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
55065509 return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_|
55075510 .{ .payload_identifier = ip.stringToSlice(field_name) }
55085511 else
......@@ -5735,8 +5738,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
57355738 else
57365739 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, mod)) },
57375740
5738 .union_type => |union_type| field_name: {
5739 const union_obj = ip.loadUnionType(union_type);
5741 .union_type => field_name: {
5742 const union_obj = ip.loadUnionType(struct_ty.toIntern());
57405743 if (union_obj.flagsPtr(ip).layout == .Packed) {
57415744 const operand_lval = if (struct_byval == .constant) blk: {
57425745 const operand_local = try f.allocLocal(inst, struct_ty);
......@@ -5762,8 +5765,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
57625765
57635766 return local;
57645767 } else {
5765 const name = union_obj.field_names.get(ip)[extra.field_index];
5766 break :field_name if (union_type.hasTag(ip)) .{
5768 const name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
5769 break :field_name if (union_obj.hasTag(ip)) .{
57675770 .payload_identifier = ip.stringToSlice(name),
57685771 } else .{
57695772 .identifier = ip.stringToSlice(name),
......@@ -7171,7 +7174,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
71717174
71727175 const union_ty = f.typeOfIndex(inst);
71737176 const union_obj = mod.typeToUnion(union_ty).?;
7174 const field_name = union_obj.field_names.get(ip)[extra.field_index];
7177 const field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
71757178 const payload_ty = f.typeOf(extra.init);
71767179 const payload = try f.resolveInst(extra.init);
71777180 try reap(f, inst, &.{extra.init});
src/codegen/c/type.zig+8-8
......@@ -1507,7 +1507,7 @@ pub const CType = extern union {
15071507 if (lookup.isMutable()) {
15081508 for (0..switch (zig_ty_tag) {
15091509 .Struct => ty.structFieldCount(mod),
1510 .Union => mod.typeToUnion(ty).?.field_names.len,
1510 .Union => mod.typeToUnion(ty).?.field_types.len,
15111511 else => unreachable,
15121512 }) |field_i| {
15131513 const field_ty = ty.structFieldType(field_i, mod);
......@@ -1589,7 +1589,7 @@ pub const CType = extern union {
15891589 var is_packed = false;
15901590 for (0..switch (zig_ty_tag) {
15911591 .Struct => ty.structFieldCount(mod),
1592 .Union => mod.typeToUnion(ty).?.field_names.len,
1592 .Union => mod.typeToUnion(ty).?.field_types.len,
15931593 else => unreachable,
15941594 }) |field_i| {
15951595 const field_ty = ty.structFieldType(field_i, mod);
......@@ -1940,7 +1940,7 @@ pub const CType = extern union {
19401940 const zig_ty_tag = ty.zigTypeTag(mod);
19411941 const fields_len = switch (zig_ty_tag) {
19421942 .Struct => ty.structFieldCount(mod),
1943 .Union => mod.typeToUnion(ty).?.field_names.len,
1943 .Union => mod.typeToUnion(ty).?.field_types.len,
19441944 else => unreachable,
19451945 };
19461946
......@@ -1967,7 +1967,7 @@ pub const CType = extern union {
19671967 else
19681968 arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {
19691969 .Struct => ty.legacyStructFieldName(field_i, mod),
1970 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
1970 .Union => ip.loadUnionType(ty.toIntern()).loadTagType(ip).names.get(ip)[field_i],
19711971 else => unreachable,
19721972 })),
19731973 .type = store.set.typeToIndex(field_ty, mod, switch (kind) {
......@@ -2097,7 +2097,7 @@ pub const CType = extern union {
20972097 var c_field_i: usize = 0;
20982098 for (0..switch (zig_ty_tag) {
20992099 .Struct => ty.structFieldCount(mod),
2100 .Union => mod.typeToUnion(ty).?.field_names.len,
2100 .Union => mod.typeToUnion(ty).?.field_types.len,
21012101 else => unreachable,
21022102 }) |field_i_usize| {
21032103 const field_i: u32 = @intCast(field_i_usize);
......@@ -2120,7 +2120,7 @@ pub const CType = extern union {
21202120 else
21212121 ip.stringToSlice(switch (zig_ty_tag) {
21222122 .Struct => ty.legacyStructFieldName(field_i, mod),
2123 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
2123 .Union => ip.loadUnionType(ty.toIntern()).loadTagType(ip).names.get(ip)[field_i],
21242124 else => unreachable,
21252125 }),
21262126 mem.span(c_field.name),
......@@ -2226,7 +2226,7 @@ pub const CType = extern union {
22262226 const zig_ty_tag = ty.zigTypeTag(mod);
22272227 for (0..switch (ty.zigTypeTag(mod)) {
22282228 .Struct => ty.structFieldCount(mod),
2229 .Union => mod.typeToUnion(ty).?.field_names.len,
2229 .Union => mod.typeToUnion(ty).?.field_types.len,
22302230 else => unreachable,
22312231 }) |field_i_usize| {
22322232 const field_i: u32 = @intCast(field_i_usize);
......@@ -2245,7 +2245,7 @@ pub const CType = extern union {
22452245 else
22462246 mod.intern_pool.stringToSlice(switch (zig_ty_tag) {
22472247 .Struct => ty.legacyStructFieldName(field_i, mod),
2248 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
2248 .Union => ip.loadUnionType(ty.toIntern()).loadTagType(ip).names.get(ip)[field_i],
22492249 else => unreachable,
22502250 }));
22512251 autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align");
src/codegen/llvm.zig+33-28
......@@ -1997,7 +1997,7 @@ pub const Object = struct {
19971997 return debug_enum_type;
19981998 }
19991999
2000 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
2000 const enum_type = ip.loadEnumType(ty.toIntern());
20012001
20022002 const enumerators = try gpa.alloc(Builder.Metadata, enum_type.names.len);
20032003 defer gpa.free(enumerators);
......@@ -2507,8 +2507,8 @@ pub const Object = struct {
25072507 try o.debug_type_map.put(gpa, ty, debug_struct_type);
25082508 return debug_struct_type;
25092509 },
2510 .struct_type => |struct_type| {
2511 if (!struct_type.haveFieldTypes(ip)) {
2510 .struct_type => {
2511 if (!ip.loadStructType(ty.toIntern()).haveFieldTypes(ip)) {
25122512 // This can happen if a struct type makes it all the way to
25132513 // flush() without ever being instantiated or referenced (even
25142514 // via pointer). The only reason we are hearing about it now is
......@@ -2597,15 +2597,14 @@ pub const Object = struct {
25972597 const name = try o.allocTypeName(ty);
25982598 defer gpa.free(name);
25992599
2600 const union_type = ip.indexToKey(ty.toIntern()).union_type;
2600 const union_type = ip.loadUnionType(ty.toIntern());
26012601 if (!union_type.haveFieldTypes(ip) or !ty.hasRuntimeBitsIgnoreComptime(mod)) {
26022602 const debug_union_type = try o.makeEmptyNamespaceDebugType(owner_decl_index);
26032603 try o.debug_type_map.put(gpa, ty, debug_union_type);
26042604 return debug_union_type;
26052605 }
26062606
2607 const union_obj = ip.loadUnionType(union_type);
2608 const layout = mod.getUnionLayout(union_obj);
2607 const layout = mod.getUnionLayout(union_type);
26092608
26102609 const debug_fwd_ref = try o.builder.debugForwardReference();
26112610
......@@ -2622,7 +2621,7 @@ pub const Object = struct {
26222621 ty.abiSize(mod) * 8,
26232622 ty.abiAlignment(mod).toByteUnits(0) * 8,
26242623 try o.builder.debugTuple(
2625 &.{try o.lowerDebugType(Type.fromInterned(union_obj.enum_tag_ty))},
2624 &.{try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty))},
26262625 ),
26272626 );
26282627
......@@ -2636,21 +2635,23 @@ pub const Object = struct {
26362635 var fields: std.ArrayListUnmanaged(Builder.Metadata) = .{};
26372636 defer fields.deinit(gpa);
26382637
2639 try fields.ensureUnusedCapacity(gpa, union_obj.field_names.len);
2638 try fields.ensureUnusedCapacity(gpa, union_type.loadTagType(ip).names.len);
26402639
26412640 const debug_union_fwd_ref = if (layout.tag_size == 0)
26422641 debug_fwd_ref
26432642 else
26442643 try o.builder.debugForwardReference();
26452644
2646 for (0..union_obj.field_names.len) |field_index| {
2647 const field_ty = union_obj.field_types.get(ip)[field_index];
2645 const tag_type = union_type.loadTagType(ip);
2646
2647 for (0..tag_type.names.len) |field_index| {
2648 const field_ty = union_type.field_types.get(ip)[field_index];
26482649 if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(mod)) continue;
26492650
26502651 const field_size = Type.fromInterned(field_ty).abiSize(mod);
2651 const field_align = mod.unionFieldNormalAlignment(union_obj, @intCast(field_index));
2652 const field_align = mod.unionFieldNormalAlignment(union_type, @intCast(field_index));
26522653
2653 const field_name = union_obj.field_names.get(ip)[field_index];
2654 const field_name = tag_type.names.get(ip)[field_index];
26542655 fields.appendAssumeCapacity(try o.builder.debugMemberType(
26552656 try o.builder.metadataString(ip.stringToSlice(field_name)),
26562657 .none, // File
......@@ -2706,7 +2707,7 @@ pub const Object = struct {
27062707 .none, // File
27072708 debug_fwd_ref,
27082709 0, // Line
2709 try o.lowerDebugType(Type.fromInterned(union_obj.enum_tag_ty)),
2710 try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty)),
27102711 layout.tag_size * 8,
27112712 layout.tag_align.toByteUnits(0) * 8,
27122713 tag_offset * 8,
......@@ -3321,9 +3322,11 @@ pub const Object = struct {
33213322 return o.builder.structType(.normal, fields[0..fields_len]);
33223323 },
33233324 .simple_type => unreachable,
3324 .struct_type => |struct_type| {
3325 .struct_type => {
33253326 if (o.type_map.get(t.toIntern())) |value| return value;
33263327
3328 const struct_type = ip.loadStructType(t.toIntern());
3329
33273330 if (struct_type.layout == .Packed) {
33283331 const int_ty = try o.lowerType(Type.fromInterned(struct_type.backingIntType(ip).*));
33293332 try o.type_map.put(o.gpa, t.toIntern(), int_ty);
......@@ -3468,10 +3471,10 @@ pub const Object = struct {
34683471 }
34693472 return o.builder.structType(.normal, llvm_field_types.items);
34703473 },
3471 .union_type => |union_type| {
3474 .union_type => {
34723475 if (o.type_map.get(t.toIntern())) |value| return value;
34733476
3474 const union_obj = ip.loadUnionType(union_type);
3477 const union_obj = ip.loadUnionType(t.toIntern());
34753478 const layout = mod.getUnionLayout(union_obj);
34763479
34773480 if (union_obj.flagsPtr(ip).layout == .Packed) {
......@@ -3545,17 +3548,16 @@ pub const Object = struct {
35453548 );
35463549 return ty;
35473550 },
3548 .opaque_type => |opaque_type| {
3551 .opaque_type => {
35493552 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
35503553 if (!gop.found_existing) {
3551 const name = try o.builder.string(ip.stringToSlice(
3552 try mod.opaqueFullyQualifiedName(opaque_type),
3553 ));
3554 const decl = mod.declPtr(ip.loadOpaqueType(t.toIntern()).decl);
3555 const name = try o.builder.string(ip.stringToSlice(try decl.fullyQualifiedName(mod)));
35543556 gop.value_ptr.* = try o.builder.opaqueType(name);
35553557 }
35563558 return gop.value_ptr.*;
35573559 },
3558 .enum_type => |enum_type| try o.lowerType(Type.fromInterned(enum_type.tag_ty)),
3560 .enum_type => try o.lowerType(Type.fromInterned(ip.loadEnumType(t.toIntern()).tag_ty)),
35593561 .func_type => |func_type| try o.lowerTypeFn(func_type),
35603562 .error_set_type, .inferred_error_set_type => try o.errorIntType(),
35613563 // values, not types
......@@ -4032,7 +4034,8 @@ pub const Object = struct {
40324034 else
40334035 struct_ty, vals);
40344036 },
4035 .struct_type => |struct_type| {
4037 .struct_type => {
4038 const struct_type = ip.loadStructType(ty.toIntern());
40364039 assert(struct_type.haveLayout(ip));
40374040 const struct_ty = try o.lowerType(ty);
40384041 if (struct_type.layout == .Packed) {
......@@ -4596,7 +4599,7 @@ pub const Object = struct {
45964599 fn getEnumTagNameFunction(o: *Object, enum_ty: Type) !Builder.Function.Index {
45974600 const zcu = o.module;
45984601 const ip = &zcu.intern_pool;
4599 const enum_type = ip.indexToKey(enum_ty.toIntern()).enum_type;
4602 const enum_type = ip.loadEnumType(enum_ty.toIntern());
46004603
46014604 // TODO: detect when the type changes and re-emit this function.
46024605 const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl);
......@@ -9620,7 +9623,7 @@ pub const FuncGen = struct {
96209623 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
96219624 const o = self.dg.object;
96229625 const zcu = o.module;
9623 const enum_type = zcu.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
9626 const enum_type = zcu.intern_pool.loadEnumType(enum_ty.toIntern());
96249627
96259628 // TODO: detect when the type changes and re-emit this function.
96269629 const gop = try o.named_enum_map.getOrPut(o.gpa, enum_type.decl);
......@@ -10092,7 +10095,7 @@ pub const FuncGen = struct {
1009210095
1009310096 const tag_int = blk: {
1009410097 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
10095 const union_field_name = union_obj.field_names.get(ip)[extra.field_index];
10098 const union_field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
1009610099 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;
1009710100 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
1009810101 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);
......@@ -11154,7 +11157,8 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E
1115411157 if (first_non_integer == null or classes[first_non_integer.?] == .none) {
1115511158 assert(first_non_integer orelse classes.len == types_index);
1115611159 switch (ip.indexToKey(return_type.toIntern())) {
11157 .struct_type => |struct_type| {
11160 .struct_type => {
11161 const struct_type = ip.loadStructType(return_type.toIntern());
1115811162 assert(struct_type.haveLayout(ip));
1115911163 const size: u64 = struct_type.size(ip).*;
1116011164 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
......@@ -11446,7 +11450,8 @@ const ParamTypeIterator = struct {
1144611450 return .byref;
1144711451 }
1144811452 switch (ip.indexToKey(ty.toIntern())) {
11449 .struct_type => |struct_type| {
11453 .struct_type => {
11454 const struct_type = ip.loadStructType(ty.toIntern());
1145011455 assert(struct_type.haveLayout(ip));
1145111456 const size: u64 = struct_type.size(ip).*;
1145211457 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
......@@ -11562,7 +11567,7 @@ fn isByRef(ty: Type, mod: *Module) bool {
1156211567 }
1156311568 return false;
1156411569 },
11565 .struct_type => |s| s,
11570 .struct_type => ip.loadStructType(ty.toIntern()),
1156611571 else => unreachable,
1156711572 };
1156811573
src/codegen/spirv.zig+9-11
......@@ -1528,7 +1528,7 @@ const DeclGen = struct {
15281528 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
15291529 return ty_ref;
15301530 },
1531 .struct_type => |struct_type| struct_type,
1531 .struct_type => ip.loadStructType(ty.toIntern()),
15321532 else => unreachable,
15331533 };
15341534
......@@ -3633,7 +3633,8 @@ const DeclGen = struct {
36333633 index += 1;
36343634 }
36353635 },
3636 .struct_type => |struct_type| {
3636 .struct_type => {
3637 const struct_type = ip.loadStructType(result_ty.toIntern());
36373638 var it = struct_type.iterateRuntimeOrder(ip);
36383639 for (elements, 0..) |element, i| {
36393640 const field_index = it.next().?;
......@@ -3901,36 +3902,33 @@ const DeclGen = struct {
39013902 const mod = self.module;
39023903 const ip = &mod.intern_pool;
39033904 const union_ty = mod.typeToUnion(ty).?;
3905 const tag_ty = Type.fromInterned(union_ty.enum_tag_ty);
39043906
39053907 if (union_ty.getLayout(ip) == .Packed) {
39063908 unreachable; // TODO
39073909 }
39083910
3909 const maybe_tag_ty = ty.unionTagTypeSafety(mod);
39103911 const layout = self.unionLayout(ty);
39113912
39123913 const tag_int = if (layout.tag_size != 0) blk: {
3913 const tag_ty = maybe_tag_ty.?;
3914 const union_field_name = union_ty.field_names.get(ip)[active_field];
3915 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;
3916 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
3914 const tag_val = try mod.enumValueFieldIndex(tag_ty, active_field);
39173915 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);
39183916 break :blk tag_int_val.toUnsignedInt(mod);
39193917 } else 0;
39203918
39213919 if (!layout.has_payload) {
3922 const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct);
3920 const tag_ty_ref = try self.resolveType(tag_ty, .direct);
39233921 return try self.constInt(tag_ty_ref, tag_int);
39243922 }
39253923
39263924 const tmp_id = try self.alloc(ty, .{ .storage_class = .Function });
39273925
39283926 if (layout.tag_size != 0) {
3929 const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct);
3930 const tag_ptr_ty_ref = try self.ptrType(maybe_tag_ty.?, .Function);
3927 const tag_ty_ref = try self.resolveType(tag_ty, .direct);
3928 const tag_ptr_ty_ref = try self.ptrType(tag_ty, .Function);
39313929 const ptr_id = try self.accessChain(tag_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});
39323930 const tag_id = try self.constInt(tag_ty_ref, tag_int);
3933 try self.store(maybe_tag_ty.?, ptr_id, tag_id, .{});
3931 try self.store(tag_ty, ptr_id, tag_id, .{});
39343932 }
39353933
39363934 const payload_ty = Type.fromInterned(union_ty.field_types.get(ip)[active_field]);
src/glibc.zig+1
......@@ -1118,6 +1118,7 @@ fn buildSharedLib(
11181118 .cc_argv = &.{},
11191119 .parent = null,
11201120 .builtin_mod = null,
1121 .builtin_modules = null, // there is only one module in this compilation
11211122 });
11221123
11231124 const c_source_files = [1]Compilation.CSourceFile{
src/libcxx.zig+2
......@@ -181,6 +181,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) !void {
181181 .cc_argv = &.{},
182182 .parent = null,
183183 .builtin_mod = null,
184 .builtin_modules = null, // there is only one module in this compilation
184185 });
185186
186187 var c_source_files = try std.ArrayList(Compilation.CSourceFile).initCapacity(arena, libcxx_files.len);
......@@ -395,6 +396,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) !void {
395396 .cc_argv = &.{},
396397 .parent = null,
397398 .builtin_mod = null,
399 .builtin_modules = null, // there is only one module in this compilation
398400 });
399401
400402 var c_source_files = try std.ArrayList(Compilation.CSourceFile).initCapacity(arena, libcxxabi_files.len);
src/libtsan.zig+1
......@@ -92,6 +92,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) BuildError!v
9292 .cc_argv = &common_flags,
9393 .parent = null,
9494 .builtin_mod = null,
95 .builtin_modules = null, // there is only one module in this compilation
9596 }) catch |err| {
9697 comp.setMiscFailure(
9798 .libtsan,
src/libunwind.zig+1
......@@ -58,6 +58,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void {
5858 .cc_argv = &.{},
5959 .parent = null,
6060 .builtin_mod = null,
61 .builtin_modules = null, // there is only one module in this compilation
6162 });
6263
6364 const root_name = "unwind";
src/link/Dwarf.zig+4-3
......@@ -311,7 +311,8 @@ pub const DeclState = struct {
311311 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
312312 }
313313 },
314 .struct_type => |struct_type| {
314 .struct_type => {
315 const struct_type = ip.loadStructType(ty.toIntern());
315316 // DW.AT.name, DW.FORM.string
316317 try ty.print(dbg_info_buffer.writer(), mod);
317318 try dbg_info_buffer.append(0);
......@@ -374,7 +375,7 @@ pub const DeclState = struct {
374375 try ty.print(dbg_info_buffer.writer(), mod);
375376 try dbg_info_buffer.append(0);
376377
377 const enum_type = ip.indexToKey(ty.ip_index).enum_type;
378 const enum_type = ip.loadEnumType(ty.ip_index);
378379 for (enum_type.names.get(ip), 0..) |field_name_index, field_i| {
379380 const field_name = ip.stringToSlice(field_name_index);
380381 // DW.AT.enumerator
......@@ -442,7 +443,7 @@ pub const DeclState = struct {
442443 try dbg_info_buffer.append(0);
443444 }
444445
445 for (union_obj.field_types.get(ip), union_obj.field_names.get(ip)) |field_ty, field_name| {
446 for (union_obj.field_types.get(ip), union_obj.loadTagType(ip).names.get(ip)) |field_ty, field_name| {
446447 if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;
447448 // DW.AT.member
448449 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_member));
src/main.zig+15-3
......@@ -2708,7 +2708,9 @@ fn buildOutputType(
27082708 create_module.opts.emit_bin = emit_bin != .no;
27092709 create_module.opts.any_c_source_files = create_module.c_source_files.items.len != 0;
27102710
2711 const main_mod = try createModule(gpa, arena, &create_module, 0, null, zig_lib_directory);
2711 var builtin_modules: std.StringHashMapUnmanaged(*Package.Module) = .{};
2712 // `builtin_modules` allocated into `arena`, so no deinit
2713 const main_mod = try createModule(gpa, arena, &create_module, 0, null, zig_lib_directory, &builtin_modules);
27122714 for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| {
27132715 if (cli_mod.resolved == null)
27142716 fatal("module '{s}' declared but not used", .{key});
......@@ -2753,6 +2755,7 @@ fn buildOutputType(
27532755 .global = create_module.resolved_options,
27542756 .parent = main_mod,
27552757 .builtin_mod = main_mod.getBuiltinDependency(),
2758 .builtin_modules = null, // `builtin_mod` is specified
27562759 });
27572760 test_mod.deps = try main_mod.deps.clone(arena);
27582761 break :test_mod test_mod;
......@@ -2771,6 +2774,7 @@ fn buildOutputType(
27712774 .global = create_module.resolved_options,
27722775 .parent = main_mod,
27732776 .builtin_mod = main_mod.getBuiltinDependency(),
2777 .builtin_modules = null, // `builtin_mod` is specified
27742778 });
27752779
27762780 break :root_mod test_mod;
......@@ -3479,6 +3483,7 @@ fn createModule(
34793483 index: usize,
34803484 parent: ?*Package.Module,
34813485 zig_lib_directory: Cache.Directory,
3486 builtin_modules: *std.StringHashMapUnmanaged(*Package.Module),
34823487) Allocator.Error!*Package.Module {
34833488 const cli_mod = &create_module.modules.values()[index];
34843489 if (cli_mod.resolved) |m| return m;
......@@ -3931,6 +3936,7 @@ fn createModule(
39313936 .global = create_module.resolved_options,
39323937 .parent = parent,
39333938 .builtin_mod = null,
3939 .builtin_modules = builtin_modules,
39343940 }) catch |err| switch (err) {
39353941 error.ValgrindUnsupportedOnTarget => fatal("unable to create module '{s}': valgrind does not support the selected target CPU architecture", .{name}),
39363942 error.TargetRequiresSingleThreaded => fatal("unable to create module '{s}': the selected target does not support multithreading", .{name}),
......@@ -3953,7 +3959,7 @@ fn createModule(
39533959 for (cli_mod.deps) |dep| {
39543960 const dep_index = create_module.modules.getIndex(dep.value) orelse
39553961 fatal("module '{s}' depends on non-existent module '{s}'", .{ name, dep.key });
3956 const dep_mod = try createModule(gpa, arena, create_module, dep_index, mod, zig_lib_directory);
3962 const dep_mod = try createModule(gpa, arena, create_module, dep_index, mod, zig_lib_directory, builtin_modules);
39573963 try mod.deps.put(arena, dep.key, dep_mod);
39583964 }
39593965
......@@ -5249,6 +5255,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
52495255 .global = config,
52505256 .parent = null,
52515257 .builtin_mod = null,
5258 .builtin_modules = null, // all modules will inherit this one's builtin
52525259 });
52535260
52545261 const builtin_mod = root_mod.getBuiltinDependency();
......@@ -5265,6 +5272,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
52655272 .global = config,
52665273 .parent = root_mod,
52675274 .builtin_mod = builtin_mod,
5275 .builtin_modules = null, // `builtin_mod` is specified
52685276 });
52695277
52705278 var cleanup_build_dir: ?fs.Dir = null;
......@@ -5399,6 +5407,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
53995407 .global = config,
54005408 .parent = root_mod,
54015409 .builtin_mod = builtin_mod,
5410 .builtin_modules = null, // `builtin_mod` is specified
54025411 });
54035412 const hash_cloned = try arena.dupe(u8, &hash);
54045413 deps_mod.deps.putAssumeCapacityNoClobber(hash_cloned, m);
......@@ -5648,6 +5657,7 @@ fn jitCmd(
56485657 .global = config,
56495658 .parent = null,
56505659 .builtin_mod = null,
5660 .builtin_modules = null, // all modules will inherit this one's builtin
56515661 });
56525662
56535663 if (options.depend_on_aro) {
......@@ -5670,6 +5680,7 @@ fn jitCmd(
56705680 .global = config,
56715681 .parent = null,
56725682 .builtin_mod = root_mod.getBuiltinDependency(),
5683 .builtin_modules = null, // `builtin_mod` is specified
56735684 });
56745685 try root_mod.deps.put(arena, "aro", aro_mod);
56755686 }
......@@ -7216,10 +7227,11 @@ fn createDependenciesModule(
72167227 },
72177228 .fully_qualified_name = "root.@dependencies",
72187229 .parent = main_mod,
7219 .builtin_mod = builtin_mod,
72207230 .cc_argv = &.{},
72217231 .inherited = .{},
72227232 .global = global_options,
7233 .builtin_mod = builtin_mod,
7234 .builtin_modules = null, // `builtin_mod` is specified
72237235 });
72247236 try main_mod.deps.put(arena, "@dependencies", deps_mod);
72257237 return deps_mod;
src/musl.zig+1
......@@ -250,6 +250,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr
250250 .cc_argv = cc_argv,
251251 .parent = null,
252252 .builtin_mod = null,
253 .builtin_modules = null, // there is only one module in this compilation
253254 });
254255
255256 const sub_compilation = try Compilation.create(comp.gpa, arena, .{
src/print_zir.zig+102-5
......@@ -282,7 +282,6 @@ const Writer = struct {
282282
283283 .ref,
284284 .ret_implicit,
285 .closure_capture,
286285 .validate_ref_ty,
287286 => try self.writeUnTok(stream, inst),
288287
......@@ -510,8 +509,6 @@ const Writer = struct {
510509
511510 .dbg_stmt => try self.writeDbgStmt(stream, inst),
512511
513 .closure_get => try self.writeInstNode(stream, inst),
514
515512 .@"defer" => try self.writeDefer(stream, inst),
516513 .defer_err_code => try self.writeDeferErrCode(stream, inst),
517514
......@@ -611,6 +608,7 @@ const Writer = struct {
611608 .ptr_cast_no_dest => try self.writePtrCastNoDest(stream, extended),
612609
613610 .restore_err_ret_index => try self.writeRestoreErrRetIndex(stream, extended),
611 .closure_get => try self.writeClosureGet(stream, extended),
614612 }
615613 }
616614
......@@ -1401,6 +1399,12 @@ const Writer = struct {
14011399
14021400 var extra_index: usize = extra.end;
14031401
1402 const captures_len = if (small.has_captures_len) blk: {
1403 const captures_len = self.code.extra[extra_index];
1404 extra_index += 1;
1405 break :blk captures_len;
1406 } else 0;
1407
14041408 const fields_len = if (small.has_fields_len) blk: {
14051409 const fields_len = self.code.extra[extra_index];
14061410 extra_index += 1;
......@@ -1419,12 +1423,26 @@ const Writer = struct {
14191423
14201424 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
14211425
1422 if (small.layout == .Packed and small.has_backing_int) {
1426 if (captures_len == 0) {
1427 try stream.writeAll("{}, ");
1428 } else {
1429 try stream.writeAll("{ ");
1430 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1431 extra_index += 1;
1432 for (1..captures_len) |_| {
1433 try stream.writeAll(", ");
1434 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1435 extra_index += 1;
1436 }
1437 try stream.writeAll(" }, ");
1438 }
1439
1440 if (small.has_backing_int) {
14231441 const backing_int_body_len = self.code.extra[extra_index];
14241442 extra_index += 1;
14251443 try stream.writeAll("Packed(");
14261444 if (backing_int_body_len == 0) {
1427 const backing_int_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1445 const backing_int_ref: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
14281446 extra_index += 1;
14291447 try self.writeInstRef(stream, backing_int_ref);
14301448 } else {
......@@ -1601,6 +1619,12 @@ const Writer = struct {
16011619 break :blk tag_type_ref;
16021620 } else .none;
16031621
1622 const captures_len = if (small.has_captures_len) blk: {
1623 const captures_len = self.code.extra[extra_index];
1624 extra_index += 1;
1625 break :blk captures_len;
1626 } else 0;
1627
16041628 const body_len = if (small.has_body_len) blk: {
16051629 const body_len = self.code.extra[extra_index];
16061630 extra_index += 1;
......@@ -1624,6 +1648,20 @@ const Writer = struct {
16241648 });
16251649 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
16261650
1651 if (captures_len == 0) {
1652 try stream.writeAll("{}, ");
1653 } else {
1654 try stream.writeAll("{ ");
1655 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1656 extra_index += 1;
1657 for (1..captures_len) |_| {
1658 try stream.writeAll(", ");
1659 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1660 extra_index += 1;
1661 }
1662 try stream.writeAll(" }, ");
1663 }
1664
16271665 if (decls_len == 0) {
16281666 try stream.writeAll("{}");
16291667 } else {
......@@ -1748,6 +1786,12 @@ const Writer = struct {
17481786 break :blk tag_type_ref;
17491787 } else .none;
17501788
1789 const captures_len = if (small.has_captures_len) blk: {
1790 const captures_len = self.code.extra[extra_index];
1791 extra_index += 1;
1792 break :blk captures_len;
1793 } else 0;
1794
17511795 const body_len = if (small.has_body_len) blk: {
17521796 const body_len = self.code.extra[extra_index];
17531797 extra_index += 1;
......@@ -1769,6 +1813,20 @@ const Writer = struct {
17691813 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
17701814 try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive);
17711815
1816 if (captures_len == 0) {
1817 try stream.writeAll("{}, ");
1818 } else {
1819 try stream.writeAll("{ ");
1820 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1821 extra_index += 1;
1822 for (1..captures_len) |_| {
1823 try stream.writeAll(", ");
1824 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1825 extra_index += 1;
1826 }
1827 try stream.writeAll(" }, ");
1828 }
1829
17721830 if (decls_len == 0) {
17731831 try stream.writeAll("{}, ");
17741832 } else {
......@@ -1854,6 +1912,12 @@ const Writer = struct {
18541912 const extra = self.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
18551913 var extra_index: usize = extra.end;
18561914
1915 const captures_len = if (small.has_captures_len) blk: {
1916 const captures_len = self.code.extra[extra_index];
1917 extra_index += 1;
1918 break :blk captures_len;
1919 } else 0;
1920
18571921 const decls_len = if (small.has_decls_len) blk: {
18581922 const decls_len = self.code.extra[extra_index];
18591923 extra_index += 1;
......@@ -1862,6 +1926,20 @@ const Writer = struct {
18621926
18631927 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
18641928
1929 if (captures_len == 0) {
1930 try stream.writeAll("{}, ");
1931 } else {
1932 try stream.writeAll("{ ");
1933 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1934 extra_index += 1;
1935 for (1..captures_len) |_| {
1936 try stream.writeAll(", ");
1937 try self.writeCapture(stream, @bitCast(self.code.extra[extra_index]));
1938 extra_index += 1;
1939 }
1940 try stream.writeAll(" }, ");
1941 }
1942
18651943 if (decls_len == 0) {
18661944 try stream.writeAll("{})");
18671945 } else {
......@@ -2706,6 +2784,12 @@ const Writer = struct {
27062784 try self.writeSrc(stream, inst_data.src());
27072785 }
27082786
2787 fn writeClosureGet(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
2788 const src = LazySrcLoc.nodeOffset(@bitCast(extended.operand));
2789 try stream.print("{d})) ", .{extended.small});
2790 try self.writeSrc(stream, src);
2791 }
2792
27092793 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {
27102794 if (ref == .none) {
27112795 return stream.writeAll(".none");
......@@ -2722,6 +2806,19 @@ const Writer = struct {
27222806 return stream.print("%{d}", .{@intFromEnum(inst)});
27232807 }
27242808
2809 fn writeCapture(self: *Writer, stream: anytype, capture: Zir.Inst.Capture) !void {
2810 switch (capture.unwrap()) {
2811 .nested => |i| return stream.print("[{d}]", .{i}),
2812 .instruction => |inst| return self.writeInstIndex(stream, inst),
2813 .decl_val => |str| try stream.print("decl_val \"{}\"", .{
2814 std.zig.fmtEscapes(self.code.nullTerminatedString(str)),
2815 }),
2816 .decl_ref => |str| try stream.print("decl_ref \"{}\"", .{
2817 std.zig.fmtEscapes(self.code.nullTerminatedString(str)),
2818 }),
2819 }
2820 }
2821
27252822 fn writeOptionalInstRef(
27262823 self: *Writer,
27272824 stream: anytype,
src/type.zig+204-178
......@@ -320,11 +320,12 @@ pub const Type = struct {
320320
321321 .generic_poison => unreachable,
322322 },
323 .struct_type => |struct_type| {
323 .struct_type => {
324 const struct_type = ip.loadStructType(ty.toIntern());
324325 if (struct_type.decl.unwrap()) |decl_index| {
325326 const decl = mod.declPtr(decl_index);
326327 try decl.renderFullyQualifiedName(mod, writer);
327 } else if (struct_type.namespace.unwrap()) |namespace_index| {
328 } else if (ip.loadStructType(ty.toIntern()).namespace.unwrap()) |namespace_index| {
328329 const namespace = mod.namespacePtr(namespace_index);
329330 try namespace.renderFullyQualifiedName(mod, .empty, writer);
330331 } else {
......@@ -354,16 +355,16 @@ pub const Type = struct {
354355 try writer.writeAll("}");
355356 },
356357
357 .union_type => |union_type| {
358 const decl = mod.declPtr(union_type.decl);
358 .union_type => {
359 const decl = mod.declPtr(ip.loadUnionType(ty.toIntern()).decl);
359360 try decl.renderFullyQualifiedName(mod, writer);
360361 },
361 .opaque_type => |opaque_type| {
362 const decl = mod.declPtr(opaque_type.decl);
362 .opaque_type => {
363 const decl = mod.declPtr(ip.loadOpaqueType(ty.toIntern()).decl);
363364 try decl.renderFullyQualifiedName(mod, writer);
364365 },
365 .enum_type => |enum_type| {
366 const decl = mod.declPtr(enum_type.decl);
366 .enum_type => {
367 const decl = mod.declPtr(ip.loadEnumType(ty.toIntern()).decl);
367368 try decl.renderFullyQualifiedName(mod, writer);
368369 },
369370 .func_type => |fn_info| {
......@@ -573,7 +574,8 @@ pub const Type = struct {
573574
574575 .generic_poison => unreachable,
575576 },
576 .struct_type => |struct_type| {
577 .struct_type => {
578 const struct_type = ip.loadStructType(ty.toIntern());
577579 if (struct_type.assumeRuntimeBitsIfFieldTypesWip(ip)) {
578580 // In this case, we guess that hasRuntimeBits() for this type is true,
579581 // and then later if our guess was incorrect, we emit a compile error.
......@@ -601,7 +603,8 @@ pub const Type = struct {
601603 return false;
602604 },
603605
604 .union_type => |union_type| {
606 .union_type => {
607 const union_type = ip.loadUnionType(ty.toIntern());
605608 switch (union_type.flagsPtr(ip).runtime_tag) {
606609 .none => {
607610 if (union_type.flagsPtr(ip).status == .field_types_wip) {
......@@ -628,9 +631,8 @@ pub const Type = struct {
628631 .lazy => if (!union_type.flagsPtr(ip).status.haveFieldTypes())
629632 return error.NeedLazy,
630633 }
631 const union_obj = ip.loadUnionType(union_type);
632 for (0..union_obj.field_types.len) |field_index| {
633 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
634 for (0..union_type.field_types.len) |field_index| {
635 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
634636 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
635637 return true;
636638 } else {
......@@ -639,7 +641,7 @@ pub const Type = struct {
639641 },
640642
641643 .opaque_type => true,
642 .enum_type => |enum_type| Type.fromInterned(enum_type.tag_ty).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
644 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
643645
644646 // values, not types
645647 .undef,
......@@ -736,15 +738,19 @@ pub const Type = struct {
736738 .generic_poison,
737739 => false,
738740 },
739 .struct_type => |struct_type| {
741 .struct_type => {
742 const struct_type = ip.loadStructType(ty.toIntern());
740743 // Struct with no fields have a well-defined layout of no bits.
741744 return struct_type.layout != .Auto or struct_type.field_types.len == 0;
742745 },
743 .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) {
744 .none, .safety => union_type.flagsPtr(ip).layout != .Auto,
745 .tagged => false,
746 .union_type => {
747 const union_type = ip.loadUnionType(ty.toIntern());
748 return switch (union_type.flagsPtr(ip).runtime_tag) {
749 .none, .safety => union_type.flagsPtr(ip).layout != .Auto,
750 .tagged => false,
751 };
746752 },
747 .enum_type => |enum_type| switch (enum_type.tag_mode) {
753 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
748754 .auto => false,
749755 .explicit, .nonexhaustive => true,
750756 },
......@@ -1019,7 +1025,8 @@ pub const Type = struct {
10191025 .noreturn => unreachable,
10201026 .generic_poison => unreachable,
10211027 },
1022 .struct_type => |struct_type| {
1028 .struct_type => {
1029 const struct_type = ip.loadStructType(ty.toIntern());
10231030 if (struct_type.layout == .Packed) {
10241031 switch (strat) {
10251032 .sema => |sema| try sema.resolveTypeLayout(ty),
......@@ -1066,7 +1073,8 @@ pub const Type = struct {
10661073 }
10671074 return .{ .scalar = big_align };
10681075 },
1069 .union_type => |union_type| {
1076 .union_type => {
1077 const union_type = ip.loadUnionType(ty.toIntern());
10701078 const flags = union_type.flagsPtr(ip).*;
10711079 if (flags.alignment != .none) return .{ .scalar = flags.alignment };
10721080
......@@ -1082,8 +1090,8 @@ pub const Type = struct {
10821090 return .{ .scalar = union_type.flagsPtr(ip).alignment };
10831091 },
10841092 .opaque_type => return .{ .scalar = .@"1" },
1085 .enum_type => |enum_type| return .{
1086 .scalar = Type.fromInterned(enum_type.tag_ty).abiAlignment(mod),
1093 .enum_type => return .{
1094 .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiAlignment(mod),
10871095 },
10881096
10891097 // values, not types
......@@ -1394,7 +1402,8 @@ pub const Type = struct {
13941402 .noreturn => unreachable,
13951403 .generic_poison => unreachable,
13961404 },
1397 .struct_type => |struct_type| {
1405 .struct_type => {
1406 const struct_type = ip.loadStructType(ty.toIntern());
13981407 switch (strat) {
13991408 .sema => |sema| try sema.resolveTypeLayout(ty),
14001409 .lazy => switch (struct_type.layout) {
......@@ -1439,7 +1448,8 @@ pub const Type = struct {
14391448 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };
14401449 },
14411450
1442 .union_type => |union_type| {
1451 .union_type => {
1452 const union_type = ip.loadUnionType(ty.toIntern());
14431453 switch (strat) {
14441454 .sema => |sema| try sema.resolveTypeLayout(ty),
14451455 .lazy => if (!union_type.flagsPtr(ip).status.haveLayout()) return .{
......@@ -1455,7 +1465,7 @@ pub const Type = struct {
14551465 return .{ .scalar = union_type.size(ip).* };
14561466 },
14571467 .opaque_type => unreachable, // no size available
1458 .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = Type.fromInterned(enum_type.tag_ty).abiSize(mod) },
1468 .enum_type => return .{ .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiSize(mod) },
14591469
14601470 // values, not types
14611471 .undef,
......@@ -1644,7 +1654,8 @@ pub const Type = struct {
16441654 .extern_options => unreachable,
16451655 .type_info => unreachable,
16461656 },
1647 .struct_type => |struct_type| {
1657 .struct_type => {
1658 const struct_type = ip.loadStructType(ty.toIntern());
16481659 const is_packed = struct_type.layout == .Packed;
16491660 if (opt_sema) |sema| {
16501661 try sema.resolveTypeFields(ty);
......@@ -1661,7 +1672,8 @@ pub const Type = struct {
16611672 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
16621673 },
16631674
1664 .union_type => |union_type| {
1675 .union_type => {
1676 const union_type = ip.loadUnionType(ty.toIntern());
16651677 const is_packed = ty.containerLayout(mod) == .Packed;
16661678 if (opt_sema) |sema| {
16671679 try sema.resolveTypeFields(ty);
......@@ -1670,19 +1682,18 @@ pub const Type = struct {
16701682 if (!is_packed) {
16711683 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
16721684 }
1673 const union_obj = ip.loadUnionType(union_type);
1674 assert(union_obj.flagsPtr(ip).status.haveFieldTypes());
1685 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
16751686
16761687 var size: u64 = 0;
1677 for (0..union_obj.field_types.len) |field_index| {
1678 const field_ty = union_obj.field_types.get(ip)[field_index];
1688 for (0..union_type.field_types.len) |field_index| {
1689 const field_ty = union_type.field_types.get(ip)[field_index];
16791690 size = @max(size, try bitSizeAdvanced(Type.fromInterned(field_ty), mod, opt_sema));
16801691 }
16811692
16821693 return size;
16831694 },
16841695 .opaque_type => unreachable,
1685 .enum_type => |enum_type| return bitSizeAdvanced(Type.fromInterned(enum_type.tag_ty), mod, opt_sema),
1696 .enum_type => return bitSizeAdvanced(Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty), mod, opt_sema),
16861697
16871698 // values, not types
16881699 .undef,
......@@ -1713,8 +1724,8 @@ pub const Type = struct {
17131724 pub fn layoutIsResolved(ty: Type, mod: *Module) bool {
17141725 const ip = &mod.intern_pool;
17151726 return switch (ip.indexToKey(ty.toIntern())) {
1716 .struct_type => |struct_type| struct_type.haveLayout(ip),
1717 .union_type => |union_type| union_type.haveLayout(ip),
1727 .struct_type => ip.loadStructType(ty.toIntern()).haveLayout(ip),
1728 .union_type => ip.loadUnionType(ty.toIntern()).haveLayout(ip),
17181729 .array_type => |array_type| {
17191730 if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true;
17201731 return Type.fromInterned(array_type.child).layoutIsResolved(mod);
......@@ -1914,16 +1925,18 @@ pub const Type = struct {
19141925 /// Otherwise, returns `null`.
19151926 pub fn unionTagType(ty: Type, mod: *Module) ?Type {
19161927 const ip = &mod.intern_pool;
1917 return switch (ip.indexToKey(ty.toIntern())) {
1918 .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) {
1919 .tagged => {
1920 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
1921 return Type.fromInterned(union_type.enum_tag_ty);
1922 },
1923 else => null,
1928 switch (ip.indexToKey(ty.toIntern())) {
1929 .union_type => {},
1930 else => return null,
1931 }
1932 const union_type = ip.loadUnionType(ty.toIntern());
1933 switch (union_type.flagsPtr(ip).runtime_tag) {
1934 .tagged => {
1935 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
1936 return Type.fromInterned(union_type.enum_tag_ty);
19241937 },
1925 else => null,
1926 };
1938 else => return null,
1939 }
19271940 }
19281941
19291942 /// Same as `unionTagType` but includes safety tag.
......@@ -1931,7 +1944,8 @@ pub const Type = struct {
19311944 pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type {
19321945 const ip = &mod.intern_pool;
19331946 return switch (ip.indexToKey(ty.toIntern())) {
1934 .union_type => |union_type| {
1947 .union_type => {
1948 const union_type = ip.loadUnionType(ty.toIntern());
19351949 if (!union_type.hasTag(ip)) return null;
19361950 assert(union_type.haveFieldTypes(ip));
19371951 return Type.fromInterned(union_type.enum_tag_ty);
......@@ -1981,17 +1995,16 @@ pub const Type = struct {
19811995
19821996 pub fn unionGetLayout(ty: Type, mod: *Module) Module.UnionLayout {
19831997 const ip = &mod.intern_pool;
1984 const union_type = ip.indexToKey(ty.toIntern()).union_type;
1985 const union_obj = ip.loadUnionType(union_type);
1998 const union_obj = ip.loadUnionType(ty.toIntern());
19861999 return mod.getUnionLayout(union_obj);
19872000 }
19882001
19892002 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
19902003 const ip = &mod.intern_pool;
19912004 return switch (ip.indexToKey(ty.toIntern())) {
1992 .struct_type => |struct_type| struct_type.layout,
2005 .struct_type => ip.loadStructType(ty.toIntern()).layout,
19932006 .anon_struct_type => .Auto,
1994 .union_type => |union_type| union_type.flagsPtr(ip).layout,
2007 .union_type => ip.loadUnionType(ty.toIntern()).flagsPtr(ip).layout,
19952008 else => unreachable,
19962009 };
19972010 }
......@@ -2095,22 +2108,15 @@ pub const Type = struct {
20952108
20962109 /// Asserts the type is an array or vector or struct.
20972110 pub fn arrayLen(ty: Type, mod: *const Module) u64 {
2098 return arrayLenIp(ty, &mod.intern_pool);
2111 return ty.arrayLenIp(&mod.intern_pool);
20992112 }
21002113
21012114 pub fn arrayLenIp(ty: Type, ip: *const InternPool) u64 {
2102 return switch (ip.indexToKey(ty.toIntern())) {
2103 .vector_type => |vector_type| vector_type.len,
2104 .array_type => |array_type| array_type.len,
2105 .struct_type => |struct_type| struct_type.field_types.len,
2106 .anon_struct_type => |tuple| tuple.types.len,
2107
2108 else => unreachable,
2109 };
2115 return ip.aggregateTypeLen(ty.toIntern());
21102116 }
21112117
21122118 pub fn arrayLenIncludingSentinel(ty: Type, mod: *const Module) u64 {
2113 return ty.arrayLen(mod) + @intFromBool(ty.sentinel(mod) != null);
2119 return mod.intern_pool.aggregateTypeLenIncludingSentinel(ty.toIntern());
21142120 }
21152121
21162122 pub fn vectorLen(ty: Type, mod: *const Module) u32 {
......@@ -2199,8 +2205,8 @@ pub const Type = struct {
21992205 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) },
22002206 else => switch (ip.indexToKey(ty.toIntern())) {
22012207 .int_type => |int_type| return int_type,
2202 .struct_type => |t| ty = Type.fromInterned(t.backingIntType(ip).*),
2203 .enum_type => |enum_type| ty = Type.fromInterned(enum_type.tag_ty),
2208 .struct_type => ty = Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntType(ip).*),
2209 .enum_type => ty = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),
22042210 .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child),
22052211
22062212 .error_set_type, .inferred_error_set_type => {
......@@ -2463,7 +2469,8 @@ pub const Type = struct {
24632469
24642470 .generic_poison => unreachable,
24652471 },
2466 .struct_type => |struct_type| {
2472 .struct_type => {
2473 const struct_type = ip.loadStructType(ty.toIntern());
24672474 assert(struct_type.haveFieldTypes(ip));
24682475 if (struct_type.knownNonOpv(ip))
24692476 return null;
......@@ -2505,11 +2512,11 @@ pub const Type = struct {
25052512 } })));
25062513 },
25072514
2508 .union_type => |union_type| {
2509 const union_obj = ip.loadUnionType(union_type);
2515 .union_type => {
2516 const union_obj = ip.loadUnionType(ty.toIntern());
25102517 const tag_val = (try Type.fromInterned(union_obj.enum_tag_ty).onePossibleValue(mod)) orelse
25112518 return null;
2512 if (union_obj.field_names.len == 0) {
2519 if (union_obj.field_types.len == 0) {
25132520 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
25142521 return Value.fromInterned(only);
25152522 }
......@@ -2524,45 +2531,48 @@ pub const Type = struct {
25242531 return Value.fromInterned(only);
25252532 },
25262533 .opaque_type => return null,
2527 .enum_type => |enum_type| switch (enum_type.tag_mode) {
2528 .nonexhaustive => {
2529 if (enum_type.tag_ty == .comptime_int_type) return null;
2530
2531 if (try Type.fromInterned(enum_type.tag_ty).onePossibleValue(mod)) |int_opv| {
2532 const only = try mod.intern(.{ .enum_tag = .{
2533 .ty = ty.toIntern(),
2534 .int = int_opv.toIntern(),
2535 } });
2536 return Value.fromInterned(only);
2537 }
2534 .enum_type => {
2535 const enum_type = ip.loadEnumType(ty.toIntern());
2536 switch (enum_type.tag_mode) {
2537 .nonexhaustive => {
2538 if (enum_type.tag_ty == .comptime_int_type) return null;
2539
2540 if (try Type.fromInterned(enum_type.tag_ty).onePossibleValue(mod)) |int_opv| {
2541 const only = try mod.intern(.{ .enum_tag = .{
2542 .ty = ty.toIntern(),
2543 .int = int_opv.toIntern(),
2544 } });
2545 return Value.fromInterned(only);
2546 }
25382547
2539 return null;
2540 },
2541 .auto, .explicit => {
2542 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;
2548 return null;
2549 },
2550 .auto, .explicit => {
2551 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;
25432552
2544 switch (enum_type.names.len) {
2545 0 => {
2546 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
2547 return Value.fromInterned(only);
2548 },
2549 1 => {
2550 if (enum_type.values.len == 0) {
2551 const only = try mod.intern(.{ .enum_tag = .{
2552 .ty = ty.toIntern(),
2553 .int = try mod.intern(.{ .int = .{
2554 .ty = enum_type.tag_ty,
2555 .storage = .{ .u64 = 0 },
2556 } }),
2557 } });
2553 switch (enum_type.names.len) {
2554 0 => {
2555 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
25582556 return Value.fromInterned(only);
2559 } else {
2560 return Value.fromInterned(enum_type.values.get(ip)[0]);
2561 }
2562 },
2563 else => return null,
2564 }
2565 },
2557 },
2558 1 => {
2559 if (enum_type.values.len == 0) {
2560 const only = try mod.intern(.{ .enum_tag = .{
2561 .ty = ty.toIntern(),
2562 .int = try mod.intern(.{ .int = .{
2563 .ty = enum_type.tag_ty,
2564 .storage = .{ .u64 = 0 },
2565 } }),
2566 } });
2567 return Value.fromInterned(only);
2568 } else {
2569 return Value.fromInterned(enum_type.values.get(ip)[0]);
2570 }
2571 },
2572 else => return null,
2573 }
2574 },
2575 }
25662576 },
25672577
25682578 // values, not types
......@@ -2676,7 +2686,8 @@ pub const Type = struct {
26762686 .type_info,
26772687 => true,
26782688 },
2679 .struct_type => |struct_type| {
2689 .struct_type => {
2690 const struct_type = ip.loadStructType(ty.toIntern());
26802691 // packed structs cannot be comptime-only because they have a well-defined
26812692 // memory layout and every field has a well-defined bit pattern.
26822693 if (struct_type.layout == .Packed)
......@@ -2726,38 +2737,40 @@ pub const Type = struct {
27262737 return false;
27272738 },
27282739
2729 .union_type => |union_type| switch (union_type.flagsPtr(ip).requires_comptime) {
2730 .no, .wip => false,
2731 .yes => true,
2732 .unknown => {
2733 // The type is not resolved; assert that we have a Sema.
2734 const sema = opt_sema.?;
2740 .union_type => {
2741 const union_type = ip.loadUnionType(ty.toIntern());
2742 switch (union_type.flagsPtr(ip).requires_comptime) {
2743 .no, .wip => return false,
2744 .yes => return true,
2745 .unknown => {
2746 // The type is not resolved; assert that we have a Sema.
2747 const sema = opt_sema.?;
27352748
2736 if (union_type.flagsPtr(ip).status == .field_types_wip)
2737 return false;
2749 if (union_type.flagsPtr(ip).status == .field_types_wip)
2750 return false;
27382751
2739 union_type.flagsPtr(ip).requires_comptime = .wip;
2740 errdefer union_type.flagsPtr(ip).requires_comptime = .unknown;
2752 union_type.flagsPtr(ip).requires_comptime = .wip;
2753 errdefer union_type.flagsPtr(ip).requires_comptime = .unknown;
27412754
2742 try sema.resolveTypeFieldsUnion(ty, union_type);
2755 try sema.resolveTypeFieldsUnion(ty, union_type);
27432756
2744 const union_obj = ip.loadUnionType(union_type);
2745 for (0..union_obj.field_types.len) |field_idx| {
2746 const field_ty = union_obj.field_types.get(ip)[field_idx];
2747 if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) {
2748 union_obj.flagsPtr(ip).requires_comptime = .yes;
2749 return true;
2757 for (0..union_type.field_types.len) |field_idx| {
2758 const field_ty = union_type.field_types.get(ip)[field_idx];
2759 if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) {
2760 union_type.flagsPtr(ip).requires_comptime = .yes;
2761 return true;
2762 }
27502763 }
2751 }
27522764
2753 union_obj.flagsPtr(ip).requires_comptime = .no;
2754 return false;
2755 },
2765 union_type.flagsPtr(ip).requires_comptime = .no;
2766 return false;
2767 },
2768 }
27562769 },
27572770
27582771 .opaque_type => false,
27592772
2760 .enum_type => |enum_type| return Type.fromInterned(enum_type.tag_ty).comptimeOnlyAdvanced(mod, opt_sema),
2773 .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).comptimeOnlyAdvanced(mod, opt_sema),
27612774
27622775 // values, not types
27632776 .undef,
......@@ -2830,11 +2843,12 @@ pub const Type = struct {
28302843
28312844 /// Returns null if the type has no namespace.
28322845 pub fn getNamespaceIndex(ty: Type, mod: *Module) InternPool.OptionalNamespaceIndex {
2833 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2834 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
2835 .struct_type => |struct_type| struct_type.namespace,
2836 .union_type => |union_type| union_type.namespace.toOptional(),
2837 .enum_type => |enum_type| enum_type.namespace,
2846 const ip = &mod.intern_pool;
2847 return switch (ip.indexToKey(ty.toIntern())) {
2848 .opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace,
2849 .struct_type => ip.loadStructType(ty.toIntern()).namespace,
2850 .union_type => ip.loadUnionType(ty.toIntern()).namespace,
2851 .enum_type => ip.loadEnumType(ty.toIntern()).namespace,
28382852
28392853 else => .none,
28402854 };
......@@ -2920,16 +2934,18 @@ pub const Type = struct {
29202934
29212935 /// Asserts the type is an enum or a union.
29222936 pub fn intTagType(ty: Type, mod: *Module) Type {
2923 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2924 .union_type => |union_type| Type.fromInterned(union_type.enum_tag_ty).intTagType(mod),
2925 .enum_type => |enum_type| Type.fromInterned(enum_type.tag_ty),
2937 const ip = &mod.intern_pool;
2938 return switch (ip.indexToKey(ty.toIntern())) {
2939 .union_type => Type.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_ty).intTagType(mod),
2940 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),
29262941 else => unreachable,
29272942 };
29282943 }
29292944
29302945 pub fn isNonexhaustiveEnum(ty: Type, mod: *Module) bool {
2931 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2932 .enum_type => |enum_type| switch (enum_type.tag_mode) {
2946 const ip = &mod.intern_pool;
2947 return switch (ip.indexToKey(ty.toIntern())) {
2948 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
29332949 .nonexhaustive => true,
29342950 .auto, .explicit => false,
29352951 },
......@@ -2953,21 +2969,21 @@ pub const Type = struct {
29532969 }
29542970
29552971 pub fn enumFields(ty: Type, mod: *Module) InternPool.NullTerminatedString.Slice {
2956 return mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names;
2972 return mod.intern_pool.loadEnumType(ty.toIntern()).names;
29572973 }
29582974
29592975 pub fn enumFieldCount(ty: Type, mod: *Module) usize {
2960 return mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names.len;
2976 return mod.intern_pool.loadEnumType(ty.toIntern()).names.len;
29612977 }
29622978
29632979 pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString {
29642980 const ip = &mod.intern_pool;
2965 return ip.indexToKey(ty.toIntern()).enum_type.names.get(ip)[field_index];
2981 return ip.loadEnumType(ty.toIntern()).names.get(ip)[field_index];
29662982 }
29672983
29682984 pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, mod: *Module) ?u32 {
29692985 const ip = &mod.intern_pool;
2970 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
2986 const enum_type = ip.loadEnumType(ty.toIntern());
29712987 return enum_type.nameIndex(ip, field_name);
29722988 }
29732989
......@@ -2976,7 +2992,7 @@ pub const Type = struct {
29762992 /// declaration order, or `null` if `enum_tag` does not match any field.
29772993 pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
29782994 const ip = &mod.intern_pool;
2979 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
2995 const enum_type = ip.loadEnumType(ty.toIntern());
29802996 const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) {
29812997 .int => enum_tag.toIntern(),
29822998 .enum_tag => |info| info.int,
......@@ -2990,7 +3006,7 @@ pub const Type = struct {
29903006 pub fn structFieldName(ty: Type, field_index: u32, mod: *Module) InternPool.OptionalNullTerminatedString {
29913007 const ip = &mod.intern_pool;
29923008 return switch (ip.indexToKey(ty.toIntern())) {
2993 .struct_type => |struct_type| struct_type.fieldName(ip, field_index),
3009 .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, field_index),
29943010 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, field_index),
29953011 else => unreachable,
29963012 };
......@@ -3010,7 +3026,7 @@ pub const Type = struct {
30103026 pub fn structFieldCount(ty: Type, mod: *Module) u32 {
30113027 const ip = &mod.intern_pool;
30123028 return switch (ip.indexToKey(ty.toIntern())) {
3013 .struct_type => |struct_type| struct_type.field_types.len,
3029 .struct_type => ip.loadStructType(ty.toIntern()).field_types.len,
30143030 .anon_struct_type => |anon_struct| anon_struct.types.len,
30153031 else => unreachable,
30163032 };
......@@ -3020,9 +3036,9 @@ pub const Type = struct {
30203036 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
30213037 const ip = &mod.intern_pool;
30223038 return switch (ip.indexToKey(ty.toIntern())) {
3023 .struct_type => |struct_type| Type.fromInterned(struct_type.field_types.get(ip)[index]),
3024 .union_type => |union_type| {
3025 const union_obj = ip.loadUnionType(union_type);
3039 .struct_type => Type.fromInterned(ip.loadStructType(ty.toIntern()).field_types.get(ip)[index]),
3040 .union_type => {
3041 const union_obj = ip.loadUnionType(ty.toIntern());
30263042 return Type.fromInterned(union_obj.field_types.get(ip)[index]);
30273043 },
30283044 .anon_struct_type => |anon_struct| Type.fromInterned(anon_struct.types.get(ip)[index]),
......@@ -3033,7 +3049,8 @@ pub const Type = struct {
30333049 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) Alignment {
30343050 const ip = &mod.intern_pool;
30353051 switch (ip.indexToKey(ty.toIntern())) {
3036 .struct_type => |struct_type| {
3052 .struct_type => {
3053 const struct_type = ip.loadStructType(ty.toIntern());
30373054 assert(struct_type.layout != .Packed);
30383055 const explicit_align = struct_type.fieldAlign(ip, index);
30393056 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);
......@@ -3042,8 +3059,8 @@ pub const Type = struct {
30423059 .anon_struct_type => |anon_struct| {
30433060 return Type.fromInterned(anon_struct.types.get(ip)[index]).abiAlignment(mod);
30443061 },
3045 .union_type => |union_type| {
3046 const union_obj = ip.loadUnionType(union_type);
3062 .union_type => {
3063 const union_obj = ip.loadUnionType(ty.toIntern());
30473064 return mod.unionFieldNormalAlignment(union_obj, @intCast(index));
30483065 },
30493066 else => unreachable,
......@@ -3053,7 +3070,8 @@ pub const Type = struct {
30533070 pub fn structFieldDefaultValue(ty: Type, index: usize, mod: *Module) Value {
30543071 const ip = &mod.intern_pool;
30553072 switch (ip.indexToKey(ty.toIntern())) {
3056 .struct_type => |struct_type| {
3073 .struct_type => {
3074 const struct_type = ip.loadStructType(ty.toIntern());
30573075 const val = struct_type.fieldInit(ip, index);
30583076 // TODO: avoid using `unreachable` to indicate this.
30593077 if (val == .none) return Value.@"unreachable";
......@@ -3072,7 +3090,8 @@ pub const Type = struct {
30723090 pub fn structFieldValueComptime(ty: Type, mod: *Module, index: usize) !?Value {
30733091 const ip = &mod.intern_pool;
30743092 switch (ip.indexToKey(ty.toIntern())) {
3075 .struct_type => |struct_type| {
3093 .struct_type => {
3094 const struct_type = ip.loadStructType(ty.toIntern());
30763095 if (struct_type.fieldIsComptime(ip, index)) {
30773096 assert(struct_type.haveFieldInits(ip));
30783097 return Value.fromInterned(struct_type.field_inits.get(ip)[index]);
......@@ -3095,7 +3114,7 @@ pub const Type = struct {
30953114 pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool {
30963115 const ip = &mod.intern_pool;
30973116 return switch (ip.indexToKey(ty.toIntern())) {
3098 .struct_type => |struct_type| struct_type.fieldIsComptime(ip, index),
3117 .struct_type => ip.loadStructType(ty.toIntern()).fieldIsComptime(ip, index),
30993118 .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none,
31003119 else => unreachable,
31013120 };
......@@ -3110,7 +3129,8 @@ pub const Type = struct {
31103129 pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {
31113130 const ip = &mod.intern_pool;
31123131 switch (ip.indexToKey(ty.toIntern())) {
3113 .struct_type => |struct_type| {
3132 .struct_type => {
3133 const struct_type = ip.loadStructType(ty.toIntern());
31143134 assert(struct_type.haveLayout(ip));
31153135 assert(struct_type.layout != .Packed);
31163136 return struct_type.offsets.get(ip)[index];
......@@ -3137,11 +3157,11 @@ pub const Type = struct {
31373157 return offset;
31383158 },
31393159
3140 .union_type => |union_type| {
3160 .union_type => {
3161 const union_type = ip.loadUnionType(ty.toIntern());
31413162 if (!union_type.hasTag(ip))
31423163 return 0;
3143 const union_obj = ip.loadUnionType(union_type);
3144 const layout = mod.getUnionLayout(union_obj);
3164 const layout = mod.getUnionLayout(union_type);
31453165 if (layout.tag_align.compare(.gte, layout.payload_align)) {
31463166 // {Tag, Payload}
31473167 return layout.payload_align.forward(layout.tag_size);
......@@ -3160,17 +3180,8 @@ pub const Type = struct {
31603180 }
31613181
31623182 pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc {
3163 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3164 .struct_type => |struct_type| {
3165 return mod.declPtr(struct_type.decl.unwrap() orelse return null).srcLoc(mod);
3166 },
3167 .union_type => |union_type| {
3168 return mod.declPtr(union_type.decl).srcLoc(mod);
3169 },
3170 .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type),
3171 .enum_type => |enum_type| mod.declPtr(enum_type.decl).srcLoc(mod),
3172 else => null,
3173 };
3183 const decl = ty.getOwnerDeclOrNull(mod) orelse return null;
3184 return mod.declPtr(decl).srcLoc(mod);
31743185 }
31753186
31763187 pub fn getOwnerDecl(ty: Type, mod: *Module) InternPool.DeclIndex {
......@@ -3178,11 +3189,12 @@ pub const Type = struct {
31783189 }
31793190
31803191 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?InternPool.DeclIndex {
3181 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3182 .struct_type => |struct_type| struct_type.decl.unwrap(),
3183 .union_type => |union_type| union_type.decl,
3184 .opaque_type => |opaque_type| opaque_type.decl,
3185 .enum_type => |enum_type| enum_type.decl,
3192 const ip = &mod.intern_pool;
3193 return switch (ip.indexToKey(ty.toIntern())) {
3194 .struct_type => ip.loadStructType(ty.toIntern()).decl.unwrap(),
3195 .union_type => ip.loadUnionType(ty.toIntern()).decl,
3196 .opaque_type => ip.loadOpaqueType(ty.toIntern()).decl,
3197 .enum_type => ip.loadEnumType(ty.toIntern()).decl,
31863198 else => null,
31873199 };
31883200 }
......@@ -3194,7 +3206,8 @@ pub const Type = struct {
31943206 pub fn isTuple(ty: Type, mod: *Module) bool {
31953207 const ip = &mod.intern_pool;
31963208 return switch (ip.indexToKey(ty.toIntern())) {
3197 .struct_type => |struct_type| {
3209 .struct_type => {
3210 const struct_type = ip.loadStructType(ty.toIntern());
31983211 if (struct_type.layout == .Packed) return false;
31993212 if (struct_type.decl == .none) return false;
32003213 return struct_type.flagsPtr(ip).is_tuple;
......@@ -3215,7 +3228,8 @@ pub const Type = struct {
32153228 pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool {
32163229 const ip = &mod.intern_pool;
32173230 return switch (ip.indexToKey(ty.toIntern())) {
3218 .struct_type => |struct_type| {
3231 .struct_type => {
3232 const struct_type = ip.loadStructType(ty.toIntern());
32193233 if (struct_type.layout == .Packed) return false;
32203234 if (struct_type.decl == .none) return false;
32213235 return struct_type.flagsPtr(ip).is_tuple;
......@@ -3262,16 +3276,28 @@ pub const Type = struct {
32623276 }
32633277
32643278 pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
3265 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
3266 inline .struct_type,
3267 .union_type,
3268 .enum_type,
3269 .opaque_type,
3270 => |info| info.zir_index.unwrap(),
3279 const ip = &zcu.intern_pool;
3280 return switch (ip.indexToKey(ty.toIntern())) {
3281 .struct_type => ip.loadStructType(ty.toIntern()).zir_index.unwrap(),
3282 .union_type => ip.loadUnionType(ty.toIntern()).zir_index,
3283 .enum_type => ip.loadEnumType(ty.toIntern()).zir_index.unwrap(),
3284 .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
32713285 else => null,
32723286 };
32733287 }
32743288
3289 /// Given a namespace type, returns its list of caotured values.
3290 pub fn getCaptures(ty: Type, zcu: *const Zcu) InternPool.CaptureValue.Slice {
3291 const ip = &zcu.intern_pool;
3292 return switch (ip.indexToKey(ty.toIntern())) {
3293 .struct_type => ip.loadStructType(ty.toIntern()).captures,
3294 .union_type => ip.loadUnionType(ty.toIntern()).captures,
3295 .enum_type => ip.loadEnumType(ty.toIntern()).captures,
3296 .opaque_type => ip.loadOpaqueType(ty.toIntern()).captures,
3297 else => unreachable,
3298 };
3299 }
3300
32753301 pub const @"u1": Type = .{ .ip_index = .u1_type };
32763302 pub const @"u8": Type = .{ .ip_index = .u8_type };
32773303 pub const @"u16": Type = .{ .ip_index = .u16_type };
test/behavior/enum.zig+21
......@@ -1242,3 +1242,24 @@ test "Non-exhaustive enum backed by comptime_int" {
12421242 e = @as(E, @enumFromInt(378089457309184723749));
12431243 try expect(@intFromEnum(e) == 378089457309184723749);
12441244}
1245
1246test "matching captures causes enum equivalence" {
1247 const S = struct {
1248 fn Nonexhaustive(comptime I: type) type {
1249 const UTag = @Type(.{ .Int = .{
1250 .signedness = .unsigned,
1251 .bits = @typeInfo(I).Int.bits,
1252 } });
1253 return enum(UTag) { _ };
1254 }
1255 };
1256
1257 comptime assert(S.Nonexhaustive(u8) == S.Nonexhaustive(i8));
1258 comptime assert(S.Nonexhaustive(u16) == S.Nonexhaustive(i16));
1259 comptime assert(S.Nonexhaustive(u8) != S.Nonexhaustive(u16));
1260
1261 const a: S.Nonexhaustive(u8) = @enumFromInt(123);
1262 const b: S.Nonexhaustive(i8) = @enumFromInt(123);
1263 comptime assert(@TypeOf(a) == @TypeOf(b));
1264 try expect(@intFromEnum(a) == @intFromEnum(b));
1265}
test/behavior/generics.zig+6-2
......@@ -371,8 +371,12 @@ test "extern function used as generic parameter" {
371371 const S = struct {
372372 extern fn usedAsGenericParameterFoo() void;
373373 extern fn usedAsGenericParameterBar() void;
374 inline fn usedAsGenericParameterBaz(comptime _: anytype) type {
375 return struct {};
374 inline fn usedAsGenericParameterBaz(comptime token: anytype) type {
375 return struct {
376 comptime {
377 _ = token;
378 }
379 };
376380 }
377381 };
378382 try expect(S.usedAsGenericParameterBaz(S.usedAsGenericParameterFoo) !=
test/behavior/src.zig+6-2
......@@ -23,8 +23,12 @@ test "@src" {
2323
2424test "@src used as a comptime parameter" {
2525 const S = struct {
26 fn Foo(comptime _: std.builtin.SourceLocation) type {
27 return struct {};
26 fn Foo(comptime src: std.builtin.SourceLocation) type {
27 return struct {
28 comptime {
29 _ = src;
30 }
31 };
2832 }
2933 };
3034 const T1 = S.Foo(@src());
test/behavior/struct.zig+23
......@@ -2127,3 +2127,26 @@ test "struct containing optional pointer to array of @This()" {
21272127 _ = &s;
21282128 try expect(s.x.?[0].x == null);
21292129}
2130
2131test "matching captures causes struct equivalence" {
2132 const S = struct {
2133 fn UnsignedWrapper(comptime I: type) type {
2134 const bits = @typeInfo(I).Int.bits;
2135 return struct {
2136 x: @Type(.{ .Int = .{
2137 .signedness = .unsigned,
2138 .bits = bits,
2139 } }),
2140 };
2141 }
2142 };
2143
2144 comptime assert(S.UnsignedWrapper(u8) == S.UnsignedWrapper(i8));
2145 comptime assert(S.UnsignedWrapper(u16) == S.UnsignedWrapper(i16));
2146 comptime assert(S.UnsignedWrapper(u8) != S.UnsignedWrapper(u16));
2147
2148 const a: S.UnsignedWrapper(u8) = .{ .x = 10 };
2149 const b: S.UnsignedWrapper(i8) = .{ .x = 10 };
2150 comptime assert(@TypeOf(a) == @TypeOf(b));
2151 try expect(a.x == b.x);
2152}
test/behavior/type.zig+26
......@@ -2,6 +2,7 @@ const std = @import("std");
22const builtin = @import("builtin");
33const Type = std.builtin.Type;
44const testing = std.testing;
5const assert = std.debug.assert;
56
67fn testTypes(comptime types: []const type) !void {
78 inline for (types) |testType| {
......@@ -734,3 +735,28 @@ test "struct field names sliced at comptime from larger string" {
734735 try testing.expectEqualStrings("f3", gen_fields[2].name);
735736 }
736737}
738
739test "matching captures causes opaque equivalence" {
740 const S = struct {
741 fn UnsignedId(comptime I: type) type {
742 const U = @Type(.{ .Int = .{
743 .signedness = .unsigned,
744 .bits = @typeInfo(I).Int.bits,
745 } });
746 return opaque {
747 fn id(x: U) U {
748 return x;
749 }
750 };
751 }
752 };
753
754 comptime assert(S.UnsignedId(u8) == S.UnsignedId(i8));
755 comptime assert(S.UnsignedId(u16) == S.UnsignedId(i16));
756 comptime assert(S.UnsignedId(u8) != S.UnsignedId(u16));
757
758 const a = S.UnsignedId(u8).id(123);
759 const b = S.UnsignedId(i8).id(123);
760 comptime assert(@TypeOf(a) == @TypeOf(b));
761 try testing.expect(a == b);
762}
test/behavior/typename.zig+18-9
......@@ -164,21 +164,30 @@ test "fn param" {
164164}
165165
166166fn TypeFromFn(comptime T: type) type {
167 _ = T;
168 return struct {};
167 return struct {
168 comptime {
169 _ = T;
170 }
171 };
169172}
170173
171174fn TypeFromFn2(comptime T1: type, comptime T2: type) type {
172 _ = T1;
173 _ = T2;
174 return struct {};
175 return struct {
176 comptime {
177 _ = T1;
178 _ = T2;
179 }
180 };
175181}
176182
177183fn TypeFromFnB(comptime T1: type, comptime T2: type, comptime T3: type) type {
178 _ = T1;
179 _ = T2;
180 _ = T3;
181 return struct {};
184 return struct {
185 comptime {
186 _ = T1;
187 _ = T2;
188 _ = T3;
189 }
190 };
182191}
183192
184193/// Replaces integers in `actual` with '0' before doing the test.
test/behavior/union.zig+27
......@@ -2273,3 +2273,30 @@ test "create union(enum) from other union(enum)" {
22732273 else => {},
22742274 }
22752275}
2276
2277test "matching captures causes union equivalence" {
2278 const S = struct {
2279 fn SignedUnsigned(comptime I: type) type {
2280 const bits = @typeInfo(I).Int.bits;
2281 return union {
2282 u: @Type(.{ .Int = .{
2283 .signedness = .unsigned,
2284 .bits = bits,
2285 } }),
2286 i: @Type(.{ .Int = .{
2287 .signedness = .signed,
2288 .bits = bits,
2289 } }),
2290 };
2291 }
2292 };
2293
2294 comptime assert(S.SignedUnsigned(u8) == S.SignedUnsigned(i8));
2295 comptime assert(S.SignedUnsigned(u16) == S.SignedUnsigned(i16));
2296 comptime assert(S.SignedUnsigned(u8) != S.SignedUnsigned(u16));
2297
2298 const a: S.SignedUnsigned(u8) = .{ .u = 10 };
2299 const b: S.SignedUnsigned(i8) = .{ .u = 10 };
2300 comptime assert(@TypeOf(a) == @TypeOf(b));
2301 try expect(a.u == b.u);
2302}
test/cases/compile_errors/reify_struct.zig+1-1
......@@ -74,7 +74,7 @@ comptime {
7474// target=native
7575//
7676// :2:5: error: tuple cannot have non-numeric field 'foo'
77// :16:5: error: tuple field 3 exceeds tuple field count
77// :16:5: error: tuple field name '3' does not match field index 0
7878// :30:5: error: comptime field without default initialization value
7979// :44:5: error: extern struct fields cannot be marked comptime
8080// :58:5: error: alignment in a packed struct field must be set to 0
test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig+1-1
......@@ -30,6 +30,6 @@ export fn entry() void {
3030// backend=stage2
3131// target=native
3232//
33// :13:16: error: enum field(s) missing in union
33// :13:16: error: enum fields missing in union
3434// :1:13: note: field 'arst' missing, declared here
3535// :1:13: note: enum declared here
test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig+1-1
......@@ -26,7 +26,7 @@ export fn entry() void {
2626// backend=stage2
2727// target=native
2828//
29// :12:16: error: enum field(s) missing in union
29// :12:16: error: enum fields missing in union
3030// :1:13: note: field 'signed' missing, declared here
3131// :1:13: note: field 'unsigned' missing, declared here
3232// :1:13: note: enum declared here