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) = .{},...@@ -44,6 +44,9 @@ compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{},
44/// The topmost block of the current function.44/// The topmost block of the current function.
45fn_block: ?*GenZir = null,45fn_block: ?*GenZir = null,
46fn_var_args: bool = false,46fn_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,
47/// The return type of the current function. This may be a trivial `Ref`, or50/// The return type of the current function. This may be a trivial `Ref`, or
48/// otherwise it refers to a `ret_type` instruction.51/// otherwise it refers to a `ret_type` instruction.
49fn_ret_ty: Zir.Inst.Ref = .none,52fn_ret_ty: Zir.Inst.Ref = .none,
...@@ -2205,7 +2208,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn...@@ -2205,7 +2208,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
2205 },2208 },
2206 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,2209 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
2207 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,2210 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2208 .namespace, .enum_namespace => break,2211 .namespace => break,
2209 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,2212 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2210 .top => unreachable,2213 .top => unreachable,
2211 }2214 }
...@@ -2279,7 +2282,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)...@@ -2279,7 +2282,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
2279 try parent_gz.addDefer(defer_scope.index, defer_scope.len);2282 try parent_gz.addDefer(defer_scope.index, defer_scope.len);
2280 },2283 },
2281 .defer_error => scope = scope.cast(Scope.Defer).?.parent,2284 .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2282 .namespace, .enum_namespace => break,2285 .namespace => break,
2283 .top => unreachable,2286 .top => unreachable,
2284 }2287 }
2285 }2288 }
...@@ -2412,7 +2415,7 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.Toke...@@ -2412,7 +2415,7 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.Toke
2412 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,2415 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
2413 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,2416 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2414 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,2417 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2415 .namespace, .enum_namespace => break,2418 .namespace => break,
2416 .top => unreachable,2419 .top => unreachable,
2417 }2420 }
2418 }2421 }
...@@ -2790,7 +2793,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2790,7 +2793,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2790 .@"resume",2793 .@"resume",
2791 .@"await",2794 .@"await",
2792 .ret_err_value_code,2795 .ret_err_value_code,
2793 .closure_get,
2794 .ret_ptr,2796 .ret_ptr,
2795 .ret_type,2797 .ret_type,
2796 .for_len,2798 .for_len,
...@@ -2860,7 +2862,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2860,7 +2862,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2860 .store_to_inferred_ptr,2862 .store_to_inferred_ptr,
2861 .resolve_inferred_alloc,2863 .resolve_inferred_alloc,
2862 .set_runtime_safety,2864 .set_runtime_safety,
2863 .closure_capture,
2864 .memcpy,2865 .memcpy,
2865 .memset,2866 .memset,
2866 .validate_deref,2867 .validate_deref,
...@@ -2928,7 +2929,7 @@ fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct {...@@ -2928,7 +2929,7 @@ fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct {
2928 const have_err_payload = defer_scope.remapped_err_code != .none;2929 const have_err_payload = defer_scope.remapped_err_code != .none;
2929 need_err_code = need_err_code or have_err_payload;2930 need_err_code = need_err_code or have_err_payload;
2930 },2931 },
2931 .namespace, .enum_namespace => unreachable,2932 .namespace => unreachable,
2932 .top => unreachable,2933 .top => unreachable,
2933 }2934 }
2934 }2935 }
...@@ -2998,7 +2999,7 @@ fn genDefers(...@@ -2998,7 +2999,7 @@ fn genDefers(
2998 .normal_only => continue,2999 .normal_only => continue,
2999 }3000 }
3000 },3001 },
3001 .namespace, .enum_namespace => unreachable,3002 .namespace => unreachable,
3002 .top => unreachable,3003 .top => unreachable,
3003 }3004 }
3004 }3005 }
...@@ -3042,7 +3043,7 @@ fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!v...@@ -3042,7 +3043,7 @@ fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!v
3042 scope = s.parent;3043 scope = s.parent;
3043 },3044 },
3044 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,3045 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
3045 .namespace, .enum_namespace => unreachable,3046 .namespace => unreachable,
3046 .top => unreachable,3047 .top => unreachable,
3047 }3048 }
3048 }3049 }
...@@ -4052,6 +4053,11 @@ fn fnDecl(...@@ -4052,6 +4053,11 @@ fn fnDecl(
4052 };4053 };
4053 defer fn_gz.unstack();4054 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
4055 const is_pub = fn_proto.visib_token != null;4061 const is_pub = fn_proto.visib_token != null;
4056 const is_export = blk: {4062 const is_export = blk: {
4057 const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false;4063 const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false;
...@@ -4313,6 +4319,10 @@ fn fnDecl(...@@ -4313,6 +4319,10 @@ fn fnDecl(
43134319
4314 const prev_fn_block = astgen.fn_block;4320 const prev_fn_block = astgen.fn_block;
4315 const prev_fn_ret_ty = astgen.fn_ret_ty;4321 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 }
4316 astgen.fn_block = &fn_gz;4326 astgen.fn_block = &fn_gz;
4317 astgen.fn_ret_ty = if (is_inferred_error or ret_ref.toIndex() != null) r: {4327 astgen.fn_ret_ty = if (is_inferred_error or ret_ref.toIndex() != null) r: {
4318 // We're essentially guaranteed to need the return type at some point,4328 // We're essentially guaranteed to need the return type at some point,
...@@ -4321,10 +4331,6 @@ fn fnDecl(...@@ -4321,10 +4331,6 @@ fn fnDecl(
4321 // return type now so the rest of the function can use it.4331 // return type now so the rest of the function can use it.
4322 break :r try fn_gz.addNode(.ret_type, decl_node);4332 break :r try fn_gz.addNode(.ret_type, decl_node);
4323 } else ret_ref;4333 } else ret_ref;
4324 defer {
4325 astgen.fn_block = prev_fn_block;
4326 astgen.fn_ret_ty = prev_fn_ret_ty;
4327 }
43284334
4329 const prev_var_args = astgen.fn_var_args;4335 const prev_var_args = astgen.fn_var_args;
4330 astgen.fn_var_args = is_var_args;4336 astgen.fn_var_args = is_var_args;
...@@ -4732,7 +4738,7 @@ fn testDecl(...@@ -4732,7 +4738,7 @@ fn testDecl(
4732 },4738 },
4733 .gen_zir => s = s.cast(GenZir).?.parent,4739 .gen_zir => s = s.cast(GenZir).?.parent,
4734 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,4740 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
4735 .namespace, .enum_namespace => {4741 .namespace => {
4736 const ns = s.cast(Scope.Namespace).?;4742 const ns = s.cast(Scope.Namespace).?;
4737 if (ns.decls.get(name_str_index)) |i| {4743 if (ns.decls.get(name_str_index)) |i| {
4738 if (found_already) |f| {4744 if (found_already) |f| {
...@@ -4770,11 +4776,14 @@ fn testDecl(...@@ -4770,11 +4776,14 @@ fn testDecl(
4770 };4776 };
4771 defer fn_block.unstack();4777 defer fn_block.unstack();
47724778
4779 const prev_within_fn = astgen.within_fn;
4773 const prev_fn_block = astgen.fn_block;4780 const prev_fn_block = astgen.fn_block;
4774 const prev_fn_ret_ty = astgen.fn_ret_ty;4781 const prev_fn_ret_ty = astgen.fn_ret_ty;
4782 astgen.within_fn = true;
4775 astgen.fn_block = &fn_block;4783 astgen.fn_block = &fn_block;
4776 astgen.fn_ret_ty = .anyerror_void_error_union_type;4784 astgen.fn_ret_ty = .anyerror_void_error_union_type;
4777 defer {4785 defer {
4786 astgen.within_fn = prev_within_fn;
4778 astgen.fn_block = prev_fn_block;4787 astgen.fn_block = prev_fn_block;
4779 astgen.fn_ret_ty = prev_fn_ret_ty;4788 astgen.fn_ret_ty = prev_fn_ret_ty;
4780 }4789 }
...@@ -4849,10 +4858,10 @@ fn structDeclInner(...@@ -4849,10 +4858,10 @@ fn structDeclInner(
4849 try gz.setStruct(decl_inst, .{4858 try gz.setStruct(decl_inst, .{
4850 .src_node = node,4859 .src_node = node,
4851 .layout = layout,4860 .layout = layout,
4861 .captures_len = 0,
4852 .fields_len = 0,4862 .fields_len = 0,
4853 .decls_len = 0,4863 .decls_len = 0,
4854 .backing_int_ref = .none,4864 .has_backing_int = false,
4855 .backing_int_body_len = 0,
4856 .known_non_opv = false,4865 .known_non_opv = false,
4857 .known_comptime_only = false,4866 .known_comptime_only = false,
4858 .is_tuple = false,4867 .is_tuple = false,
...@@ -4873,6 +4882,7 @@ fn structDeclInner(...@@ -4873,6 +4882,7 @@ fn structDeclInner(
4873 .node = node,4882 .node = node,
4874 .inst = decl_inst,4883 .inst = decl_inst,
4875 .declaring_gz = gz,4884 .declaring_gz = gz,
4885 .maybe_generic = astgen.within_fn,
4876 };4886 };
4877 defer namespace.deinit(gpa);4887 defer namespace.deinit(gpa);
48784888
...@@ -5142,10 +5152,10 @@ fn structDeclInner(...@@ -5142,10 +5152,10 @@ fn structDeclInner(
5142 try gz.setStruct(decl_inst, .{5152 try gz.setStruct(decl_inst, .{
5143 .src_node = node,5153 .src_node = node,
5144 .layout = layout,5154 .layout = layout,
5155 .captures_len = @intCast(namespace.captures.count()),
5145 .fields_len = field_count,5156 .fields_len = field_count,
5146 .decls_len = decl_count,5157 .decls_len = decl_count,
5147 .backing_int_ref = backing_int_ref,5158 .has_backing_int = backing_int_ref != .none,
5148 .backing_int_body_len = @intCast(backing_int_body_len),
5149 .known_non_opv = known_non_opv,5159 .known_non_opv = known_non_opv,
5150 .known_comptime_only = known_comptime_only,5160 .known_comptime_only = known_comptime_only,
5151 .is_tuple = is_tuple,5161 .is_tuple = is_tuple,
...@@ -5159,15 +5169,22 @@ fn structDeclInner(...@@ -5159,15 +5169,22 @@ fn structDeclInner(
5159 const decls_slice = wip_members.declsSlice();5169 const decls_slice = wip_members.declsSlice();
5160 const fields_slice = wip_members.fieldsSlice();5170 const fields_slice = wip_members.fieldsSlice();
5161 const bodies_slice = astgen.scratch.items[bodies_start..];5171 const bodies_slice = astgen.scratch.items[bodies_start..];
5162 try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len +5172 try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len + 2 +
5163 decls_slice.len + fields_slice.len + bodies_slice.len);5173 decls_slice.len + namespace.captures.count() + fields_slice.len + bodies_slice.len);
5164 astgen.extra.appendSliceAssumeCapacity(astgen.scratch.items[scratch_top..][0..backing_int_body_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 }
5165 astgen.extra.appendSliceAssumeCapacity(decls_slice);5183 astgen.extra.appendSliceAssumeCapacity(decls_slice);
5166 astgen.extra.appendSliceAssumeCapacity(fields_slice);5184 astgen.extra.appendSliceAssumeCapacity(fields_slice);
5167 astgen.extra.appendSliceAssumeCapacity(bodies_slice);5185 astgen.extra.appendSliceAssumeCapacity(bodies_slice);
51685186
5169 block_scope.unstack();5187 block_scope.unstack();
5170 try gz.addNamespaceCaptures(&namespace);
5171 return decl_inst.toRef();5188 return decl_inst.toRef();
5172}5189}
51735190
...@@ -5190,6 +5207,7 @@ fn unionDeclInner(...@@ -5190,6 +5207,7 @@ fn unionDeclInner(
5190 .node = node,5207 .node = node,
5191 .inst = decl_inst,5208 .inst = decl_inst,
5192 .declaring_gz = gz,5209 .declaring_gz = gz,
5210 .maybe_generic = astgen.within_fn,
5193 };5211 };
5194 defer namespace.deinit(gpa);5212 defer namespace.deinit(gpa);
51955213
...@@ -5368,6 +5386,7 @@ fn unionDeclInner(...@@ -5368,6 +5386,7 @@ fn unionDeclInner(
5368 .src_node = node,5386 .src_node = node,
5369 .layout = layout,5387 .layout = layout,
5370 .tag_type = arg_inst,5388 .tag_type = arg_inst,
5389 .captures_len = @intCast(namespace.captures.count()),
5371 .body_len = body_len,5390 .body_len = body_len,
5372 .fields_len = field_count,5391 .fields_len = field_count,
5373 .decls_len = decl_count,5392 .decls_len = decl_count,
...@@ -5379,13 +5398,13 @@ fn unionDeclInner(...@@ -5379,13 +5398,13 @@ fn unionDeclInner(
5379 wip_members.finishBits(bits_per_field);5398 wip_members.finishBits(bits_per_field);
5380 const decls_slice = wip_members.declsSlice();5399 const decls_slice = wip_members.declsSlice();
5381 const fields_slice = wip_members.fieldsSlice();5400 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()));
5383 astgen.extra.appendSliceAssumeCapacity(decls_slice);5403 astgen.extra.appendSliceAssumeCapacity(decls_slice);
5384 astgen.appendBodyWithFixups(body);5404 astgen.appendBodyWithFixups(body);
5385 astgen.extra.appendSliceAssumeCapacity(fields_slice);5405 astgen.extra.appendSliceAssumeCapacity(fields_slice);
53865406
5387 block_scope.unstack();5407 block_scope.unstack();
5388 try gz.addNamespaceCaptures(&namespace);
5389 return decl_inst.toRef();5408 return decl_inst.toRef();
5390}5409}
53915410
...@@ -5537,6 +5556,7 @@ fn containerDecl(...@@ -5537,6 +5556,7 @@ fn containerDecl(
5537 .node = node,5556 .node = node,
5538 .inst = decl_inst,5557 .inst = decl_inst,
5539 .declaring_gz = gz,5558 .declaring_gz = gz,
5559 .maybe_generic = astgen.within_fn,
5540 };5560 };
5541 defer namespace.deinit(gpa);5561 defer namespace.deinit(gpa);
55425562
...@@ -5555,7 +5575,7 @@ fn containerDecl(...@@ -5555,7 +5575,7 @@ fn containerDecl(
5555 defer block_scope.unstack();5575 defer block_scope.unstack();
55565576
5557 _ = try astgen.scanDecls(&namespace, container_decl.ast.members);5577 _ = try astgen.scanDecls(&namespace, container_decl.ast.members);
5558 namespace.base.tag = .enum_namespace;5578 namespace.base.tag = .namespace;
55595579
5560 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0)5580 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0)
5561 try comptimeExpr(&block_scope, &namespace.base, coerced_type_ri, container_decl.ast.arg)5581 try comptimeExpr(&block_scope, &namespace.base, coerced_type_ri, container_decl.ast.arg)
...@@ -5586,7 +5606,6 @@ fn containerDecl(...@@ -5586,7 +5606,6 @@ fn containerDecl(
5586 if (member_node == counts.nonexhaustive_node)5606 if (member_node == counts.nonexhaustive_node)
5587 continue;5607 continue;
5588 fields_hasher.update(tree.getNodeSource(member_node));5608 fields_hasher.update(tree.getNodeSource(member_node));
5589 namespace.base.tag = .namespace;
5590 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {5609 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
5591 .decl => continue,5610 .decl => continue,
5592 .field => |field| field,5611 .field => |field| field,
...@@ -5630,7 +5649,6 @@ fn containerDecl(...@@ -5630,7 +5649,6 @@ fn containerDecl(
5630 },5649 },
5631 );5650 );
5632 }5651 }
5633 namespace.base.tag = .enum_namespace;
5634 const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .rl = .{ .ty = arg_inst } }, member.ast.value_expr);5652 const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .rl = .{ .ty = arg_inst } }, member.ast.value_expr);
5635 wip_members.appendToField(@intFromEnum(tag_value_inst));5653 wip_members.appendToField(@intFromEnum(tag_value_inst));
5636 }5654 }
...@@ -5676,6 +5694,7 @@ fn containerDecl(...@@ -5676,6 +5694,7 @@ fn containerDecl(
5676 .src_node = node,5694 .src_node = node,
5677 .nonexhaustive = nonexhaustive,5695 .nonexhaustive = nonexhaustive,
5678 .tag_type = arg_inst,5696 .tag_type = arg_inst,
5697 .captures_len = @intCast(namespace.captures.count()),
5679 .body_len = body_len,5698 .body_len = body_len,
5680 .fields_len = @intCast(counts.total_fields),5699 .fields_len = @intCast(counts.total_fields),
5681 .decls_len = @intCast(counts.decls),5700 .decls_len = @intCast(counts.decls),
...@@ -5685,13 +5704,13 @@ fn containerDecl(...@@ -5685,13 +5704,13 @@ fn containerDecl(
5685 wip_members.finishBits(bits_per_field);5704 wip_members.finishBits(bits_per_field);
5686 const decls_slice = wip_members.declsSlice();5705 const decls_slice = wip_members.declsSlice();
5687 const fields_slice = wip_members.fieldsSlice();5706 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()));
5689 astgen.extra.appendSliceAssumeCapacity(decls_slice);5709 astgen.extra.appendSliceAssumeCapacity(decls_slice);
5690 astgen.appendBodyWithFixups(body);5710 astgen.appendBodyWithFixups(body);
5691 astgen.extra.appendSliceAssumeCapacity(fields_slice);5711 astgen.extra.appendSliceAssumeCapacity(fields_slice);
56925712
5693 block_scope.unstack();5713 block_scope.unstack();
5694 try gz.addNamespaceCaptures(&namespace);
5695 return rvalue(gz, ri, decl_inst.toRef(), node);5714 return rvalue(gz, ri, decl_inst.toRef(), node);
5696 },5715 },
5697 .keyword_opaque => {5716 .keyword_opaque => {
...@@ -5704,6 +5723,7 @@ fn containerDecl(...@@ -5704,6 +5723,7 @@ fn containerDecl(
5704 .node = node,5723 .node = node,
5705 .inst = decl_inst,5724 .inst = decl_inst,
5706 .declaring_gz = gz,5725 .declaring_gz = gz,
5726 .maybe_generic = astgen.within_fn,
5707 };5727 };
5708 defer namespace.deinit(gpa);5728 defer namespace.deinit(gpa);
57095729
...@@ -5733,16 +5753,17 @@ fn containerDecl(...@@ -5733,16 +5753,17 @@ fn containerDecl(
57335753
5734 try gz.setOpaque(decl_inst, .{5754 try gz.setOpaque(decl_inst, .{
5735 .src_node = node,5755 .src_node = node,
5756 .captures_len = @intCast(namespace.captures.count()),
5736 .decls_len = decl_count,5757 .decls_len = decl_count,
5737 });5758 });
57385759
5739 wip_members.finishBits(0);5760 wip_members.finishBits(0);
5740 const decls_slice = wip_members.declsSlice();5761 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()));
5742 astgen.extra.appendSliceAssumeCapacity(decls_slice);5764 astgen.extra.appendSliceAssumeCapacity(decls_slice);
57435765
5744 block_scope.unstack();5766 block_scope.unstack();
5745 try gz.addNamespaceCaptures(&namespace);
5746 return rvalue(gz, ri, decl_inst.toRef(), node);5767 return rvalue(gz, ri, decl_inst.toRef(), node);
5747 },5768 },
5748 else => unreachable,5769 else => unreachable,
...@@ -8238,12 +8259,17 @@ fn localVarRef(...@@ -8238,12 +8259,17 @@ fn localVarRef(
8238 ident_token: Ast.TokenIndex,8259 ident_token: Ast.TokenIndex,
8239) InnerError!Zir.Inst.Ref {8260) InnerError!Zir.Inst.Ref {
8240 const astgen = gz.astgen;8261 const astgen = gz.astgen;
8241 const gpa = astgen.gpa;
8242 const name_str_index = try astgen.identAsString(ident_token);8262 const name_str_index = try astgen.identAsString(ident_token);
8243 var s = scope;8263 var s = scope;
8244 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already8264 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
8245 var num_namespaces_out: u32 = 0;8269 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
8247 while (true) switch (s.tag) {8273 while (true) switch (s.tag) {
8248 .local_val => {8274 .local_val => {
8249 const local_val = s.cast(Scope.LocalVal).?;8275 const local_val = s.cast(Scope.LocalVal).?;
...@@ -8257,15 +8283,13 @@ fn localVarRef(...@@ -8257,15 +8283,13 @@ fn localVarRef(
8257 local_val.used = ident_token;8283 local_val.used = ident_token;
8258 }8284 }
82598285
8260 const value_inst = try tunnelThroughClosure(8286 const value_inst = if (num_namespaces_out != 0) try tunnelThroughClosure(
8261 gz,8287 gz,
8262 ident,8288 ident,
8263 num_namespaces_out,8289 num_namespaces_out,
8264 capturing_namespace,8290 .{ .ref = local_val.inst },
8265 local_val.inst,8291 .{ .token = local_val.token_src },
8266 local_val.token_src,8292 ) else local_val.inst;
8267 gpa,
8268 );
82698293
8270 return rvalueNoCoercePreRef(gz, ri, value_inst, ident);8294 return rvalueNoCoercePreRef(gz, ri, value_inst, ident);
8271 }8295 }
...@@ -8285,19 +8309,17 @@ fn localVarRef(...@@ -8285,19 +8309,17 @@ fn localVarRef(
8285 const ident_name = try astgen.identifierTokenString(ident_token);8309 const ident_name = try astgen.identifierTokenString(ident_token);
8286 return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{8310 return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{
8287 try astgen.errNoteTok(local_ptr.token_src, "declared mutable here", .{}),8311 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", .{}),
8289 });8313 });
8290 }8314 }
82918315
8292 const ptr_inst = try tunnelThroughClosure(8316 const ptr_inst = if (num_namespaces_out != 0) try tunnelThroughClosure(
8293 gz,8317 gz,
8294 ident,8318 ident,
8295 num_namespaces_out,8319 num_namespaces_out,
8296 capturing_namespace,8320 .{ .ref = local_ptr.ptr },
8297 local_ptr.ptr,8321 .{ .token = local_ptr.token_src },
8298 local_ptr.token_src,8322 ) else local_ptr.ptr;
8299 gpa,
8300 );
83018323
8302 switch (ri.rl) {8324 switch (ri.rl) {
8303 .ref, .ref_coerced_ty => {8325 .ref, .ref_coerced_ty => {
...@@ -8314,7 +8336,7 @@ fn localVarRef(...@@ -8314,7 +8336,7 @@ fn localVarRef(
8314 },8336 },
8315 .gen_zir => s = s.cast(GenZir).?.parent,8337 .gen_zir => s = s.cast(GenZir).?.parent,
8316 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,8338 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
8317 .namespace, .enum_namespace => {8339 .namespace => {
8318 const ns = s.cast(Scope.Namespace).?;8340 const ns = s.cast(Scope.Namespace).?;
8319 if (ns.decls.get(name_str_index)) |i| {8341 if (ns.decls.get(name_str_index)) |i| {
8320 if (found_already) |f| {8342 if (found_already) |f| {
...@@ -8325,8 +8347,10 @@ fn localVarRef(...@@ -8325,8 +8347,10 @@ fn localVarRef(
8325 }8347 }
8326 // We found a match but must continue looking for ambiguous references to decls.8348 // We found a match but must continue looking for ambiguous references to decls.
8327 found_already = i;8349 found_already = i;
8350 found_needs_tunnel = ns.maybe_generic;
8351 found_namespaces_out = num_namespaces_out;
8328 }8352 }
8329 if (s.tag == .namespace) num_namespaces_out += 1;8353 num_namespaces_out += 1;
8330 capturing_namespace = ns;8354 capturing_namespace = ns;
8331 s = ns.parent;8355 s = ns.parent;
8332 },8356 },
...@@ -8339,6 +8363,29 @@ fn localVarRef(...@@ -8339,6 +8363,29 @@ fn localVarRef(
83398363
8340 // Decl references happen by name rather than ZIR index so that when unrelated8364 // Decl references happen by name rather than ZIR index so that when unrelated
8341 // decls are modified, ZIR code containing references to them can be unmodified.8365 // 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
8342 switch (ri.rl) {8389 switch (ri.rl) {
8343 .ref, .ref_coerced_ty => return gz.addStrTok(.decl_ref, name_str_index, ident_token),8390 .ref, .ref_coerced_ty => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
8344 else => {8391 else => {
...@@ -8348,41 +8395,90 @@ fn localVarRef(...@@ -8348,41 +8395,90 @@ fn localVarRef(
8348 }8395 }
8349}8396}
83508397
8351/// Adds a capture to a namespace, if needed.8398/// Access a ZIR instruction through closure. May tunnel through arbitrarily
8352/// Returns the index of the closure_capture instruction.8399/// many namespaces, adding closure captures as required.
8400/// Returns the index of the `closure_get` instruction added to `gz`.
8353fn tunnelThroughClosure(8401fn tunnelThroughClosure(
8354 gz: *GenZir,8402 gz: *GenZir,
8403 /// The node which references the value to be captured.
8355 inner_ref_node: Ast.Node.Index,8404 inner_ref_node: Ast.Node.Index,
8405 /// The number of namespaces being tunnelled through. At least 1.
8356 num_tunnels: u32,8406 num_tunnels: u32,
8357 ns: ?*Scope.Namespace,8407 /// The value being captured.
8358 value: Zir.Inst.Ref,8408 value: union(enum) {
8359 token: Ast.TokenIndex,8409 ref: Zir.Inst.Ref,
8360 gpa: Allocator,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 },
8361) !Zir.Inst.Ref {8418) !Zir.Inst.Ref {
8362 // For trivial values, we don't need a tunnel.8419 switch (value) {
8363 // Just return the ref.8420 .ref => |v| if (v.toIndex() == null) return v, // trivia value; do not need tunnel
8364 if (num_tunnels == 0 or value.toIndex() == null) {8421 .decl_val, .decl_ref => {},
8365 return value;
8366 }8422 }
83678423
8368 // Otherwise we need a tunnel. Check if this namespace8424 const astgen = gz.astgen;
8369 // already has one for this value.8425 const gpa = astgen.gpa;
8370 const gop = try ns.?.captures.getOrPut(gpa, value.toIndex().?);8426
8371 if (!gop.found_existing) {8427 // Otherwise we need a tunnel. First, figure out the path of namespaces we
8372 // Make a new capture for this value but don't add it to the declaring_gz yet8428 // are tunneling through. This is usually only going to be one or two, so
8373 try gz.astgen.instructions.append(gz.astgen.gpa, .{8429 // use an SFBA to optimize for the common case.
8374 .tag = .closure_capture,8430 var sfba = std.heap.stackFallback(@sizeOf(usize) * 2, astgen.arena);
8375 .data = .{ .un_tok = .{8431 var intermediate_tunnels = try sfba.get().alloc(*Scope.Namespace, num_tunnels - 1);
8376 .operand = value,8432
8377 .src_tok = ns.?.declaring_gz.?.tokenIndexToRelative(token),8433 const root_ns = ns: {
8378 } },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", .{}),
8379 });8477 });
8380 gop.value_ptr.* = @enumFromInt(gz.astgen.instructions.len - 1);
8381 }8478 }
83828479
8383 // Add an instruction to get the value from the closure into8480 // Add an instruction to get the value from the closure.
8384 // our current context8481 return gz.addExtendedNodeSmall(.closure_get, inner_ref_node, cur_capture_index);
8385 return try gz.addInstNode(.closure_get, gop.value_ptr.*, inner_ref_node);
8386}8482}
83878483
8388fn stringLiteral(8484fn stringLiteral(
...@@ -9095,7 +9191,7 @@ fn builtinCall(...@@ -9095,7 +9191,7 @@ fn builtinCall(
9095 },9191 },
9096 .gen_zir => s = s.cast(GenZir).?.parent,9192 .gen_zir => s = s.cast(GenZir).?.parent,
9097 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,9193 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
9098 .namespace, .enum_namespace => {9194 .namespace => {
9099 const ns = s.cast(Scope.Namespace).?;9195 const ns = s.cast(Scope.Namespace).?;
9100 if (ns.decls.get(decl_name)) |i| {9196 if (ns.decls.get(decl_name)) |i| {
9101 if (found_already) |f| {9197 if (found_already) |f| {
...@@ -11605,7 +11701,7 @@ const Scope = struct {...@@ -11605,7 +11701,7 @@ const Scope = struct {
11605 }11701 }
11606 if (T == Namespace) {11702 if (T == Namespace) {
11607 switch (base.tag) {11703 switch (base.tag) {
11608 .namespace, .enum_namespace => return @fieldParentPtr(T, "base", base),11704 .namespace => return @fieldParentPtr(T, "base", base),
11609 else => return null,11705 else => return null,
11610 }11706 }
11611 }11707 }
...@@ -11621,7 +11717,7 @@ const Scope = struct {...@@ -11621,7 +11717,7 @@ const Scope = struct {
11621 .local_val => base.cast(LocalVal).?.parent,11717 .local_val => base.cast(LocalVal).?.parent,
11622 .local_ptr => base.cast(LocalPtr).?.parent,11718 .local_ptr => base.cast(LocalPtr).?.parent,
11623 .defer_normal, .defer_error => base.cast(Defer).?.parent,11719 .defer_normal, .defer_error => base.cast(Defer).?.parent,
11624 .namespace, .enum_namespace => base.cast(Namespace).?.parent,11720 .namespace => base.cast(Namespace).?.parent,
11625 .top => null,11721 .top => null,
11626 };11722 };
11627 }11723 }
...@@ -11633,7 +11729,6 @@ const Scope = struct {...@@ -11633,7 +11729,6 @@ const Scope = struct {
11633 defer_normal,11729 defer_normal,
11634 defer_error,11730 defer_error,
11635 namespace,11731 namespace,
11636 enum_namespace,
11637 top,11732 top,
11638 };11733 };
1163911734
...@@ -11720,14 +11815,14 @@ const Scope = struct {...@@ -11720,14 +11815,14 @@ const Scope = struct {
11720 decls: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{},11815 decls: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{},
11721 node: Ast.Node.Index,11816 node: Ast.Node.Index,
11722 inst: Zir.Inst.Index,11817 inst: Zir.Inst.Index,
11818 maybe_generic: bool,
1172311819
11724 /// The astgen scope containing this namespace.11820 /// The astgen scope containing this namespace.
11725 /// Only valid during astgen.11821 /// Only valid during astgen.
11726 declaring_gz: ?*GenZir,11822 declaring_gz: ?*GenZir,
1172711823
11728 /// Map from the raw captured value to the instruction11824 /// Set of captures used by this namespace.
11729 /// ref of the capture for decls in this namespace11825 captures: std.AutoArrayHashMapUnmanaged(Zir.Inst.Capture, void) = .{},
11730 captures: std.AutoArrayHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
1173111826
11732 fn deinit(self: *Namespace, gpa: Allocator) void {11827 fn deinit(self: *Namespace, gpa: Allocator) void {
11733 self.decls.deinit(gpa);11828 self.decls.deinit(gpa);
...@@ -11787,12 +11882,6 @@ const GenZir = struct {...@@ -11787,12 +11882,6 @@ const GenZir = struct {
11787 // Set if this GenZir is a defer or it is inside a defer.11882 // Set if this GenZir is a defer or it is inside a defer.
11788 any_defer_node: Ast.Node.Index = 0,11883 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
11796 const unstacked_top = std.math.maxInt(usize);11885 const unstacked_top = std.math.maxInt(usize);
11797 /// Call unstack before adding any new instructions to containing GenZir.11886 /// Call unstack before adding any new instructions to containing GenZir.
11798 fn unstack(self: *GenZir) void {11887 fn unstack(self: *GenZir) void {
...@@ -12534,6 +12623,30 @@ const GenZir = struct {...@@ -12534,6 +12623,30 @@ const GenZir = struct {
12534 return new_index.toRef();12623 return new_index.toRef();
12535 }12624 }
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
12537 fn addUnTok(12650 fn addUnTok(
12538 gz: *GenZir,12651 gz: *GenZir,
12539 tag: Zir.Inst.Tag,12652 tag: Zir.Inst.Tag,
...@@ -12957,10 +13070,10 @@ const GenZir = struct {...@@ -12957,10 +13070,10 @@ const GenZir = struct {
1295713070
12958 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {13071 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
12959 src_node: Ast.Node.Index,13072 src_node: Ast.Node.Index,
13073 captures_len: u32,
12960 fields_len: u32,13074 fields_len: u32,
12961 decls_len: u32,13075 decls_len: u32,
12962 backing_int_ref: Zir.Inst.Ref,13076 has_backing_int: bool,
12963 backing_int_body_len: u32,
12964 layout: std.builtin.Type.ContainerLayout,13077 layout: std.builtin.Type.ContainerLayout,
12965 known_non_opv: bool,13078 known_non_opv: bool,
12966 known_comptime_only: bool,13079 known_comptime_only: bool,
...@@ -12978,7 +13091,7 @@ const GenZir = struct {...@@ -12978,7 +13091,7 @@ const GenZir = struct {
1297813091
12979 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);13092 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);
12982 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{13095 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
12983 .fields_hash_0 = fields_hash_arr[0],13096 .fields_hash_0 = fields_hash_arr[0],
12984 .fields_hash_1 = fields_hash_arr[1],13097 .fields_hash_1 = fields_hash_arr[1],
...@@ -12987,26 +13100,24 @@ const GenZir = struct {...@@ -12987,26 +13100,24 @@ const GenZir = struct {
12987 .src_node = gz.nodeIndexToRelative(args.src_node),13100 .src_node = gz.nodeIndexToRelative(args.src_node),
12988 });13101 });
1298913102
13103 if (args.captures_len != 0) {
13104 astgen.extra.appendAssumeCapacity(args.captures_len);
13105 }
12990 if (args.fields_len != 0) {13106 if (args.fields_len != 0) {
12991 astgen.extra.appendAssumeCapacity(args.fields_len);13107 astgen.extra.appendAssumeCapacity(args.fields_len);
12992 }13108 }
12993 if (args.decls_len != 0) {13109 if (args.decls_len != 0) {
12994 astgen.extra.appendAssumeCapacity(args.decls_len);13110 astgen.extra.appendAssumeCapacity(args.decls_len);
12995 }13111 }
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 }
13002 astgen.instructions.set(@intFromEnum(inst), .{13112 astgen.instructions.set(@intFromEnum(inst), .{
13003 .tag = .extended,13113 .tag = .extended,
13004 .data = .{ .extended = .{13114 .data = .{ .extended = .{
13005 .opcode = .struct_decl,13115 .opcode = .struct_decl,
13006 .small = @bitCast(Zir.Inst.StructDecl.Small{13116 .small = @bitCast(Zir.Inst.StructDecl.Small{
13117 .has_captures_len = args.captures_len != 0,
13007 .has_fields_len = args.fields_len != 0,13118 .has_fields_len = args.fields_len != 0,
13008 .has_decls_len = args.decls_len != 0,13119 .has_decls_len = args.decls_len != 0,
13009 .has_backing_int = args.backing_int_ref != .none,13120 .has_backing_int = args.has_backing_int,
13010 .known_non_opv = args.known_non_opv,13121 .known_non_opv = args.known_non_opv,
13011 .known_comptime_only = args.known_comptime_only,13122 .known_comptime_only = args.known_comptime_only,
13012 .is_tuple = args.is_tuple,13123 .is_tuple = args.is_tuple,
...@@ -13024,6 +13135,7 @@ const GenZir = struct {...@@ -13024,6 +13135,7 @@ const GenZir = struct {
13024 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct {13135 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
13025 src_node: Ast.Node.Index,13136 src_node: Ast.Node.Index,
13026 tag_type: Zir.Inst.Ref,13137 tag_type: Zir.Inst.Ref,
13138 captures_len: u32,
13027 body_len: u32,13139 body_len: u32,
13028 fields_len: u32,13140 fields_len: u32,
13029 decls_len: u32,13141 decls_len: u32,
...@@ -13039,7 +13151,7 @@ const GenZir = struct {...@@ -13039,7 +13151,7 @@ const GenZir = struct {
1303913151
13040 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);13152 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);
13043 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{13155 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{
13044 .fields_hash_0 = fields_hash_arr[0],13156 .fields_hash_0 = fields_hash_arr[0],
13045 .fields_hash_1 = fields_hash_arr[1],13157 .fields_hash_1 = fields_hash_arr[1],
...@@ -13051,6 +13163,9 @@ const GenZir = struct {...@@ -13051,6 +13163,9 @@ const GenZir = struct {
13051 if (args.tag_type != .none) {13163 if (args.tag_type != .none) {
13052 astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));13164 astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));
13053 }13165 }
13166 if (args.captures_len != 0) {
13167 astgen.extra.appendAssumeCapacity(args.captures_len);
13168 }
13054 if (args.body_len != 0) {13169 if (args.body_len != 0) {
13055 astgen.extra.appendAssumeCapacity(args.body_len);13170 astgen.extra.appendAssumeCapacity(args.body_len);
13056 }13171 }
...@@ -13066,6 +13181,7 @@ const GenZir = struct {...@@ -13066,6 +13181,7 @@ const GenZir = struct {
13066 .opcode = .union_decl,13181 .opcode = .union_decl,
13067 .small = @bitCast(Zir.Inst.UnionDecl.Small{13182 .small = @bitCast(Zir.Inst.UnionDecl.Small{
13068 .has_tag_type = args.tag_type != .none,13183 .has_tag_type = args.tag_type != .none,
13184 .has_captures_len = args.captures_len != 0,
13069 .has_body_len = args.body_len != 0,13185 .has_body_len = args.body_len != 0,
13070 .has_fields_len = args.fields_len != 0,13186 .has_fields_len = args.fields_len != 0,
13071 .has_decls_len = args.decls_len != 0,13187 .has_decls_len = args.decls_len != 0,
...@@ -13082,6 +13198,7 @@ const GenZir = struct {...@@ -13082,6 +13198,7 @@ const GenZir = struct {
13082 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {13198 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
13083 src_node: Ast.Node.Index,13199 src_node: Ast.Node.Index,
13084 tag_type: Zir.Inst.Ref,13200 tag_type: Zir.Inst.Ref,
13201 captures_len: u32,
13085 body_len: u32,13202 body_len: u32,
13086 fields_len: u32,13203 fields_len: u32,
13087 decls_len: u32,13204 decls_len: u32,
...@@ -13095,7 +13212,7 @@ const GenZir = struct {...@@ -13095,7 +13212,7 @@ const GenZir = struct {
1309513212
13096 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);13213 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);
13099 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{13216 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{
13100 .fields_hash_0 = fields_hash_arr[0],13217 .fields_hash_0 = fields_hash_arr[0],
13101 .fields_hash_1 = fields_hash_arr[1],13218 .fields_hash_1 = fields_hash_arr[1],
...@@ -13107,6 +13224,9 @@ const GenZir = struct {...@@ -13107,6 +13224,9 @@ const GenZir = struct {
13107 if (args.tag_type != .none) {13224 if (args.tag_type != .none) {
13108 astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));13225 astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));
13109 }13226 }
13227 if (args.captures_len != 0) {
13228 astgen.extra.appendAssumeCapacity(args.captures_len);
13229 }
13110 if (args.body_len != 0) {13230 if (args.body_len != 0) {
13111 astgen.extra.appendAssumeCapacity(args.body_len);13231 astgen.extra.appendAssumeCapacity(args.body_len);
13112 }13232 }
...@@ -13122,6 +13242,7 @@ const GenZir = struct {...@@ -13122,6 +13242,7 @@ const GenZir = struct {
13122 .opcode = .enum_decl,13242 .opcode = .enum_decl,
13123 .small = @bitCast(Zir.Inst.EnumDecl.Small{13243 .small = @bitCast(Zir.Inst.EnumDecl.Small{
13124 .has_tag_type = args.tag_type != .none,13244 .has_tag_type = args.tag_type != .none,
13245 .has_captures_len = args.captures_len != 0,
13125 .has_body_len = args.body_len != 0,13246 .has_body_len = args.body_len != 0,
13126 .has_fields_len = args.fields_len != 0,13247 .has_fields_len = args.fields_len != 0,
13127 .has_decls_len = args.decls_len != 0,13248 .has_decls_len = args.decls_len != 0,
...@@ -13135,6 +13256,7 @@ const GenZir = struct {...@@ -13135,6 +13256,7 @@ const GenZir = struct {
1313513256
13136 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct {13257 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
13137 src_node: Ast.Node.Index,13258 src_node: Ast.Node.Index,
13259 captures_len: u32,
13138 decls_len: u32,13260 decls_len: u32,
13139 }) !void {13261 }) !void {
13140 const astgen = gz.astgen;13262 const astgen = gz.astgen;
...@@ -13142,11 +13264,14 @@ const GenZir = struct {...@@ -13142,11 +13264,14 @@ const GenZir = struct {
1314213264
13143 assert(args.src_node != 0);13265 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);
13146 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{13268 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{
13147 .src_node = gz.nodeIndexToRelative(args.src_node),13269 .src_node = gz.nodeIndexToRelative(args.src_node),
13148 });13270 });
1314913271
13272 if (args.captures_len != 0) {
13273 astgen.extra.appendAssumeCapacity(args.captures_len);
13274 }
13150 if (args.decls_len != 0) {13275 if (args.decls_len != 0) {
13151 astgen.extra.appendAssumeCapacity(args.decls_len);13276 astgen.extra.appendAssumeCapacity(args.decls_len);
13152 }13277 }
...@@ -13155,6 +13280,7 @@ const GenZir = struct {...@@ -13155,6 +13280,7 @@ const GenZir = struct {
13155 .data = .{ .extended = .{13280 .data = .{ .extended = .{
13156 .opcode = .opaque_decl,13281 .opcode = .opaque_decl,
13157 .small = @bitCast(Zir.Inst.OpaqueDecl.Small{13282 .small = @bitCast(Zir.Inst.OpaqueDecl.Small{
13283 .has_captures_len = args.captures_len != 0,
13158 .has_decls_len = args.decls_len != 0,13284 .has_decls_len = args.decls_len != 0,
13159 .name_strategy = gz.anon_name_strategy,13285 .name_strategy = gz.anon_name_strategy,
13160 }),13286 }),
...@@ -13197,15 +13323,6 @@ const GenZir = struct {...@@ -13197,15 +13323,6 @@ const GenZir = struct {
13197 }13323 }
13198 }13324 }
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
13209 fn addDbgVar(gz: *GenZir, tag: Zir.Inst.Tag, name: Zir.NullTerminatedString, inst: Zir.Inst.Ref) !void {13326 fn addDbgVar(gz: *GenZir, tag: Zir.Inst.Tag, name: Zir.NullTerminatedString, inst: Zir.Inst.Ref) !void {
13210 if (gz.is_comptime) return;13327 if (gz.is_comptime) return;
1321113328
...@@ -13305,7 +13422,7 @@ fn detectLocalShadowing(...@@ -13305,7 +13422,7 @@ fn detectLocalShadowing(
13305 }13422 }
13306 s = local_ptr.parent;13423 s = local_ptr.parent;
13307 },13424 },
13308 .namespace, .enum_namespace => {13425 .namespace => {
13309 outer_scope = true;13426 outer_scope = true;
13310 const ns = s.cast(Scope.Namespace).?;13427 const ns = s.cast(Scope.Namespace).?;
13311 const decl_node = ns.decls.get(ident_name) orelse {13428 const decl_node = ns.decls.get(ident_name) orelse {
...@@ -13478,7 +13595,7 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast....@@ -13478,7 +13595,7 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
13478 }13595 }
13479 s = local_ptr.parent;13596 s = local_ptr.parent;
13480 },13597 },
13481 .namespace, .enum_namespace => s = s.cast(Scope.Namespace).?.parent,13598 .namespace => s = s.cast(Scope.Namespace).?.parent,
13482 .gen_zir => s = s.cast(GenZir).?.parent,13599 .gen_zir => s = s.cast(GenZir).?.parent,
13483 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,13600 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
13484 .top => break,13601 .top => break,
lib/std/zig/Zir.zig+123-48
...@@ -1004,17 +1004,6 @@ pub const Inst = struct {...@@ -1004,17 +1004,6 @@ pub const Inst = struct {
1004 @"resume",1004 @"resume",
1005 @"await",1005 @"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
1018 /// A defer statement.1007 /// A defer statement.
1019 /// Uses the `defer` union field.1008 /// Uses the `defer` union field.
1020 @"defer",1009 @"defer",
...@@ -1251,8 +1240,6 @@ pub const Inst = struct {...@@ -1251,8 +1240,6 @@ pub const Inst = struct {
1251 .@"await",1240 .@"await",
1252 .ret_err_value_code,1241 .ret_err_value_code,
1253 .extended,1242 .extended,
1254 .closure_get,
1255 .closure_capture,
1256 .ret_ptr,1243 .ret_ptr,
1257 .ret_type,1244 .ret_type,
1258 .@"try",1245 .@"try",
...@@ -1542,8 +1529,6 @@ pub const Inst = struct {...@@ -1542,8 +1529,6 @@ pub const Inst = struct {
1542 .@"resume",1529 .@"resume",
1543 .@"await",1530 .@"await",
1544 .ret_err_value_code,1531 .ret_err_value_code,
1545 .closure_get,
1546 .closure_capture,
1547 .@"break",1532 .@"break",
1548 .break_inline,1533 .break_inline,
1549 .condbr,1534 .condbr,
...@@ -1829,9 +1814,6 @@ pub const Inst = struct {...@@ -1829,9 +1814,6 @@ pub const Inst = struct {
1829 .@"resume" = .un_node,1814 .@"resume" = .un_node,
1830 .@"await" = .un_node,1815 .@"await" = .un_node,
18311816
1832 .closure_capture = .un_tok,
1833 .closure_get = .inst_node,
1834
1835 .@"defer" = .@"defer",1817 .@"defer" = .@"defer",
1836 .defer_err_code = .defer_err_code,1818 .defer_err_code = .defer_err_code,
18371819
...@@ -2074,6 +2056,10 @@ pub const Inst = struct {...@@ -2074,6 +2056,10 @@ pub const Inst = struct {
2074 /// `operand` is payload index to `RestoreErrRetIndex`.2056 /// `operand` is payload index to `RestoreErrRetIndex`.
2075 /// `small` is undefined.2057 /// `small` is undefined.
2076 restore_err_ret_index,2058 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,
2077 /// Used as a placeholder instruction which is just a dummy index for Sema to replace2063 /// Used as a placeholder instruction which is just a dummy index for Sema to replace
2078 /// with a specific value. For instance, this is used for the capture of an `errdefer`.2064 /// with a specific value. For instance, this is used for the capture of an `errdefer`.
2079 /// This should never appear in a body.2065 /// This should never appear in a body.
...@@ -2949,7 +2935,7 @@ pub const Inst = struct {...@@ -2949,7 +2935,7 @@ pub const Inst = struct {
2949 /// These are stored in trailing data in `extra` for each prong.2935 /// These are stored in trailing data in `extra` for each prong.
2950 pub const ProngInfo = packed struct(u32) {2936 pub const ProngInfo = packed struct(u32) {
2951 body_len: u28,2937 body_len: u28,
2952 capture: Capture,2938 capture: ProngInfo.Capture,
2953 is_inline: bool,2939 is_inline: bool,
2954 has_tag_capture: bool,2940 has_tag_capture: bool,
29552941
...@@ -3013,19 +2999,21 @@ pub const Inst = struct {...@@ -3013,19 +2999,21 @@ pub const Inst = struct {
3013 };2999 };
30143000
3015 /// Trailing:3001 /// Trailing:
3016 /// 0. fields_len: u32, // if has_fields_len3002 /// 0. captures_len: u32 // if has_captures_len
3017 /// 1. decls_len: u32, // if has_decls_len3003 /// 1. fields_len: u32, // if has_fields_len
3018 /// 2. backing_int_body_len: u32, // if has_backing_int3004 /// 2. decls_len: u32, // if has_decls_len
3019 /// 3. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 03005 /// 3. capture: Capture // for every captures_len
3020 /// 4. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 03006 /// 4. backing_int_body_len: u32, // if has_backing_int
3021 /// 5. decl: Index, // for every decls_len; points to a `declaration` instruction3007 /// 5. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
3022 /// 6. flags: u32 // for every 8 fields3008 /// 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
3023 /// - sets of 4 bits:3011 /// - sets of 4 bits:
3024 /// 0b000X: whether corresponding field has an align expression3012 /// 0b000X: whether corresponding field has an align expression
3025 /// 0b00X0: whether corresponding field has a default expression3013 /// 0b00X0: whether corresponding field has a default expression
3026 /// 0b0X00: whether corresponding field is comptime3014 /// 0b0X00: whether corresponding field is comptime
3027 /// 0bX000: whether corresponding field has a type expression3015 /// 0bX000: whether corresponding field has a type expression
3028 /// 7. fields: { // for every fields_len3016 /// 9. fields: { // for every fields_len
3029 /// field_name: u32, // if !is_tuple3017 /// field_name: u32, // if !is_tuple
3030 /// doc_comment: NullTerminatedString, // .empty if no doc comment3018 /// doc_comment: NullTerminatedString, // .empty if no doc comment
3031 /// field_type: Ref, // if corresponding bit is not set. none means anytype.3019 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
...@@ -3033,7 +3021,7 @@ pub const Inst = struct {...@@ -3033,7 +3021,7 @@ pub const Inst = struct {
3033 /// align_body_len: u32, // if corresponding bit is set3021 /// align_body_len: u32, // if corresponding bit is set
3034 /// init_body_len: u32, // if corresponding bit is set3022 /// init_body_len: u32, // if corresponding bit is set
3035 /// }3023 /// }
3036 /// 8. bodies: { // for every fields_len3024 /// 10. bodies: { // for every fields_len
3037 /// field_type_body_inst: Inst, // for each field_type_body_len3025 /// field_type_body_inst: Inst, // for each field_type_body_len
3038 /// align_body_inst: Inst, // for each align_body_len3026 /// align_body_inst: Inst, // for each align_body_len
3039 /// init_body_inst: Inst, // for each init_body_len3027 /// init_body_inst: Inst, // for each init_body_len
...@@ -3052,6 +3040,7 @@ pub const Inst = struct {...@@ -3052,6 +3040,7 @@ pub const Inst = struct {
3052 }3040 }
30533041
3054 pub const Small = packed struct {3042 pub const Small = packed struct {
3043 has_captures_len: bool,
3055 has_fields_len: bool,3044 has_fields_len: bool,
3056 has_decls_len: bool,3045 has_decls_len: bool,
3057 has_backing_int: bool,3046 has_backing_int: bool,
...@@ -3063,8 +3052,57 @@ pub const Inst = struct {...@@ -3063,8 +3052,57 @@ pub const Inst = struct {
3063 any_default_inits: bool,3052 any_default_inits: bool,
3064 any_comptime_fields: bool,3053 any_comptime_fields: bool,
3065 any_aligned_fields: bool,3054 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,
3067 };3077 };
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 }
3068 };3106 };
30693107
3070 pub const NameStrategy = enum(u2) {3108 pub const NameStrategy = enum(u2) {
...@@ -3098,14 +3136,16 @@ pub const Inst = struct {...@@ -3098,14 +3136,16 @@ pub const Inst = struct {
30983136
3099 /// Trailing:3137 /// Trailing:
3100 /// 0. tag_type: Ref, // if has_tag_type3138 /// 0. tag_type: Ref, // if has_tag_type
3101 /// 1. body_len: u32, // if has_body_len3139 /// 1. captures_len: u32, // if has_captures_len
3102 /// 2. fields_len: u32, // if has_fields_len3140 /// 2. body_len: u32, // if has_body_len
3103 /// 3. decls_len: u32, // if has_decls_len3141 /// 3. fields_len: u32, // if has_fields_len
3104 /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction3142 /// 4. decls_len: u32, // if has_decls_len
3105 /// 5. inst: Index // for every body_len3143 /// 5. capture: Capture // for every captures_len
3106 /// 6. has_bits: u32 // for every 32 fields3144 /// 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
3107 /// - the bit is whether corresponding field has an value expression3147 /// - the bit is whether corresponding field has an value expression
3108 /// 7. fields: { // for every fields_len3148 /// 9. fields: { // for every fields_len
3109 /// field_name: u32,3149 /// field_name: u32,
3110 /// doc_comment: u32, // .empty if no doc_comment3150 /// doc_comment: u32, // .empty if no doc_comment
3111 /// value: Ref, // if corresponding bit is set3151 /// value: Ref, // if corresponding bit is set
...@@ -3125,29 +3165,32 @@ pub const Inst = struct {...@@ -3125,29 +3165,32 @@ pub const Inst = struct {
31253165
3126 pub const Small = packed struct {3166 pub const Small = packed struct {
3127 has_tag_type: bool,3167 has_tag_type: bool,
3168 has_captures_len: bool,
3128 has_body_len: bool,3169 has_body_len: bool,
3129 has_fields_len: bool,3170 has_fields_len: bool,
3130 has_decls_len: bool,3171 has_decls_len: bool,
3131 name_strategy: NameStrategy,3172 name_strategy: NameStrategy,
3132 nonexhaustive: bool,3173 nonexhaustive: bool,
3133 _: u9 = undefined,3174 _: u8 = undefined,
3134 };3175 };
3135 };3176 };
31363177
3137 /// Trailing:3178 /// Trailing:
3138 /// 0. tag_type: Ref, // if has_tag_type3179 /// 0. tag_type: Ref, // if has_tag_type
3139 /// 1. body_len: u32, // if has_body_len3180 /// 1. captures_len: u32 // if has_captures_len
3140 /// 2. fields_len: u32, // if has_fields_len3181 /// 2. body_len: u32, // if has_body_len
3141 /// 3. decls_len: u32, // if has_decls_len3182 /// 3. fields_len: u32, // if has_fields_len
3142 /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction3183 /// 4. decls_len: u37, // if has_decls_len
3143 /// 5. inst: Index // for every body_len3184 /// 5. capture: Capture // for every captures_len
3144 /// 6. has_bits: u32 // for every 8 fields3185 /// 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
3145 /// - sets of 4 bits:3188 /// - sets of 4 bits:
3146 /// 0b000X: whether corresponding field has a type expression3189 /// 0b000X: whether corresponding field has a type expression
3147 /// 0b00X0: whether corresponding field has a align expression3190 /// 0b00X0: whether corresponding field has a align expression
3148 /// 0b0X00: whether corresponding field has a tag value expression3191 /// 0b0X00: whether corresponding field has a tag value expression
3149 /// 0bX000: unused3192 /// 0bX000: unused
3150 /// 7. fields: { // for every fields_len3193 /// 9. fields: { // for every fields_len
3151 /// field_name: NullTerminatedString, // null terminated string index3194 /// field_name: NullTerminatedString, // null terminated string index
3152 /// doc_comment: NullTerminatedString, // .empty if no doc comment3195 /// doc_comment: NullTerminatedString, // .empty if no doc comment
3153 /// field_type: Ref, // if corresponding bit is set3196 /// field_type: Ref, // if corresponding bit is set
...@@ -3170,6 +3213,7 @@ pub const Inst = struct {...@@ -3170,6 +3213,7 @@ pub const Inst = struct {
31703213
3171 pub const Small = packed struct {3214 pub const Small = packed struct {
3172 has_tag_type: bool,3215 has_tag_type: bool,
3216 has_captures_len: bool,
3173 has_body_len: bool,3217 has_body_len: bool,
3174 has_fields_len: bool,3218 has_fields_len: bool,
3175 has_decls_len: bool,3219 has_decls_len: bool,
...@@ -3183,13 +3227,15 @@ pub const Inst = struct {...@@ -3183,13 +3227,15 @@ pub const Inst = struct {
3183 /// true | false | union(T) { }3227 /// true | false | union(T) { }
3184 auto_enum_tag: bool,3228 auto_enum_tag: bool,
3185 any_aligned_fields: bool,3229 any_aligned_fields: bool,
3186 _: u6 = undefined,3230 _: u5 = undefined,
3187 };3231 };
3188 };3232 };
31893233
3190 /// Trailing:3234 /// Trailing:
3191 /// 0. decls_len: u32, // if has_decls_len3235 /// 0. captures_len: u32, // if has_captures_len
3192 /// 1. decl: Index, // for every decls_len; points to a `declaration` instruction3236 /// 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
3193 pub const OpaqueDecl = struct {3239 pub const OpaqueDecl = struct {
3194 src_node: i32,3240 src_node: i32,
31953241
...@@ -3198,9 +3244,10 @@ pub const Inst = struct {...@@ -3198,9 +3244,10 @@ pub const Inst = struct {
3198 }3244 }
31993245
3200 pub const Small = packed struct {3246 pub const Small = packed struct {
3247 has_captures_len: bool,
3201 has_decls_len: bool,3248 has_decls_len: bool,
3202 name_strategy: NameStrategy,3249 name_strategy: NameStrategy,
3203 _: u13 = undefined,3250 _: u12 = undefined,
3204 };3251 };
3205 };3252 };
32063253
...@@ -3502,6 +3549,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3502,6 +3549,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3502 .struct_decl => {3549 .struct_decl => {
3503 const small: Inst.StructDecl.Small = @bitCast(extended.small);3550 const small: Inst.StructDecl.Small = @bitCast(extended.small);
3504 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).Struct.fields.len);3551 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;
3505 extra_index += @intFromBool(small.has_fields_len);3557 extra_index += @intFromBool(small.has_fields_len);
3506 const decls_len = if (small.has_decls_len) decls_len: {3558 const decls_len = if (small.has_decls_len) decls_len: {
3507 const decls_len = zir.extra[extra_index];3559 const decls_len = zir.extra[extra_index];
...@@ -3509,6 +3561,8 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3509,6 +3561,8 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3509 break :decls_len decls_len;3561 break :decls_len decls_len;
3510 } else 0;3562 } else 0;
35113563
3564 extra_index += captures_len;
3565
3512 if (small.has_backing_int) {3566 if (small.has_backing_int) {
3513 const backing_int_body_len = zir.extra[extra_index];3567 const backing_int_body_len = zir.extra[extra_index];
3514 extra_index += 1; // backing_int_body_len3568 extra_index += 1; // backing_int_body_len
...@@ -3529,6 +3583,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3529,6 +3583,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3529 const small: Inst.EnumDecl.Small = @bitCast(extended.small);3583 const small: Inst.EnumDecl.Small = @bitCast(extended.small);
3530 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).Struct.fields.len);3584 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).Struct.fields.len);
3531 extra_index += @intFromBool(small.has_tag_type);3585 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;
3532 extra_index += @intFromBool(small.has_body_len);3591 extra_index += @intFromBool(small.has_body_len);
3533 extra_index += @intFromBool(small.has_fields_len);3592 extra_index += @intFromBool(small.has_fields_len);
3534 const decls_len = if (small.has_decls_len) decls_len: {3593 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 {...@@ -3537,6 +3596,8 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3537 break :decls_len decls_len;3596 break :decls_len decls_len;
3538 } else 0;3597 } else 0;
35393598
3599 extra_index += captures_len;
3600
3540 return .{3601 return .{
3541 .extra_index = extra_index,3602 .extra_index = extra_index,
3542 .decls_remaining = decls_len,3603 .decls_remaining = decls_len,
...@@ -3547,6 +3608,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3547,6 +3608,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3547 const small: Inst.UnionDecl.Small = @bitCast(extended.small);3608 const small: Inst.UnionDecl.Small = @bitCast(extended.small);
3548 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).Struct.fields.len);3609 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).Struct.fields.len);
3549 extra_index += @intFromBool(small.has_tag_type);3610 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;
3550 extra_index += @intFromBool(small.has_body_len);3616 extra_index += @intFromBool(small.has_body_len);
3551 extra_index += @intFromBool(small.has_fields_len);3617 extra_index += @intFromBool(small.has_fields_len);
3552 const decls_len = if (small.has_decls_len) decls_len: {3618 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 {...@@ -3555,6 +3621,8 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3555 break :decls_len decls_len;3621 break :decls_len decls_len;
3556 } else 0;3622 } else 0;
35573623
3624 extra_index += captures_len;
3625
3558 return .{3626 return .{
3559 .extra_index = extra_index,3627 .extra_index = extra_index,
3560 .decls_remaining = decls_len,3628 .decls_remaining = decls_len,
...@@ -3569,6 +3637,13 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3569,6 +3637,13 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3569 extra_index += 1;3637 extra_index += 1;
3570 break :decls_len decls_len;3638 break :decls_len decls_len;
3571 } else 0;3639 } 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
3573 return .{3648 return .{
3574 .extra_index = extra_index,3649 .extra_index = extra_index,
src/Autodoc.zig+72-24
...@@ -450,7 +450,7 @@ const Scope = struct {...@@ -450,7 +450,7 @@ const Scope = struct {
450 Zir.NullTerminatedString, // index into the current file's string table (decl name)450 Zir.NullTerminatedString, // index into the current file's string table (decl name)
451 *DeclStatus,451 *DeclStatus,
452 ) = .{},452 ) = .{},
453453 captures: []const Zir.Inst.Capture = &.{},
454 enclosing_type: ?usize, // index into `types`, null = file top-level struct454 enclosing_type: ?usize, // index into `types`, null = file top-level struct
455455
456 pub const DeclStatus = union(enum) {456 pub const DeclStatus = union(enum) {
...@@ -459,6 +459,24 @@ const Scope = struct {...@@ -459,6 +459,24 @@ const Scope = struct {
459 NotRequested: u32, // instr_index459 NotRequested: u32, // instr_index
460 };460 };
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
462 /// Returns a pointer so that the caller has a chance to modify the value480 /// Returns a pointer so that the caller has a chance to modify the value
463 /// in case they decide to start analyzing a previously not requested decl.481 /// in case they decide to start analyzing a previously not requested decl.
464 /// Another reason is that in some places we use the pointer to uniquely482 /// Another reason is that in some places we use the pointer to uniquely
...@@ -1151,29 +1169,6 @@ fn walkInstruction(...@@ -1151,29 +1169,6 @@ fn walkInstruction(
1151 .expr = .{ .comptimeExpr = 0 },1169 .expr = .{ .comptimeExpr = 0 },
1152 };1170 };
1153 },1171 },
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 },
1177 .str => {1172 .str => {
1178 const str = data[@intFromEnum(inst)].str.get(file.zir);1173 const str = data[@intFromEnum(inst)].str.get(file.zir);
11791174
...@@ -3395,11 +3390,23 @@ fn walkInstruction(...@@ -3395,11 +3390,23 @@ fn walkInstruction(
3395 .enclosing_type = type_slot_index,3390 .enclosing_type = type_slot_index,
3396 };3391 };
33973392
3393 const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
3398 const extra = file.zir.extraData(Zir.Inst.OpaqueDecl, extended.operand);3394 const extra = file.zir.extraData(Zir.Inst.OpaqueDecl, extended.operand);
3399 var extra_index: usize = extra.end;3395 var extra_index: usize = extra.end;
34003396
3401 const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);3397 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
3403 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};3410 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
3404 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};3411 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
34053412
...@@ -3503,6 +3510,12 @@ fn walkInstruction(...@@ -3503,6 +3510,12 @@ fn walkInstruction(
3503 break :blk tag_ref;3510 break :blk tag_ref;
3504 } else null;3511 } 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
3506 const body_len = if (small.has_body_len) blk: {3519 const body_len = if (small.has_body_len) blk: {
3507 const body_len = file.zir.extra[extra_index];3520 const body_len = file.zir.extra[extra_index];
3508 extra_index += 1;3521 extra_index += 1;
...@@ -3520,6 +3533,11 @@ fn walkInstruction(...@@ -3520,6 +3533,11 @@ fn walkInstruction(
3520 else => .{ .enumLiteral = @tagName(small.layout) },3533 else => .{ .enumLiteral = @tagName(small.layout) },
3521 };3534 };
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
3523 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};3541 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
3524 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};3542 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
35253543
...@@ -3631,6 +3649,12 @@ fn walkInstruction(...@@ -3631,6 +3649,12 @@ fn walkInstruction(
3631 break :blk wr.expr;3649 break :blk wr.expr;
3632 } else null;3650 } 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
3634 const body_len = if (small.has_body_len) blk: {3658 const body_len = if (small.has_body_len) blk: {
3635 const body_len = file.zir.extra[extra_index];3659 const body_len = file.zir.extra[extra_index];
3636 extra_index += 1;3660 extra_index += 1;
...@@ -3643,6 +3667,11 @@ fn walkInstruction(...@@ -3643,6 +3667,11 @@ fn walkInstruction(
3643 break :blk fields_len;3667 break :blk fields_len;
3644 } else 0;3668 } 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
3646 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};3675 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
3647 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};3676 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
36483677
...@@ -3759,6 +3788,12 @@ fn walkInstruction(...@@ -3759,6 +3788,12 @@ fn walkInstruction(
37593788
3760 const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);3789 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
3762 const fields_len = if (small.has_fields_len) blk: {3797 const fields_len = if (small.has_fields_len) blk: {
3763 const fields_len = file.zir.extra[extra_index];3798 const fields_len = file.zir.extra[extra_index];
3764 extra_index += 1;3799 extra_index += 1;
...@@ -3768,6 +3803,9 @@ fn walkInstruction(...@@ -3768,6 +3803,9 @@ fn walkInstruction(
3768 // We don't care about decls yet3803 // We don't care about decls yet
3769 if (small.has_decls_len) extra_index += 1;3804 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
3771 var backing_int: ?DocData.Expr = null;3809 var backing_int: ?DocData.Expr = null;
3772 if (small.has_backing_int) {3810 if (small.has_backing_int) {
3773 const backing_int_body_len = file.zir.extra[extra_index];3811 const backing_int_body_len = file.zir.extra[extra_index];
...@@ -4018,6 +4056,16 @@ fn walkInstruction(...@@ -4018,6 +4056,16 @@ fn walkInstruction(
4018 .expr = .{ .cmpxchgIndex = cmpxchg_index },4056 .expr = .{ .cmpxchgIndex = cmpxchg_index },
4019 };4057 };
4020 },4058 },
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 },
4021 }4069 }
4022 },4070 },
4023 }4071 }
src/Builtin.zig+2
...@@ -264,6 +264,8 @@ pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void {...@@ -264,6 +264,8 @@ pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void {
264 assert(!file.zir.hasCompileErrors()); // builtin.zig must not have astgen errors264 assert(!file.zir.hasCompileErrors()); // builtin.zig must not have astgen errors
265 file.zir_loaded = true;265 file.zir_loaded = true;
266 file.status = .success_zir;266 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`.
267}269}
268270
269fn writeFile(file: *File, mod: *Module) !void {271fn writeFile(file: *File, mod: *Module) !void {
src/Compilation.zig+4
...@@ -1326,6 +1326,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1326,6 +1326,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1326 .global = options.config,1326 .global = options.config,
1327 .parent = options.root_mod,1327 .parent = options.root_mod,
1328 .builtin_mod = options.root_mod.getBuiltinDependency(),1328 .builtin_mod = options.root_mod.getBuiltinDependency(),
1329 .builtin_modules = null, // `builtin_mod` is set
1329 });1330 });
1330 try options.root_mod.deps.putNoClobber(arena, "compiler_rt", compiler_rt_mod);1331 try options.root_mod.deps.putNoClobber(arena, "compiler_rt", compiler_rt_mod);
1331 }1332 }
...@@ -1430,6 +1431,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1430,6 +1431,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1430 .global = options.config,1431 .global = options.config,
1431 .parent = options.root_mod,1432 .parent = options.root_mod,
1432 .builtin_mod = options.root_mod.getBuiltinDependency(),1433 .builtin_mod = options.root_mod.getBuiltinDependency(),
1434 .builtin_modules = null, // `builtin_mod` is set
1433 });1435 });
14341436
1435 const zcu = try arena.create(Module);1437 const zcu = try arena.create(Module);
...@@ -6107,6 +6109,7 @@ fn buildOutputFromZig(...@@ -6107,6 +6109,7 @@ fn buildOutputFromZig(
6107 .cc_argv = &.{},6109 .cc_argv = &.{},
6108 .parent = null,6110 .parent = null,
6109 .builtin_mod = null,6111 .builtin_mod = null,
6112 .builtin_modules = null, // there is only one module in this compilation
6110 });6113 });
6111 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];6114 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
6112 const target = comp.getTarget();6115 const target = comp.getTarget();
...@@ -6219,6 +6222,7 @@ pub fn build_crt_file(...@@ -6219,6 +6222,7 @@ pub fn build_crt_file(
6219 .cc_argv = &.{},6222 .cc_argv = &.{},
6220 .parent = null,6223 .parent = null,
6221 .builtin_mod = null,6224 .builtin_mod = null,
6225 .builtin_modules = null, // there is only one module in this compilation
6222 });6226 });
62236227
6224 for (c_source_files) |*item| {6228 for (c_source_files) |*item| {
src/InternPool.zig+1781-1219
...@@ -1,7 +1,6 @@...@@ -1,7 +1,6 @@
1//! All interned objects have both a value and a type.1//! All interned objects have both a value and a type.
2//! This data structure is self-contained, with the following exceptions:2//! This data structure is self-contained, with the following exceptions:
3//! * Module.Namespace has a pointer to Module.File3//! * Module.Namespace has a pointer to Module.File
4//! * Module.Decl has a pointer to Module.CaptureScope
54
6/// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are5/// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are
7/// constructed lazily.6/// constructed lazily.
...@@ -345,6 +344,7 @@ const KeyAdapter = struct {...@@ -345,6 +344,7 @@ const KeyAdapter = struct {
345344
346 pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool {345 pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool {
347 _ = b_void;346 _ = b_void;
347 if (ctx.intern_pool.items.items(.tag)[b_map_index] == .removed) return false;
348 return ctx.intern_pool.indexToKey(@as(Index, @enumFromInt(b_map_index))).eql(a, ctx.intern_pool);348 return ctx.intern_pool.indexToKey(@as(Index, @enumFromInt(b_map_index))).eql(a, ctx.intern_pool);
349 }349 }
350350
...@@ -502,6 +502,51 @@ pub const OptionalNullTerminatedString = enum(u32) {...@@ -502,6 +502,51 @@ pub const OptionalNullTerminatedString = enum(u32) {
502 }502 }
503};503};
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
505pub const Key = union(enum) {550pub const Key = union(enum) {
506 int_type: IntType,551 int_type: IntType,
507 ptr_type: PtrType,552 ptr_type: PtrType,
...@@ -516,14 +561,14 @@ pub const Key = union(enum) {...@@ -516,14 +561,14 @@ pub const Key = union(enum) {
516 /// This represents a struct that has been explicitly declared in source code,561 /// This represents a struct that has been explicitly declared in source code,
517 /// or was created with `@Type`. It is unique and based on a declaration.562 /// or was created with `@Type`. It is unique and based on a declaration.
518 /// It may be a tuple, if declared like this: `struct {A, B, C}`.563 /// It may be a tuple, if declared like this: `struct {A, B, C}`.
519 struct_type: StructType,564 struct_type: NamespaceType,
520 /// This is an anonymous struct or tuple type which has no corresponding565 /// This is an anonymous struct or tuple type which has no corresponding
521 /// declaration. It is used for types that have no `struct` keyword in the566 /// declaration. It is used for types that have no `struct` keyword in the
522 /// source code, and were not created via `@Type`.567 /// source code, and were not created via `@Type`.
523 anon_struct_type: AnonStructType,568 anon_struct_type: AnonStructType,
524 union_type: Key.UnionType,569 union_type: NamespaceType,
525 opaque_type: OpaqueType,570 opaque_type: NamespaceType,
526 enum_type: EnumType,571 enum_type: NamespaceType,
527 func_type: FuncType,572 func_type: FuncType,
528 error_set_type: ErrorSetType,573 error_set_type: ErrorSetType,
529 /// The payload is the function body, either a `func_decl` or `func_instance`.574 /// The payload is the function body, either a `func_decl` or `func_instance`.
...@@ -645,348 +690,6 @@ pub const Key = union(enum) {...@@ -645,348 +690,6 @@ pub const Key = union(enum) {
645 child: Index,690 child: Index,
646 };691 };
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
990 pub const AnonStructType = struct {693 pub const AnonStructType = struct {
991 types: Index.Slice,694 types: Index.Slice,
992 /// This may be empty, indicating this is a tuple.695 /// This may be empty, indicating this is a tuple.
...@@ -1010,192 +713,41 @@ pub const Key = union(enum) {...@@ -1010,192 +713,41 @@ pub const Key = union(enum) {
1010 }713 }
1011 };714 };
1012715
1013 /// Serves two purposes:716 /// This is the hashmap key. To fetch other data associated with the type, see:
1014 /// * Being the key in the InternPool hash map, which only requires the `decl` field.717 /// * `loadStructType`
1015 /// * Provide the other fields that do not require chasing the enum type.718 /// * `loadUnionType`
1016 pub const UnionType = struct {719 /// * `loadEnumType`
1017 /// The Decl that corresponds to the union itself.720 /// * `loadOpaqueType`
1018 decl: DeclIndex,721 pub const NamespaceType = union(enum) {
1019 /// The index of the `Tag.TypeUnion` payload. Ignored by `get`,722 /// This type corresponds to an actual source declaration, e.g. `struct { ... }`.
1020 /// populated by `indexToKey`.723 /// It is hashed based on its ZIR instruction index and set of captures.
1021 extra_index: u32,724 declared: struct {
1022 namespace: NamespaceIndex,725 /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction.
1023 flags: Tag.TypeUnion.Flags,726 zir_index: TrackedInst.Index,
1024 /// The enum that provides the list of field names and values.727 /// The captured values of this type. These values must be fully resolved per the language spec.
1025 enum_tag_ty: Index,728 captures: union(enum) {
1026 zir_index: TrackedInst.Index.Optional,729 owned: CaptureValue.Slice,
1027730 external: []const CaptureValue,
1028 /// The returned pointer expires with any addition to the `InternPool`.731 },
1029 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeUnion.Flags {732 },
1030 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;733 /// This type is an automatically-generated enum tag type for a union.
1031 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);734 /// It is hashed based on the index of the union type it corresponds to.
1032 }735 generated_tag: struct {
1033736 /// The union for which this is a tag type.
1034 /// The returned pointer expires with any addition to the `InternPool`.737 union_type: Index,
1035 pub fn size(self: @This(), ip: *InternPool) *u32 {738 },
1036 const size_field_index = std.meta.fieldIndex(Tag.TypeUnion, "size").?;739 /// This type originates from a reification via `@Type`.
1037 return &ip.extra.items[self.extra_index + size_field_index];740 /// It is hased based on its ZIR instruction index and fields, attributes, etc.
1038 }741 /// To avoid making this key overly complex, the type-specific data is hased by Sema.
1039742 reified: struct {
1040 /// The returned pointer expires with any addition to the `InternPool`.743 /// A `reify` instruction.
1041 pub fn padding(self: @This(), ip: *InternPool) *u32 {744 zir_index: TrackedInst.Index,
1042 const padding_field_index = std.meta.fieldIndex(Tag.TypeUnion, "padding").?;745 /// A hash of this type's attributes, fields, etc, generated by Sema.
1043 return &ip.extra.items[self.extra_index + padding_field_index];746 type_hash: u64,
1044 }747 },
1045748 /// This type is `@TypeOf(.{})`.
1046 pub fn haveFieldTypes(self: @This(), ip: *const InternPool) bool {749 /// TODO: can we change the language spec to not special-case this type?
1047 return self.flagsPtr(ip).status.haveFieldTypes();750 empty_struct: void,
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 }
1199 };751 };
1200752
1201 pub const FuncType = struct {753 pub const FuncType = struct {
...@@ -1546,12 +1098,37 @@ pub const Key = union(enum) {...@@ -1546,12 +1098,37 @@ pub const Key = union(enum) {
1546 .payload => |y| Hash.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)),1098 .payload => |y| Hash.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)),
1547 },1099 },
15481100
1549 inline .opaque_type,1101 .variable => |variable| Hash.hash(seed, asBytes(&variable.decl)),
1102
1103 .opaque_type,
1550 .enum_type,1104 .enum_type,
1551 .variable,
1552 .union_type,1105 .union_type,
1553 .struct_type,1106 .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
1556 .int => |int| {1133 .int => |int| {
1557 var hasher = Hash.init(seed);1134 var hasher = Hash.init(seed);
...@@ -1956,21 +1533,31 @@ pub const Key = union(enum) {...@@ -1956,21 +1533,31 @@ pub const Key = union(enum) {
1956 }1533 }
1957 },1534 },
19581535
1959 .opaque_type => |a_info| {1536 inline .opaque_type, .enum_type, .union_type, .struct_type => |a_info, a_tag_ct| {
1960 const b_info = b.opaque_type;1537 const b_info = @field(b, @tagName(a_tag_ct));
1961 return a_info.decl == b_info.decl;1538 if (std.meta.activeTag(a_info) != b_info) return false;
1962 },1539 switch (a_info) {
1963 .enum_type => |a_info| {1540 .declared => |a_d| {
1964 const b_info = b.enum_type;1541 const b_d = b_info.declared;
1965 return a_info.decl == b_info.decl;1542 if (a_d.zir_index != b_d.zir_index) return false;
1966 },1543 const a_captures = switch (a_d.captures) {
1967 .union_type => |a_info| {1544 .owned => |s| s.get(ip),
1968 const b_info = b.union_type;1545 .external => |cvs| cvs,
1969 return a_info.decl == b_info.decl;1546 };
1970 },1547 const b_captures = switch (b_d.captures) {
1971 .struct_type => |a_info| {1548 .owned => |s| s.get(ip),
1972 const b_info = b.struct_type;1549 .external => |cvs| cvs,
1973 return a_info.decl == b_info.decl;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 }
1974 },1561 },
1975 .aggregate => |a_info| {1562 .aggregate => |a_info| {
1976 const b_info = b.aggregate;1563 const b_info = b.aggregate;
...@@ -2112,21 +1699,15 @@ pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };...@@ -2112,21 +1699,15 @@ pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };
2112// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a1699// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a
2113// minimal hashmap key, this type is a convenience type that contains info1700// minimal hashmap key, this type is a convenience type that contains info
2114// needed by semantic analysis.1701// needed by semantic analysis.
2115pub const UnionType = struct {1702pub const LoadedUnionType = struct {
1703 /// The index of the `Tag.TypeUnion` payload.
1704 extra_index: u32,
2116 /// The Decl that corresponds to the union itself.1705 /// The Decl that corresponds to the union itself.
2117 decl: DeclIndex,1706 decl: DeclIndex,
2118 /// Represents the declarations inside this union.1707 /// Represents the declarations inside this union.
2119 namespace: NamespaceIndex,1708 namespace: OptionalNamespaceIndex,
2120 /// The enum tag type.1709 /// The enum tag type.
2121 enum_tag_ty: Index,1710 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,
2130 /// List of field types in declaration order.1711 /// List of field types in declaration order.
2131 /// These are `none` until `status` is `have_field_types` or `have_layout`.1712 /// These are `none` until `status` is `have_field_types` or `have_layout`.
2132 field_types: Index.Slice,1713 field_types: Index.Slice,
...@@ -2134,12 +1715,9 @@ pub const UnionType = struct {...@@ -2134,12 +1715,9 @@ pub const UnionType = struct {
2134 /// `none` means the ABI alignment of the type.1715 /// `none` means the ABI alignment of the type.
2135 /// If this slice has length 0 it means all elements are `none`.1716 /// If this slice has length 0 it means all elements are `none`.
2136 field_aligns: Alignment.Slice,1717 field_aligns: Alignment.Slice,
2137 /// Index of the union_decl ZIR instruction.1718 /// Index of the union_decl or reify ZIR instruction.
2138 zir_index: TrackedInst.Index.Optional,1719 zir_index: TrackedInst.Index,
2139 /// Index into extra array of the `flags` field.1720 captures: CaptureValue.Slice,
2140 flags_index: u32,
2141 /// Copied from `enum_tag_ty`.
2142 names_map: OptionalMapIndex,
21431721
2144 pub const RuntimeTag = enum(u2) {1722 pub const RuntimeTag = enum(u2) {
2145 none,1723 none,
...@@ -2154,118 +1732,823 @@ pub const UnionType = struct {...@@ -2154,118 +1732,823 @@ pub const UnionType = struct {
2154 }1732 }
2155 };1733 };
21561734
2157 pub const Status = enum(u3) {1735 pub const Status = enum(u3) {
2158 none,1736 none,
2159 field_types_wip,1737 field_types_wip,
2160 have_field_types,1738 have_field_types,
2161 layout_wip,1739 layout_wip,
2162 have_layout,1740 have_layout,
2163 fully_resolved_wip,1741 fully_resolved_wip,
2164 /// The types and all its fields have had their layout resolved.1742 /// The types and all its fields have had their layout resolved.
2165 /// Even through pointer, which `have_layout` does not ensure.1743 /// Even through pointer, which `have_layout` does not ensure.
2166 fully_resolved,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 {2098 pub fn setInitsWip(s: @This(), ip: *InternPool) bool {
2169 return switch (status) {2099 switch (s.layout) {
2170 .none,2100 .Packed => {
2171 .field_types_wip,2101 const flag = &s.packedFlagsPtr(ip).field_inits_wip;
2172 => false,2102 if (flag.*) return true;
2173 .have_field_types,2103 flag.* = true;
2174 .layout_wip,2104 return false;
2175 .have_layout,2105 },
2176 .fully_resolved_wip,2106 .Auto, .Extern => {
2177 .fully_resolved,2107 const flag = &s.flagsPtr(ip).field_inits_wip;
2178 => true,2108 if (flag.*) return true;
2179 };2109 flag.* = true;
2110 return false;
2111 },
2180 }2112 }
2113 }
21812114
2182 pub fn haveLayout(status: Status) bool {2115 pub fn clearInitsWip(s: @This(), ip: *InternPool) void {
2183 return switch (status) {2116 switch (s.layout) {
2184 .none,2117 .Packed => s.packedFlagsPtr(ip).field_inits_wip = false,
2185 .field_types_wip,2118 .Auto, .Extern => s.flagsPtr(ip).field_inits_wip = false,
2186 .have_field_types,
2187 .layout_wip,
2188 => false,
2189 .have_layout,
2190 .fully_resolved_wip,
2191 .fully_resolved,
2192 => true,
2193 };
2194 }2119 }
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
2197 /// The returned pointer expires with any addition to the `InternPool`.2134 /// The returned pointer expires with any addition to the `InternPool`.
2198 pub fn flagsPtr(self: UnionType, ip: *const InternPool) *Tag.TypeUnion.Flags {2135 /// Asserts the struct is not packed.
2199 return @ptrCast(&ip.extra.items[self.flags_index]);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]);
2200 }2140 }
22012141
2202 /// Look up field index based on field name.2142 /// The backing integer type of the packed struct. Whether zig chooses
2203 pub fn nameIndex(self: UnionType, ip: *const InternPool, name: NullTerminatedString) ?u32 {2143 /// this type or the user specifies it, it is stored here. This will be
2204 const map = &ip.maps.items[@intFromEnum(self.names_map.unwrap().?)];2144 /// set to `none` until the layout is resolved.
2205 const adapter: NullTerminatedString.Adapter = .{ .strings = self.field_names.get(ip) };2145 /// Asserts the struct is packed.
2206 const field_index = map.getIndexAdapted(name, adapter) orelse return null;2146 pub fn backingIntType(s: @This(), ip: *const InternPool) *Index {
2207 return @intCast(field_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]);
2208 }2150 }
22092151
2210 pub fn hasTag(self: UnionType, ip: *const InternPool) bool {2152 /// Asserts the struct is not packed.
2211 return self.flagsPtr(ip).runtime_tag.hasTag();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);
2212 }2157 }
22132158
2214 pub fn haveFieldTypes(self: UnionType, ip: *const InternPool) bool {2159 pub fn haveFieldTypes(s: @This(), ip: *const InternPool) bool {
2215 return self.flagsPtr(ip).status.haveFieldTypes();2160 const types = s.field_types.get(ip);
2161 return types.len == 0 or types[0] != .none;
2216 }2162 }
22172163
2218 pub fn haveLayout(self: UnionType, ip: *const InternPool) bool {2164 pub fn haveFieldInits(s: @This(), ip: *const InternPool) bool {
2219 return self.flagsPtr(ip).status.haveLayout();2165 return switch (s.layout) {
2166 .Packed => s.packedFlagsPtr(ip).inits_resolved,
2167 .Auto, .Extern => s.flagsPtr(ip).inits_resolved,
2168 };
2220 }2169 }
22212170
2222 pub fn getLayout(self: UnionType, ip: *const InternPool) std.builtin.Type.ContainerLayout {2171 pub fn setHaveFieldInits(s: @This(), ip: *InternPool) void {
2223 return self.flagsPtr(ip).layout;2172 switch (s.layout) {
2173 .Packed => s.packedFlagsPtr(ip).inits_resolved = true,
2174 .Auto, .Extern => s.flagsPtr(ip).inits_resolved = true,
2175 }
2224 }2176 }
22252177
2226 pub fn fieldAlign(self: UnionType, ip: *const InternPool, field_index: u32) Alignment {2178 pub fn haveLayout(s: @This(), ip: *InternPool) bool {
2227 if (self.field_aligns.len == 0) return .none;2179 return switch (s.layout) {
2228 return self.field_aligns.get(ip)[field_index];2180 .Packed => s.backingIntType(ip).* != .none,
2181 .Auto, .Extern => s.flagsPtr(ip).layout_resolved,
2182 };
2229 }2183 }
22302184
2231 /// This does not mutate the field of UnionType.2185 pub fn isTuple(s: @This(), ip: *InternPool) bool {
2232 pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {2186 return s.layout != .Packed and s.flagsPtr(ip).is_tuple;
2233 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;2187 }
2234 const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;2188
2235 const ptr: *TrackedInst.Index.Optional =2189 pub fn hasReorderedFields(s: @This()) bool {
2236 @ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]);2190 return s.layout == .Auto;
2237 ptr.* = new_zir_index;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 };
2238 }2230 }
2239};2231};
22402232
2241/// Fetch all the interesting fields of a union type into a convenient data2233pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
2242/// structure.2234 const item = ip.items.get(@intFromEnum(index));
2243/// This asserts that the union's enum tag type has been resolved.2235 switch (item.tag) {
2244pub fn loadUnionType(ip: *InternPool, key: Key.UnionType) UnionType {2236 .type_struct => {
2245 const type_union = ip.extraDataTrail(Tag.TypeUnion, key.extra_index);2237 if (item.data == 0) return .{
2246 const enum_ty = type_union.data.tag_ty;2238 .extra_index = 0,
2247 const enum_info = ip.indexToKey(enum_ty).enum_type;2239 .decl = .none,
2248 const fields_len: u32 = @intCast(enum_info.names.len);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;
2250 return .{2502 return .{
2251 .decl = type_union.data.decl,2503 .decl = extra.data.decl,
2252 .namespace = type_union.data.namespace,2504 .namespace = extra.data.namespace,
2253 .enum_tag_ty = enum_ty,2505 .tag_ty = extra.data.int_tag_type,
2254 .int_tag_ty = enum_info.tag_ty,2506 .names = .{
2255 .size = type_union.data.size,2507 .start = extra_index + captures_len,
2256 .padding = type_union.data.padding,2508 .len = extra.data.fields_len,
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,
2262 },2509 },
2263 .field_aligns = .{2510 .values = .{
2264 .start = type_union.end + fields_len,2511 .start = extra_index + captures_len + extra.data.fields_len,
2265 .len = if (type_union.data.flags.any_aligned_fields) fields_len else 0,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,
2266 },2551 },
2267 .zir_index = type_union.data.zir_index,
2268 .flags_index = key.extra_index + std.meta.fieldIndex(Tag.TypeUnion, "flags").?,
2269 };2552 };
2270}2553}
22712554
...@@ -2457,6 +2740,7 @@ pub const Index = enum(u32) {...@@ -2457,6 +2740,7 @@ pub const Index = enum(u32) {
2457 },2740 },
2458 };2741 };
24592742
2743 removed: void,
2460 type_int_signed: struct { data: u32 },2744 type_int_signed: struct { data: u32 },
2461 type_int_unsigned: struct { data: u32 },2745 type_int_unsigned: struct { data: u32 },
2462 type_array_big: struct { data: *Array },2746 type_array_big: struct { data: *Array },
...@@ -2484,9 +2768,8 @@ pub const Index = enum(u32) {...@@ -2484,9 +2768,8 @@ pub const Index = enum(u32) {
2484 type_enum_explicit: DataIsExtraIndexOfEnumExplicit,2768 type_enum_explicit: DataIsExtraIndexOfEnumExplicit,
2485 type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit,2769 type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit,
2486 simple_type: struct { data: SimpleType },2770 simple_type: struct { data: SimpleType },
2487 type_opaque: struct { data: *Key.OpaqueType },2771 type_opaque: struct { data: *Tag.TypeOpaque },
2488 type_struct: struct { data: *Tag.TypeStruct },2772 type_struct: struct { data: *Tag.TypeStruct },
2489 type_struct_ns: struct { data: NamespaceIndex },
2490 type_struct_anon: DataIsExtraIndexOfTypeStructAnon,2773 type_struct_anon: DataIsExtraIndexOfTypeStructAnon,
2491 type_struct_packed: struct { data: *Tag.TypeStructPacked },2774 type_struct_packed: struct { data: *Tag.TypeStructPacked },
2492 type_struct_packed_inits: struct { data: *Tag.TypeStructPacked },2775 type_struct_packed_inits: struct { data: *Tag.TypeStructPacked },
...@@ -2865,6 +3148,12 @@ comptime {...@@ -2865,6 +3148,12 @@ comptime {
2865}3148}
28663149
2867pub const Tag = enum(u8) {3150pub 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
2868 /// An integer type.3157 /// An integer type.
2869 /// data is number of bits3158 /// data is number of bits
2870 type_int_signed,3159 type_int_signed,
...@@ -2920,15 +3209,12 @@ pub const Tag = enum(u8) {...@@ -2920,15 +3209,12 @@ pub const Tag = enum(u8) {
2920 /// data is SimpleType enum value.3209 /// data is SimpleType enum value.
2921 simple_type,3210 simple_type,
2922 /// An opaque type.3211 /// An opaque type.
2923 /// data is index of Key.OpaqueType in extra.3212 /// data is index of Tag.TypeOpaque in extra.
2924 type_opaque,3213 type_opaque,
2925 /// A non-packed struct type.3214 /// A non-packed struct type.
2926 /// data is 0 or extra index of `TypeStruct`.3215 /// data is 0 or extra index of `TypeStruct`.
2927 /// data == 0 represents `@TypeOf(.{})`.3216 /// data == 0 represents `@TypeOf(.{})`.
2928 type_struct,3217 type_struct,
2929 /// A non-packed struct type that has only a namespace; no fields.
2930 /// data is NamespaceIndex.
2931 type_struct_ns,
2932 /// An AnonStructType which stores types, names, and values for fields.3218 /// An AnonStructType which stores types, names, and values for fields.
2933 /// data is extra index of `TypeStructAnon`.3219 /// data is extra index of `TypeStructAnon`.
2934 type_struct_anon,3220 type_struct_anon,
...@@ -3126,7 +3412,6 @@ pub const Tag = enum(u8) {...@@ -3126,7 +3412,6 @@ pub const Tag = enum(u8) {
3126 memoized_call,3412 memoized_call,
31273413
3128 const ErrorUnionType = Key.ErrorUnionType;3414 const ErrorUnionType = Key.ErrorUnionType;
3129 const OpaqueType = Key.OpaqueType;
3130 const TypeValue = Key.TypeValue;3415 const TypeValue = Key.TypeValue;
3131 const Error = Key.Error;3416 const Error = Key.Error;
3132 const EnumTag = Key.EnumTag;3417 const EnumTag = Key.EnumTag;
...@@ -3136,6 +3421,7 @@ pub const Tag = enum(u8) {...@@ -3136,6 +3421,7 @@ pub const Tag = enum(u8) {
31363421
3137 fn Payload(comptime tag: Tag) type {3422 fn Payload(comptime tag: Tag) type {
3138 return switch (tag) {3423 return switch (tag) {
3424 .removed => unreachable,
3139 .type_int_signed => unreachable,3425 .type_int_signed => unreachable,
3140 .type_int_unsigned => unreachable,3426 .type_int_unsigned => unreachable,
3141 .type_array_big => Array,3427 .type_array_big => Array,
...@@ -3153,9 +3439,8 @@ pub const Tag = enum(u8) {...@@ -3153,9 +3439,8 @@ pub const Tag = enum(u8) {
3153 .type_enum_explicit => EnumExplicit,3439 .type_enum_explicit => EnumExplicit,
3154 .type_enum_nonexhaustive => EnumExplicit,3440 .type_enum_nonexhaustive => EnumExplicit,
3155 .simple_type => unreachable,3441 .simple_type => unreachable,
3156 .type_opaque => OpaqueType,3442 .type_opaque => TypeOpaque,
3157 .type_struct => TypeStruct,3443 .type_struct => TypeStruct,
3158 .type_struct_ns => unreachable,
3159 .type_struct_anon => TypeStructAnon,3444 .type_struct_anon => TypeStructAnon,
3160 .type_struct_packed, .type_struct_packed_inits => TypeStructPacked,3445 .type_struct_packed, .type_struct_packed_inits => TypeStructPacked,
3161 .type_tuple_anon => TypeStructAnon,3446 .type_tuple_anon => TypeStructAnon,
...@@ -3311,43 +3596,54 @@ pub const Tag = enum(u8) {...@@ -3311,43 +3596,54 @@ pub const Tag = enum(u8) {
3311 };3596 };
3312 };3597 };
33133598
3314 /// The number of fields is provided by the `tag_ty` field.
3315 /// Trailing:3599 /// Trailing:
3316 /// 0. field type: Index for each field; declaration order3600 /// 0. captures_len: u32 // if `any_captures`
3317 /// 1. field align: Alignment for each field; declaration order3601 /// 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
3318 pub const TypeUnion = struct {3605 pub const TypeUnion = struct {
3319 flags: Flags,3606 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,
3320 /// Only valid after .have_layout3611 /// Only valid after .have_layout
3321 size: u32,3612 size: u32,
3322 /// Only valid after .have_layout3613 /// Only valid after .have_layout
3323 padding: u32,3614 padding: u32,
3324 decl: DeclIndex,3615 decl: DeclIndex,
3325 namespace: NamespaceIndex,3616 namespace: OptionalNamespaceIndex,
3326 /// The enum that provides the list of field names and values.3617 /// The enum that provides the list of field names and values.
3327 tag_ty: Index,3618 tag_ty: Index,
3328 zir_index: TrackedInst.Index.Optional,3619 zir_index: TrackedInst.Index,
33293620
3330 pub const Flags = packed struct(u32) {3621 pub const Flags = packed struct(u32) {
3331 runtime_tag: UnionType.RuntimeTag,3622 any_captures: bool,
3623 runtime_tag: LoadedUnionType.RuntimeTag,
3332 /// If false, the field alignment trailing data is omitted.3624 /// If false, the field alignment trailing data is omitted.
3333 any_aligned_fields: bool,3625 any_aligned_fields: bool,
3334 layout: std.builtin.Type.ContainerLayout,3626 layout: std.builtin.Type.ContainerLayout,
3335 status: UnionType.Status,3627 status: LoadedUnionType.Status,
3336 requires_comptime: RequiresComptime,3628 requires_comptime: RequiresComptime,
3337 assumed_runtime_bits: bool,3629 assumed_runtime_bits: bool,
3338 assumed_pointer_aligned: bool,3630 assumed_pointer_aligned: bool,
3339 alignment: Alignment,3631 alignment: Alignment,
3340 _: u14 = 0,3632 is_reified: bool,
3633 _: u12 = 0,
3341 };3634 };
3342 };3635 };
33433636
3344 /// Trailing:3637 /// Trailing:
3345 /// 0. type: Index for each fields_len3638 /// 0. captures_len: u32 // if `any_captures`
3346 /// 1. name: NullTerminatedString for each fields_len3639 /// 1. capture: CaptureValue // for each `captures_len`
3347 /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits3640 /// 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
3348 pub const TypeStructPacked = struct {3644 pub const TypeStructPacked = struct {
3349 decl: DeclIndex,3645 decl: DeclIndex,
3350 zir_index: TrackedInst.Index.Optional,3646 zir_index: TrackedInst.Index,
3351 fields_len: u32,3647 fields_len: u32,
3352 namespace: OptionalNamespaceIndex,3648 namespace: OptionalNamespaceIndex,
3353 backing_int_ty: Index,3649 backing_int_ty: Index,
...@@ -3355,10 +3651,12 @@ pub const Tag = enum(u8) {...@@ -3355,10 +3651,12 @@ pub const Tag = enum(u8) {
3355 flags: Flags,3651 flags: Flags,
33563652
3357 pub const Flags = packed struct(u32) {3653 pub const Flags = packed struct(u32) {
3654 any_captures: bool,
3358 /// Dependency loop detection when resolving field inits.3655 /// Dependency loop detection when resolving field inits.
3359 field_inits_wip: bool,3656 field_inits_wip: bool,
3360 inits_resolved: bool,3657 inits_resolved: bool,
3361 _: u30 = 0,3658 is_reified: bool,
3659 _: u28 = 0,
3362 };3660 };
3363 };3661 };
33643662
...@@ -3377,29 +3675,33 @@ pub const Tag = enum(u8) {...@@ -3377,29 +3675,33 @@ pub const Tag = enum(u8) {
3377 /// than coming up with some other scheme for the data.3675 /// than coming up with some other scheme for the data.
3378 ///3676 ///
3379 /// Trailing:3677 /// Trailing:
3380 /// 0. type: Index for each field in declared order3678 /// 0. captures_len: u32 // if `any_captures`
3381 /// 1. if not is_tuple: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:
3382 /// names_map: MapIndex,3683 /// names_map: MapIndex,
3383 /// name: NullTerminatedString // for each field in declared order3684 /// name: NullTerminatedString // for each field in declared order
3384 /// 2. if any_default_inits:3685 /// 5. if any_default_inits:
3385 /// init: Index // for each field in declared order3686 /// init: Index // for each field in declared order
3386 /// 3. if has_namespace:3687 /// 6. if has_namespace:
3387 /// namespace: NamespaceIndex3688 /// namespace: NamespaceIndex
3388 /// 4. if any_aligned_fields:3689 /// 7. if any_aligned_fields:
3389 /// align: Alignment // for each field in declared order3690 /// align: Alignment // for each field in declared order
3390 /// 5. if any_comptime_fields:3691 /// 8. if any_comptime_fields:
3391 /// field_is_comptime_bits: u32 // minimal number of u32s needed, LSB is field 03692 /// 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:
3393 /// field_index: RuntimeOrder // for each field in runtime order3694 /// field_index: RuntimeOrder // for each field in runtime order
3394 /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved3695 /// 10. field_offset: u32 // for each field in declared order, undef until layout_resolved
3395 pub const TypeStruct = struct {3696 pub const TypeStruct = struct {
3396 decl: DeclIndex,3697 decl: DeclIndex,
3397 zir_index: TrackedInst.Index.Optional,3698 zir_index: TrackedInst.Index,
3398 fields_len: u32,3699 fields_len: u32,
3399 flags: Flags,3700 flags: Flags,
3400 size: u32,3701 size: u32,
34013702
3402 pub const Flags = packed struct(u32) {3703 pub const Flags = packed struct(u32) {
3704 any_captures: bool,
3403 is_extern: bool,3705 is_extern: bool,
3404 known_non_opv: bool,3706 known_non_opv: bool,
3405 requires_comptime: RequiresComptime,3707 requires_comptime: RequiresComptime,
...@@ -3428,10 +3730,23 @@ pub const Tag = enum(u8) {...@@ -3428,10 +3730,23 @@ pub const Tag = enum(u8) {
3428 // The types and all its fields have had their layout resolved. Even through pointer,3730 // The types and all its fields have had their layout resolved. Even through pointer,
3429 // which `layout_resolved` does not ensure.3731 // which `layout_resolved` does not ensure.
3430 fully_resolved: bool,3732 fully_resolved: bool,
34313733 is_reified: bool,
3432 _: u8 = 0,3734 _: u6 = 0,
3433 };3735 };
3434 };3736 };
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 };
3435};3750};
34363751
3437/// State that is mutable during semantic analysis. This data is not used for3752/// State that is mutable during semantic analysis. This data is not used for
...@@ -3738,11 +4053,16 @@ pub const Array = struct {...@@ -3738,11 +4053,16 @@ pub const Array = struct {
3738};4053};
37394054
3740/// Trailing:4055/// Trailing:
3741/// 0. field name: NullTerminatedString for each fields_len; declaration order4056/// 0. owner_union: Index // if `zir_index == .none`
3742/// 1. tag value: Index for each fields_len; declaration order4057/// 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
3743pub const EnumExplicit = struct {4061pub const EnumExplicit = struct {
3744 /// The Decl that corresponds to the enum itself.4062 /// The Decl that corresponds to the enum itself.
3745 decl: DeclIndex,4063 decl: DeclIndex,
4064 /// `std.math.maxInt(u32)` indicates this type is reified.
4065 captures_len: u32,
3746 /// This may be `none` if there are no declarations.4066 /// This may be `none` if there are no declarations.
3747 namespace: OptionalNamespaceIndex,4067 namespace: OptionalNamespaceIndex,
3748 /// An integer type which is used for the numerical value of the enum, which4068 /// An integer type which is used for the numerical value of the enum, which
...@@ -3755,14 +4075,21 @@ pub const EnumExplicit = struct {...@@ -3755,14 +4075,21 @@ pub const EnumExplicit = struct {
3755 /// If this is `none`, it means the trailing tag values are absent because4075 /// If this is `none`, it means the trailing tag values are absent because
3756 /// they are auto-numbered.4076 /// they are auto-numbered.
3757 values_map: OptionalMapIndex,4077 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.
3758 zir_index: TrackedInst.Index.Optional,4080 zir_index: TrackedInst.Index.Optional,
3759};4081};
37604082
3761/// Trailing:4083/// Trailing:
3762/// 0. field name: NullTerminatedString for each fields_len; declaration order4084/// 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
3763pub const EnumAuto = struct {4088pub const EnumAuto = struct {
3764 /// The Decl that corresponds to the enum itself.4089 /// The Decl that corresponds to the enum itself.
3765 decl: DeclIndex,4090 decl: DeclIndex,
4091 /// `std.math.maxInt(u32)` indicates this type is reified.
4092 captures_len: u32,
3766 /// This may be `none` if there are no declarations.4093 /// This may be `none` if there are no declarations.
3767 namespace: OptionalNamespaceIndex,4094 namespace: OptionalNamespaceIndex,
3768 /// An integer type which is used for the numerical value of the enum, which4095 /// An integer type which is used for the numerical value of the enum, which
...@@ -3771,6 +4098,8 @@ pub const EnumAuto = struct {...@@ -3771,6 +4098,8 @@ pub const EnumAuto = struct {
3771 fields_len: u32,4098 fields_len: u32,
3772 /// Maps field names to declaration index.4099 /// Maps field names to declaration index.
3773 names_map: MapIndex,4100 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.
3774 zir_index: TrackedInst.Index.Optional,4103 zir_index: TrackedInst.Index.Optional,
3775};4104};
37764105
...@@ -4011,6 +4340,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -4011,6 +4340,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
4011 const item = ip.items.get(@intFromEnum(index));4340 const item = ip.items.get(@intFromEnum(index));
4012 const data = item.data;4341 const data = item.data;
4013 return switch (item.tag) {4342 return switch (item.tag) {
4343 .removed => unreachable,
4014 .type_int_signed => .{4344 .type_int_signed => .{
4015 .int_type = .{4345 .int_type = .{
4016 .signedness = .signed,4346 .signedness = .signed,
...@@ -4072,68 +4402,124 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -4072,68 +4402,124 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
4072 .inferred_error_set_type = @enumFromInt(data),4402 .inferred_error_set_type = @enumFromInt(data),
4073 },4403 },
40744404
4075 .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) },4405 .type_opaque => .{ .opaque_type = ns: {
40764406 const extra = ip.extraDataTrail(Tag.TypeOpaque, data);
4077 .type_struct => .{ .struct_type = if (data == 0) .{4407 if (extra.data.captures_len == std.math.maxInt(u32)) {
4078 .extra_index = 0,4408 break :ns .{ .reified = .{
4079 .namespace = .none,4409 .zir_index = extra.data.zir_index,
4080 .decl = .none,4410 .type_hash = 0,
4081 .zir_index = undefined,4411 } };
4082 .layout = .Auto,4412 }
4083 .field_names = .{ .start = 0, .len = 0 },4413 break :ns .{ .declared = .{
4084 .field_types = .{ .start = 0, .len = 0 },4414 .zir_index = extra.data.zir_index,
4085 .field_inits = .{ .start = 0, .len = 0 },4415 .captures = .{ .owned = .{
4086 .field_aligns = .{ .start = 0, .len = 0 },4416 .start = extra.end,
4087 .runtime_order = .{ .start = 0, .len = 0 },4417 .len = extra.data.captures_len,
4088 .comptime_bits = .{ .start = 0, .len = 0 },4418 } },
4089 .offsets = .{ .start = 0, .len = 0 },4419 } };
4090 .names_map = undefined,4420 } },
4091 } else extraStructType(ip, data) },4421
40924422 .type_struct => .{ .struct_type = ns: {
4093 .type_struct_ns => .{ .struct_type = .{4423 if (data == 0) break :ns .empty_struct;
4094 .extra_index = 0,4424 const extra = ip.extraDataTrail(Tag.TypeStruct, data);
4095 .namespace = @as(NamespaceIndex, @enumFromInt(data)).toOptional(),4425 if (extra.data.flags.is_reified) {
4096 .decl = .none,4426 assert(!extra.data.flags.any_captures);
4097 .zir_index = undefined,4427 break :ns .{ .reified = .{
4098 .layout = .Auto,4428 .zir_index = extra.data.zir_index,
4099 .field_names = .{ .start = 0, .len = 0 },4429 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4100 .field_types = .{ .start = 0, .len = 0 },4430 } };
4101 .field_inits = .{ .start = 0, .len = 0 },4431 }
4102 .field_aligns = .{ .start = 0, .len = 0 },4432 break :ns .{ .declared = .{
4103 .runtime_order = .{ .start = 0, .len = 0 },4433 .zir_index = extra.data.zir_index,
4104 .comptime_bits = .{ .start = 0, .len = 0 },4434 .captures = .{ .owned = if (extra.data.flags.any_captures) .{
4105 .offsets = .{ .start = 0, .len = 0 },4435 .start = extra.end + 1,
4106 .names_map = undefined,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 } };
4107 } },4457 } },
41084458
4109 .type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(ip, data) },4459 .type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(ip, data) },
4110 .type_tuple_anon => .{ .anon_struct_type = extraTypeTupleAnon(ip, data) },4460 .type_tuple_anon => .{ .anon_struct_type = extraTypeTupleAnon(ip, data) },
4111 .type_struct_packed => .{ .struct_type = extraPackedStructType(ip, data, false) },4461 .type_union => .{ .union_type = ns: {
4112 .type_struct_packed_inits => .{ .struct_type = extraPackedStructType(ip, data, true) },4462 const extra = ip.extraDataTrail(Tag.TypeUnion, data);
4113 .type_union => .{ .union_type = extraUnionType(ip, 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 => {4479 .type_enum_auto => .{ .enum_type = ns: {
4116 const enum_auto = ip.extraDataTrail(EnumAuto, data);4480 const extra = ip.extraDataTrail(EnumAuto, data);
4117 return .{ .enum_type = .{4481 const zir_index = extra.data.zir_index.unwrap() orelse {
4118 .decl = enum_auto.data.decl,4482 assert(extra.data.captures_len == 0);
4119 .namespace = enum_auto.data.namespace,4483 break :ns .{ .generated_tag = .{
4120 .tag_ty = enum_auto.data.int_tag_type,4484 .union_type = @enumFromInt(ip.extra.items[extra.end]),
4121 .names = .{4485 } };
4122 .start = @intCast(enum_auto.end),4486 };
4123 .len = enum_auto.data.fields_len,4487 if (extra.data.captures_len == std.math.maxInt(u32)) {
4124 },4488 break :ns .{ .reified = .{
4125 .values = .{4489 .zir_index = zir_index,
4126 .start = 0,4490 .type_hash = ip.extraData(PackedU64, extra.end).get(),
4127 .len = 0,4491 } };
4128 },4492 }
4129 .tag_mode = .auto,4493 break :ns .{ .declared = .{
4130 .names_map = enum_auto.data.names_map.toOptional(),4494 .zir_index = zir_index,
4131 .values_map = .none,4495 .captures = .{ .owned = .{
4132 .zir_index = enum_auto.data.zir_index,4496 .start = extra.end,
4497 .len = extra.data.captures_len,
4498 } },
4133 } };4499 } };
4134 },4500 } },
4135 .type_enum_explicit => ip.indexToKeyEnum(data, .explicit),4501 .type_enum_explicit, .type_enum_nonexhaustive => .{ .enum_type = ns: {
4136 .type_enum_nonexhaustive => ip.indexToKeyEnum(data, .nonexhaustive),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 } },
4137 .type_function => .{ .func_type = ip.extraFuncType(data) },4523 .type_function => .{ .func_type = ip.extraFuncType(data) },
41384524
4139 .undef => .{ .undef = @as(Index, @enumFromInt(data)) },4525 .undef => .{ .undef = @as(Index, @enumFromInt(data)) },
...@@ -4366,7 +4752,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -4366,7 +4752,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
4366 },4752 },
4367 .type_array_small,4753 .type_array_small,
4368 .type_vector,4754 .type_vector,
4369 .type_struct_ns,
4370 .type_struct_packed,4755 .type_struct_packed,
4371 => .{ .aggregate = .{4756 => .{ .aggregate = .{
4372 .ty = ty,4757 .ty = ty,
...@@ -4375,16 +4760,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -4375,16 +4760,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
43754760
4376 // There is only one possible value precisely due to the4761 // There is only one possible value precisely due to the
4377 // fact that this values slice is fully populated!4762 // fact that this values slice is fully populated!
4378 .type_struct => {4763 .type_struct, .type_struct_packed_inits => {
4379 const info = extraStructType(ip, ty_item.data);4764 const info = loadStructType(ip, ty);
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);
4388 return .{ .aggregate = .{4765 return .{ .aggregate = .{
4389 .ty = ty,4766 .ty = ty,
4390 .storage = .{ .elems = @ptrCast(info.field_inits.get(ip)) },4767 .storage = .{ .elems = @ptrCast(info.field_inits.get(ip)) },
...@@ -4476,18 +4853,6 @@ fn extraErrorSet(ip: *const InternPool, extra_index: u32) Key.ErrorSetType {...@@ -4476,18 +4853,6 @@ fn extraErrorSet(ip: *const InternPool, extra_index: u32) Key.ErrorSetType {
4476 };4853 };
4477}4854}
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
4491fn extraTypeStructAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructType {4856fn extraTypeStructAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructType {
4492 const type_struct_anon = ip.extraDataTrail(TypeStructAnon, extra_index);4857 const type_struct_anon = ip.extraDataTrail(TypeStructAnon, extra_index);
4493 const fields_len = type_struct_anon.data.fields_len;4858 const fields_len = type_struct_anon.data.fields_len;
...@@ -4526,109 +4891,6 @@ fn extraTypeTupleAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructTyp...@@ -4526,109 +4891,6 @@ fn extraTypeTupleAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructTyp
4526 };4891 };
4527}4892}
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
4632fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {4894fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {
4633 const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index);4895 const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index);
4634 var index: usize = type_function.end;4896 var index: usize = type_function.end;
...@@ -4720,28 +4982,6 @@ fn extraFuncCoerced(ip: *const InternPool, extra_index: u32) Key.Func {...@@ -4720,28 +4982,6 @@ fn extraFuncCoerced(ip: *const InternPool, extra_index: u32) Key.Func {
4720 return func;4982 return func;
4721}4983}
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
4745fn indexToKeyBigInt(ip: *const InternPool, limb_index: u32, positive: bool) Key {4985fn indexToKeyBigInt(ip: *const InternPool, limb_index: u32, positive: bool) Key {
4746 const int_info = ip.limbData(Int, limb_index);4986 const int_info = ip.limbData(Int, limb_index);
4747 return .{ .int = .{4987 return .{ .int = .{
...@@ -4901,15 +5141,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -4901,15 +5141,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
4901 .struct_type => unreachable, // use getStructType() instead5141 .struct_type => unreachable, // use getStructType() instead
4902 .anon_struct_type => unreachable, // use getAnonStructType() instead5142 .anon_struct_type => unreachable, // use getAnonStructType() instead
4903 .union_type => unreachable, // use getUnionType() instead5143 .union_type => unreachable, // use getUnionType() instead
5144 .opaque_type => unreachable, // use getOpaqueType() instead
49045145
4905 .opaque_type => |opaque_type| {5146 .enum_type => unreachable, // use getEnumType() instead
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
4913 .func_type => unreachable, // use getFuncType() instead5147 .func_type => unreachable, // use getFuncType() instead
4914 .extern_func => unreachable, // use getExternFunc() instead5148 .extern_func => unreachable, // use getExternFunc() instead
4915 .func => unreachable, // use getFuncInstance() or getFuncDecl() instead5149 .func => unreachable, // use getFuncInstance() or getFuncDecl() instead
...@@ -5027,14 +5261,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -5027,14 +5261,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
5027 assert(ptr.addr == .field);5261 assert(ptr.addr == .field);
5028 assert(base_index.index < anon_struct_type.types.len);5262 assert(base_index.index < anon_struct_type.types.len);
5029 },5263 },
5030 .struct_type => |struct_type| {5264 .struct_type => {
5031 assert(ptr.addr == .field);5265 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);
5033 },5267 },
5034 .union_type => |union_key| {5268 .union_type => {
5035 const union_type = ip.loadUnionType(union_key);5269 const union_type = ip.loadUnionType(base_ptr_type.child);
5036 assert(ptr.addr == .field);5270 assert(ptr.addr == .field);
5037 assert(base_index.index < union_type.field_names.len);5271 assert(base_index.index < union_type.field_types.len);
5038 },5272 },
5039 .ptr_type => |slice_type| {5273 .ptr_type => |slice_type| {
5040 assert(ptr.addr == .field);5274 assert(ptr.addr == .field);
...@@ -5305,7 +5539,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -5305,7 +5539,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
5305 assert(ip.isEnumType(enum_tag.ty));5539 assert(ip.isEnumType(enum_tag.ty));
5306 switch (ip.indexToKey(enum_tag.ty)) {5540 switch (ip.indexToKey(enum_tag.ty)) {
5307 .simple_type => assert(ip.isIntegerType(ip.typeOf(enum_tag.int))),5541 .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),
5309 else => unreachable,5543 else => unreachable,
5310 }5544 }
5311 ip.items.appendAssumeCapacity(.{5545 ip.items.appendAssumeCapacity(.{
...@@ -5398,8 +5632,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -5398,8 +5632,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
5398 assert(ip.typeOf(elem) == child);5632 assert(ip.typeOf(elem) == child);
5399 }5633 }
5400 },5634 },
5401 .struct_type => |t| {5635 .struct_type => {
5402 for (aggregate.storage.values(), t.field_types.get(ip)) |elem, field_ty| {5636 for (aggregate.storage.values(), ip.loadStructType(aggregate.ty).field_types.get(ip)) |elem, field_ty| {
5403 assert(ip.typeOf(elem) == field_ty);5637 assert(ip.typeOf(elem) == field_ty);
5404 }5638 }
5405 },5639 },
...@@ -5572,10 +5806,17 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -5572,10 +5806,17 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
5572}5806}
55735807
5574pub const UnionTypeInit = struct {5808pub const UnionTypeInit = struct {
5575 flags: Tag.TypeUnion.Flags,5809 flags: packed struct {
5576 decl: DeclIndex,5810 runtime_tag: LoadedUnionType.RuntimeTag,
5577 namespace: NamespaceIndex,5811 any_aligned_fields: bool,
5578 zir_index: TrackedInst.Index.Optional,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,
5579 fields_len: u32,5820 fields_len: u32,
5580 enum_tag_ty: Index,5821 enum_tag_ty: Index,
5581 /// May have length 0 which leaves the values unset until later.5822 /// May have length 0 which leaves the values unset until later.
...@@ -5584,27 +5825,84 @@ pub const UnionTypeInit = struct {...@@ -5584,27 +5825,84 @@ pub const UnionTypeInit = struct {
5584 /// The logic for `any_aligned_fields` is asserted to have been done before5825 /// The logic for `any_aligned_fields` is asserted to have been done before
5585 /// calling this function.5826 /// calling this function.
5586 field_aligns: []const Alignment,5827 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 },
5587};5838};
55885839
5589pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocator.Error!Index {5840pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocator.Error!WipNamespaceType.Result {
5590 const prev_extra_len = ip.extra.items.len;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
5591 const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;5855 const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;
5592 const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);5856 const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);
5593 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeUnion).Struct.fields.len +5857 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
5594 ini.fields_len + // field types5865 ini.fields_len + // field types
5595 align_elements_len);5866 align_elements_len);
5596 try ip.items.ensureUnusedCapacity(gpa, 1);5867 try ip.items.ensureUnusedCapacity(gpa, 1);
55975868
5598 const union_type_extra_index = ip.addExtraAssumeCapacity(Tag.TypeUnion{5869 const extra_index = ip.addExtraAssumeCapacity(Tag.TypeUnion{
5599 .flags = ini.flags,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,
5600 .size = std.math.maxInt(u32),5883 .size = std.math.maxInt(u32),
5601 .padding = std.math.maxInt(u32),5884 .padding = std.math.maxInt(u32),
5602 .decl = ini.decl,5885 .decl = undefined, // set by `finish`
5603 .namespace = ini.namespace,5886 .namespace = .none, // set by `finish`
5604 .tag_ty = ini.enum_tag_ty,5887 .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,
5606 });5896 });
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
5608 // field types5906 // field types
5609 if (ini.field_types.len > 0) {5907 if (ini.field_types.len > 0) {
5610 assert(ini.field_types.len == ini.fields_len);5908 assert(ini.field_types.len == ini.fields_len);
...@@ -5627,27 +5925,41 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat...@@ -5627,27 +5925,41 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat
5627 assert(ini.field_aligns.len == 0);5925 assert(ini.field_aligns.len == 0);
5628 }5926 }
56295927
5630 const adapter: KeyAdapter = .{ .intern_pool = ip };5928 return .{ .wip = .{
5631 const gop = try ip.map.getOrPutAdapted(gpa, Key{5929 .index = @enumFromInt(ip.items.len - 1),
5632 .union_type = extraUnionType(ip, union_type_extra_index),5930 .decl_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "decl").?,
5633 }, adapter);5931 .namespace_extra_index = if (ini.has_namespace)
5634 if (gop.found_existing) {5932 extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?
5635 ip.extra.items.len = prev_extra_len;5933 else
5636 return @enumFromInt(gop.index);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);
5637 }5953 }
56385954
5639 ip.items.appendAssumeCapacity(.{5955 pub const Result = union(enum) {
5640 .tag = .type_union,5956 wip: WipNamespaceType,
5641 .data = union_type_extra_index,5957 existing: Index,
5642 });5958 };
5643 return @enumFromInt(ip.items.len - 1);5959};
5644}
56455960
5646pub const StructTypeInit = struct {5961pub const StructTypeInit = struct {
5647 decl: DeclIndex,
5648 namespace: OptionalNamespaceIndex,
5649 layout: std.builtin.Type.ContainerLayout,5962 layout: std.builtin.Type.ContainerLayout,
5650 zir_index: TrackedInst.Index.Optional,
5651 fields_len: u32,5963 fields_len: u32,
5652 known_non_opv: bool,5964 known_non_opv: bool,
5653 requires_comptime: RequiresComptime,5965 requires_comptime: RequiresComptime,
...@@ -5656,69 +5968,101 @@ pub const StructTypeInit = struct {...@@ -5656,69 +5968,101 @@ pub const StructTypeInit = struct {
5656 any_default_inits: bool,5968 any_default_inits: bool,
5657 inits_resolved: bool,5969 inits_resolved: bool,
5658 any_aligned_fields: bool,5970 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 },
5659};5982};
56605983
5661pub fn getStructType(5984pub fn getStructType(
5662 ip: *InternPool,5985 ip: *InternPool,
5663 gpa: Allocator,5986 gpa: Allocator,
5664 ini: StructTypeInit,5987 ini: StructTypeInit,
5665) Allocator.Error!Index {5988) Allocator.Error!WipNamespaceType.Result {
5666 const adapter: KeyAdapter = .{ .intern_pool = ip };5989 const adapter: KeyAdapter = .{ .intern_pool = ip };
5667 const key: Key = .{5990 const key: Key = .{ .struct_type = switch (ini.key) {
5668 .struct_type = .{5991 .declared => |d| .{ .declared = .{
5669 // Only the decl matters for hashing and equality purposes.5992 .zir_index = d.zir_index,
5670 .decl = ini.decl.toOptional(),5993 .captures = .{ .external = d.captures },
56715994 } },
5672 .extra_index = undefined,5995 .reified => |r| .{ .reified = .{
5673 .namespace = undefined,5996 .zir_index = r.zir_index,
5674 .zir_index = undefined,5997 .type_hash = r.type_hash,
5675 .layout = undefined,5998 } },
5676 .field_names = undefined,5999 } };
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 };
5686 const gop = try ip.map.getOrPutAdapted(gpa, key, adapter);6000 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) };
5688 errdefer _ = ip.map.pop();6002 errdefer _ = ip.map.pop();
56896003
5690 const names_map = try ip.addMap(gpa, ini.fields_len);6004 const names_map = try ip.addMap(gpa, ini.fields_len);
5691 errdefer _ = ip.maps.pop();6005 errdefer _ = ip.maps.pop();
56926006
6007 const zir_index = switch (ini.key) {
6008 inline else => |x| x.zir_index,
6009 };
6010
5693 const is_extern = switch (ini.layout) {6011 const is_extern = switch (ini.layout) {
5694 .Auto => false,6012 .Auto => false,
5695 .Extern => true,6013 .Extern => true,
5696 .Packed => {6014 .Packed => {
5697 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStructPacked).Struct.fields.len +6015 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
5698 ini.fields_len + // types6023 ini.fields_len + // types
5699 ini.fields_len + // names6024 ini.fields_len + // names
5700 ini.fields_len); // inits6025 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 });
5701 try ip.items.append(gpa, .{6040 try ip.items.append(gpa, .{
5702 .tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed,6041 .tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed,
5703 .data = ip.addExtraAssumeCapacity(Tag.TypeStructPacked{6042 .data = extra_index,
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 }),
5715 });6043 });
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 }
5716 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);6053 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
5717 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);6054 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);
5718 if (ini.any_default_inits) {6055 if (ini.any_default_inits) {
5719 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);6056 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
5720 }6057 }
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 } };
5722 },6066 },
5723 };6067 };
57246068
...@@ -5727,38 +6071,57 @@ pub fn getStructType(...@@ -5727,38 +6071,57 @@ pub fn getStructType(
5727 const comptime_elements_len = if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0;6071 const comptime_elements_len = if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0;
57286072
5729 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStruct).Struct.fields.len +6073 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
5730 (ini.fields_len * 5) + // types, names, inits, runtime order, offsets6081 (ini.fields_len * 5) + // types, names, inits, runtime order, offsets
5731 align_elements_len + comptime_elements_len +6082 align_elements_len + comptime_elements_len +
5732 2); // names_map + namespace6083 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 });
5733 try ip.items.append(gpa, .{6112 try ip.items.append(gpa, .{
5734 .tag = .type_struct,6113 .tag = .type_struct,
5735 .data = ip.addExtraAssumeCapacity(Tag.TypeStruct{6114 .data = extra_index,
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 }),
5761 });6115 });
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 }
5762 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);6125 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
5763 if (!ini.is_tuple) {6126 if (!ini.is_tuple) {
5764 ip.extra.appendAssumeCapacity(@intFromEnum(names_map));6127 ip.extra.appendAssumeCapacity(@intFromEnum(names_map));
...@@ -5767,9 +6130,10 @@ pub fn getStructType(...@@ -5767,9 +6130,10 @@ pub fn getStructType(
5767 if (ini.any_default_inits) {6130 if (ini.any_default_inits) {
5768 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);6131 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
5769 }6132 }
5770 if (ini.namespace.unwrap()) |namespace| {6133 const namespace_extra_index: ?u32 = if (ini.has_namespace) i: {
5771 ip.extra.appendAssumeCapacity(@intFromEnum(namespace));6134 ip.extra.appendAssumeCapacity(undefined); // set by `finish`
5772 }6135 break :i @intCast(ip.extra.items.len - 1);
6136 } else null;
5773 if (ini.any_aligned_fields) {6137 if (ini.any_aligned_fields) {
5774 ip.extra.appendNTimesAssumeCapacity(align_element, align_elements_len);6138 ip.extra.appendNTimesAssumeCapacity(align_element, align_elements_len);
5775 }6139 }
...@@ -5777,10 +6141,14 @@ pub fn getStructType(...@@ -5777,10 +6141,14 @@ pub fn getStructType(
5777 ip.extra.appendNTimesAssumeCapacity(0, comptime_elements_len);6141 ip.extra.appendNTimesAssumeCapacity(0, comptime_elements_len);
5778 }6142 }
5779 if (ini.layout == .Auto) {6143 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);
5781 }6145 }
5782 ip.extra.appendNTimesAssumeCapacity(std.math.maxInt(u32), ini.fields_len);6146 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 } };
5784}6152}
57856153
5786pub const AnonStructTypeInit = struct {6154pub const AnonStructTypeInit = struct {
...@@ -6395,7 +6763,6 @@ fn finishFuncInstance(...@@ -6395,7 +6763,6 @@ fn finishFuncInstance(
6395 .@"addrspace" = fn_owner_decl.@"addrspace",6763 .@"addrspace" = fn_owner_decl.@"addrspace",
6396 .analysis = .complete,6764 .analysis = .complete,
6397 .zir_decl_index = fn_owner_decl.zir_decl_index,6765 .zir_decl_index = fn_owner_decl.zir_decl_index,
6398 .src_scope = fn_owner_decl.src_scope,
6399 .is_pub = fn_owner_decl.is_pub,6766 .is_pub = fn_owner_decl.is_pub,
6400 .is_exported = fn_owner_decl.is_exported,6767 .is_exported = fn_owner_decl.is_exported,
6401 .alive = true,6768 .alive = true,
...@@ -6417,257 +6784,386 @@ fn finishFuncInstance(...@@ -6417,257 +6784,386 @@ fn finishFuncInstance(
6417 return func_index;6784 return func_index;
6418}6785}
64196786
6420/// Provides API for completing an enum type after calling `getIncompleteEnum`.6787pub const EnumTypeInit = struct {
6421pub const IncompleteEnumType = 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 {
6422 index: Index,6805 index: Index,
6423 tag_ty_index: u32,6806 tag_ty_index: u32,
6807 decl_index: u32,
6808 namespace_index: ?u32,
6424 names_map: MapIndex,6809 names_map: MapIndex,
6425 names_start: u32,6810 names_start: u32,
6426 values_map: OptionalMapIndex,6811 values_map: OptionalMapIndex,
6427 values_start: u32,6812 values_start: u32,
64286813
6429 pub fn setTagType(self: @This(), ip: *InternPool, tag_ty: Index) void {6814 pub fn prepare(
6430 assert(tag_ty == .noreturn_type or ip.isIntegerType(tag_ty));6815 wip: WipEnumType,
6431 ip.extra.items[self.tag_ty_index] = @intFromEnum(tag_ty);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 }
6432 }6826 }
64336827
6434 /// Returns the already-existing field with the same name, if any.6828 pub fn setTagTy(wip: WipEnumType, ip: *InternPool, tag_ty: Index) void {
6435 pub fn addFieldName(6829 assert(ip.isIntegerType(tag_ty));
6436 self: @This(),6830 ip.extra.items[wip.tag_ty_index] = @intFromEnum(tag_ty);
6437 ip: *InternPool,
6438 name: NullTerminatedString,
6439 ) ?u32 {
6440 return ip.addFieldName(self.names_map, self.names_start, name);
6441 }6831 }
64426832
6443 /// Returns the already-existing field with the same value, if any.6833 pub const FieldConflict = struct {
6444 /// Make sure the type of the value has the integer tag type of the enum.6834 kind: enum { name, value },
6445 pub fn addFieldValue(6835 prev_field_idx: u32,
6446 self: @This(),6836 };
6447 ip: *InternPool,6837
6448 value: Index,6838 /// Returns the already-existing field with the same name or value, if any.
6449 ) ?u32 {6839 /// If the enum is automatially numbered, `value` must be `.none`.
6450 assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[self.tag_ty_index])));6840 /// Otherwise, the type of `value` must be the integer tag type of the enum.
6451 const map = &ip.maps.items[@intFromEnum(self.values_map.unwrap().?)];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().?)];
6452 const field_index = map.count();6851 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];
6454 const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) };6853 const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) };
6455 const gop = map.getOrPutAssumeCapacityAdapted(value, adapter);6854 const gop = map.getOrPutAssumeCapacityAdapted(value, adapter);
6456 if (gop.found_existing) return @intCast(gop.index);6855 if (gop.found_existing) {
6457 ip.extra.items[self.values_start + field_index] = @intFromEnum(value);6856 return .{ .kind = .value, .prev_field_idx = @intCast(gop.index) };
6857 }
6858 ip.extra.items[wip.values_start + field_index] = @intFromEnum(value);
6458 return null;6859 return null;
6459 }6860 }
6460};
64616861
6462/// This is used to create an enum type in the `InternPool`, with the ability6862 pub fn cancel(wip: WipEnumType, ip: *InternPool) void {
6463/// to update the tag type, field names, and field values later.6863 ip.remove(wip.index);
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),
6473 }6864 }
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(.{6866 pub const Result = union(enum) {
6512 .tag = .type_enum_auto,6867 wip: WipEnumType,
6513 .data = extra_index,6868 existing: 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,
6523 };6869 };
6524}6870};
65256871
6526fn getIncompleteEnumExplicit(6872pub fn getEnumType(
6527 ip: *InternPool,6873 ip: *InternPool,
6528 gpa: Allocator,6874 gpa: Allocator,
6529 enum_type: Key.IncompleteEnumType,6875 ini: EnumTypeInit,
6530 tag: Tag,6876) Allocator.Error!WipEnumType.Result {
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`.
6535 const adapter: KeyAdapter = .{ .intern_pool = ip };6877 const adapter: KeyAdapter = .{ .intern_pool = ip };
6536 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);6878 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .enum_type = switch (ini.key) {
6537 assert(!gop.found_existing);6879 .declared => |d| .{ .declared = .{
65386880 .zir_index = d.zir_index,
6539 const names_map = try ip.addMap(gpa, enum_type.fields_len);6881 .captures = .{ .external = d.captures },
6540 const values_map: OptionalMapIndex = if (!enum_type.has_values) .none else m: {6882 } },
6541 const values_map = try ip.addMap(gpa, enum_type.fields_len);6883 .reified => |r| .{ .reified = .{
6542 break :m values_map.toOptional();6884 .zir_index = r.zir_index,
6543 };6885 .type_hash = r.type_hash,
65446886 } },
6545 const reserved_len = enum_type.fields_len +6887 } }, adapter);
6546 if (enum_type.has_values) enum_type.fields_len else 0;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);
6550 try ip.items.ensureUnusedCapacity(gpa, 1);6892 try ip.items.ensureUnusedCapacity(gpa, 1);
65516893
6552 const extra_index = ip.addExtraAssumeCapacity(EnumExplicit{6894 const names_map = try ip.addMap(gpa, ini.fields_len);
6553 .decl = enum_type.decl,6895 errdefer _ = ip.maps.pop();
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 });
65616896
6562 ip.items.appendAssumeCapacity(.{6897 switch (ini.tag_mode) {
6563 .tag = tag,6898 .auto => {
6564 .data = extra_index,6899 assert(!ini.has_values);
6565 });6900 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
6566 // This is both fields and values (if present).6901 // TODO: fmt bug
6567 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), reserved_len);6902 // zig fmt: off
6568 return .{6903 switch (ini.key) {
6569 .index = @enumFromInt(ip.items.len - 1),6904 .declared => |d| d.captures.len,
6570 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,6905 .reified => 2, // type_hash: PackedU64
6571 .names_map = names_map,6906 } +
6572 .names_start = extra_index + extra_fields_len,6907 // zig fmt: on
6573 .values_map = values_map,6908 ini.fields_len); // field types
6574 .values_start = extra_index + extra_fields_len + enum_type.fields_len,6909
6575 };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 }
6576}7010}
65777011
6578pub const GetEnumInit = struct {7012const GeneratedTagEnumTypeInit = struct {
6579 decl: DeclIndex,7013 decl: DeclIndex,
6580 namespace: OptionalNamespaceIndex,7014 owner_union_ty: Index,
6581 tag_ty: Index,7015 tag_ty: Index,
6582 names: []const NullTerminatedString,7016 names: []const NullTerminatedString,
6583 values: []const Index,7017 values: []const Index,
6584 tag_mode: Key.EnumType.TagMode,7018 tag_mode: LoadedEnumType.TagMode,
6585 zir_index: TrackedInst.Index.Optional,
6586};7019};
65877020
6588pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Error!Index {7021/// Creates an enum type which was automatically-generated as the tag type of a
6589 const adapter: KeyAdapter = .{ .intern_pool = ip };7022/// `union` with no explicit tag type. Since this is only called once per union
6590 const gop = try ip.map.getOrPutAdapted(gpa, Key{7023/// type, it asserts that no matching type yet exists.
6591 .enum_type = .{7024pub fn getGeneratedTagEnumType(ip: *InternPool, gpa: Allocator, ini: GeneratedTagEnumTypeInit) Allocator.Error!Index {
6592 // Only the decl is used for hashing and equality.7025 assert(ip.isUnion(ini.owner_union_ty));
6593 .decl = ini.decl,7026 assert(ip.isIntegerType(ini.tag_ty));
65947027 for (ini.values) |val| assert(ip.typeOf(val) == ini.tag_ty);
6595 .namespace = undefined,7028
6596 .tag_ty = undefined,7029 try ip.map.ensureUnusedCapacity(gpa, 1);
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();
6607 try ip.items.ensureUnusedCapacity(gpa, 1);7030 try ip.items.ensureUnusedCapacity(gpa, 1);
66087031
6609 assert(ini.tag_ty == .noreturn_type or ip.isIntegerType(ini.tag_ty));7032 const names_map = try ip.addMap(gpa, ini.names.len);
6610 for (ini.values) |value| assert(ip.typeOf(value) == ini.tag_ty);7033 errdefer _ = ip.maps.pop();
7034 ip.addStringsToMap(names_map, ini.names);
7035
7036 const fields_len: u32 = @intCast(ini.names.len);
66117037
6612 switch (ini.tag_mode) {7038 switch (ini.tag_mode) {
6613 .auto => {7039 .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);
6618 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +7040 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
6619 fields_len);7041 1 + // owner_union
7042 fields_len); // field names
6620 ip.items.appendAssumeCapacity(.{7043 ip.items.appendAssumeCapacity(.{
6621 .tag = .type_enum_auto,7044 .tag = .type_enum_auto,
6622 .data = ip.addExtraAssumeCapacity(EnumAuto{7045 .data = ip.addExtraAssumeCapacity(EnumAuto{
6623 .decl = ini.decl,7046 .decl = ini.decl,
6624 .namespace = ini.namespace,7047 .captures_len = 0,
7048 .namespace = .none,
6625 .int_tag_type = ini.tag_ty,7049 .int_tag_type = ini.tag_ty,
7050 .fields_len = fields_len,
6626 .names_map = names_map,7051 .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,
6627 .fields_len = fields_len,7083 .fields_len = fields_len,
6628 .zir_index = ini.zir_index,7084 .names_map = names_map,
7085 .values_map = values_map,
7086 .zir_index = .none,
6629 }),7087 }),
6630 });7088 });
7089 ip.extra.appendAssumeCapacity(@intFromEnum(ini.owner_union_ty));
6631 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));7090 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
6632 return @enumFromInt(ip.items.len - 1);7091 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));
6633 },7092 },
6634 .explicit => return finishGetEnum(ip, gpa, ini, .type_enum_explicit),
6635 .nonexhaustive => return finishGetEnum(ip, gpa, ini, .type_enum_nonexhaustive),
6636 }7093 }
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);
6637}7105}
66387106
6639pub fn finishGetEnum(7107pub const OpaqueTypeIni = struct {
6640 ip: *InternPool,7108 has_namespace: bool,
6641 gpa: Allocator,7109 key: union(enum) {
6642 ini: GetEnumInit,7110 declared: struct {
6643 tag: Tag,7111 zir_index: TrackedInst.Index,
6644) Allocator.Error!Index {7112 captures: []const CaptureValue,
6645 const names_map = try ip.addMap(gpa, ini.names.len);7113 },
6646 addStringsToMap(ip, names_map, ini.names);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: {7121pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, ini: OpaqueTypeIni) Allocator.Error!WipNamespaceType.Result {
6649 const values_map = try ip.addMap(gpa, ini.values.len);7122 const adapter: KeyAdapter = .{ .intern_pool = ip };
6650 addIndexesToMap(ip, values_map, ini.values);7123 const gop = try ip.map.getOrPutAdapted(gpa, Key{ .opaque_type = switch (ini.key) {
6651 break :m values_map.toOptional();7124 .declared => |d| .{ .declared = .{
6652 };7125 .zir_index = d.zir_index,
6653 const fields_len: u32 = @intCast(ini.names.len);7126 .captures = .{ .external = d.captures },
6654 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len +7127 } },
6655 fields_len);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 });
6656 ip.items.appendAssumeCapacity(.{7151 ip.items.appendAssumeCapacity(.{
6657 .tag = tag,7152 .tag = .type_opaque,
6658 .data = ip.addExtraAssumeCapacity(EnumExplicit{7153 .data = extra_index,
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 }),
6667 });7154 });
6668 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));7155 switch (ini.key) {
6669 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.values));7156 .declared => |d| ip.extra.appendSliceAssumeCapacity(@ptrCast(d.captures)),
6670 return @enumFromInt(ip.items.len - 1);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 } };
6671}7167}
66727168
6673pub fn getIfExists(ip: *const InternPool, key: Key) ?Index {7169pub fn getIfExists(ip: *const InternPool, key: Key) ?Index {
...@@ -6716,8 +7212,34 @@ fn addMap(ip: *InternPool, gpa: Allocator, cap: usize) Allocator.Error!MapIndex...@@ -6716,8 +7212,34 @@ fn addMap(ip: *InternPool, gpa: Allocator, cap: usize) Allocator.Error!MapIndex
67167212
6717/// This operation only happens under compile error conditions.7213/// This operation only happens under compile error conditions.
6718/// Leak the index until the next garbage collection.7214/// Leak the index until the next garbage collection.
6719/// TODO: this is a bit problematic to implement, can we get away without it?7215/// Invalidates all references to this index.
6720pub const remove = @compileError("InternPool.remove is not currently a supported operation; put a TODO there instead");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
6722fn addInt(ip: *InternPool, gpa: Allocator, ty: Index, tag: Tag, limbs: []const Limb) !void {7244fn addInt(ip: *InternPool, gpa: Allocator, ty: Index, tag: Tag, limbs: []const Limb) !void {
6723 const limbs_len = @as(u32, @intCast(limbs.len));7245 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...@@ -7077,9 +7599,9 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
7077 .func => unreachable,7599 .func => unreachable,
70787600
7079 .int => |int| switch (ip.indexToKey(new_ty)) {7601 .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 = .{
7081 .ty = new_ty,7603 .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),
7083 } }),7605 } }),
7084 .ptr_type => return ip.get(gpa, .{ .ptr = .{7606 .ptr_type => return ip.get(gpa, .{ .ptr = .{
7085 .ty = new_ty,7607 .ty = new_ty,
...@@ -7108,7 +7630,8 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al...@@ -7108,7 +7630,8 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
7108 .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))7630 .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))
7109 return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty),7631 return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty),
7110 .enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) {7632 .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);
7112 const index = enum_type.nameIndex(ip, enum_literal).?;7635 const index = enum_type.nameIndex(ip, enum_literal).?;
7113 return ip.get(gpa, .{ .enum_tag = .{7636 return ip.get(gpa, .{ .enum_tag = .{
7114 .ty = new_ty,7637 .ty = new_ty,
...@@ -7249,7 +7772,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al...@@ -7249,7 +7772,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
7249 const new_elem_ty = switch (ip.indexToKey(new_ty)) {7772 const new_elem_ty = switch (ip.indexToKey(new_ty)) {
7250 inline .array_type, .vector_type => |seq_type| seq_type.child,7773 inline .array_type, .vector_type => |seq_type| seq_type.child,
7251 .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[i],7774 .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],
7253 else => unreachable,7776 else => unreachable,
7254 };7777 };
7255 elem.* = try ip.getCoerced(gpa, elem.*, new_elem_ty);7778 elem.* = try ip.getCoerced(gpa, elem.*, new_elem_ty);
...@@ -7513,6 +8036,10 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -7513,6 +8036,10 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
7513 if (!gop.found_existing) gop.value_ptr.* = .{};8036 if (!gop.found_existing) gop.value_ptr.* = .{};
7514 gop.value_ptr.count += 1;8037 gop.value_ptr.count += 1;
7515 gop.value_ptr.bytes += 1 + 4 + @as(usize, switch (tag) {8038 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
7516 .type_int_signed => 0,8043 .type_int_signed => 0,
7517 .type_int_unsigned => 0,8044 .type_int_unsigned => 0,
7518 .type_array_small => @sizeOf(Vector),8045 .type_array_small => @sizeOf(Vector),
...@@ -7529,12 +8056,31 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -7529,12 +8056,31 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
7529 break :b @sizeOf(Tag.ErrorSet) + (@sizeOf(u32) * info.names_len);8056 break :b @sizeOf(Tag.ErrorSet) + (@sizeOf(u32) * info.names_len);
7530 },8057 },
7531 .type_inferred_error_set => 0,8058 .type_inferred_error_set => 0,
7532 .type_enum_explicit, .type_enum_nonexhaustive => @sizeOf(EnumExplicit),8059 .type_enum_explicit, .type_enum_nonexhaustive => b: {
7533 .type_enum_auto => @sizeOf(EnumAuto),8060 const info = ip.extraData(EnumExplicit, data);
7534 .type_opaque => @sizeOf(Key.OpaqueType),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 },
7535 .type_struct => b: {8075 .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;
7537 var ints: usize = @typeInfo(Tag.TypeStruct).Struct.fields.len;8079 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 }
7538 ints += info.fields_len; // types8084 ints += info.fields_len; // types
7539 if (!info.flags.is_tuple) {8085 if (!info.flags.is_tuple) {
7540 ints += 1; // names_map8086 ints += 1; // names_map
...@@ -7552,20 +8098,29 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -7552,20 +8098,29 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
7552 ints += info.fields_len; // offsets8098 ints += info.fields_len; // offsets
7553 break :b @sizeOf(u32) * ints;8099 break :b @sizeOf(u32) * ints;
7554 },8100 },
7555 .type_struct_ns => @sizeOf(Module.Namespace),
7556 .type_struct_anon => b: {8101 .type_struct_anon => b: {
7557 const info = ip.extraData(TypeStructAnon, data);8102 const info = ip.extraData(TypeStructAnon, data);
7558 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len);8103 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len);
7559 },8104 },
7560 .type_struct_packed => b: {8105 .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;
7562 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +8111 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);
7564 },8114 },
7565 .type_struct_packed_inits => b: {8115 .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;
7567 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +8121 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);
7569 },8124 },
7570 .type_tuple_anon => b: {8125 .type_tuple_anon => b: {
7571 const info = ip.extraData(TypeStructAnon, data);8126 const info = ip.extraData(TypeStructAnon, data);
...@@ -7573,16 +8128,20 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -7573,16 +8128,20 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
7573 },8128 },
75748129
7575 .type_union => b: {8130 .type_union => b: {
7576 const info = ip.extraData(Tag.TypeUnion, data);8131 const extra = ip.extraDataTrail(Tag.TypeUnion, data);
7577 const enum_info = ip.indexToKey(info.tag_ty).enum_type;8132 const captures_len = if (extra.data.flags.any_captures)
7578 const fields_len: u32 = @intCast(enum_info.names.len);8133 ip.extra.items[extra.end]
8134 else
8135 0;
7579 const per_field = @sizeOf(u32); // field type8136 const per_field = @sizeOf(u32); // field type
7580 // 1 byte per field for alignment, rounded up to the nearest 4 bytes8137 // 1 byte per field for alignment, rounded up to the nearest 4 bytes
7581 const alignments = if (info.flags.any_aligned_fields)8138 const alignments = if (extra.data.flags.any_aligned_fields)
7582 ((fields_len + 3) / 4) * 48139 ((extra.data.fields_len + 3) / 4) * 4
7583 else8140 else
7584 0;8141 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;
7586 },8145 },
75878146
7588 .type_function => b: {8147 .type_function => b: {
...@@ -7698,6 +8257,8 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {...@@ -7698,6 +8257,8 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
7698 for (tags, datas, 0..) |tag, data, i| {8257 for (tags, datas, 0..) |tag, data, i| {
7699 try w.print("${d} = {s}(", .{ i, @tagName(tag) });8258 try w.print("${d} = {s}(", .{ i, @tagName(tag) });
7700 switch (tag) {8259 switch (tag) {
8260 .removed => {},
8261
7701 .simple_type => try w.print("{s}", .{@tagName(@as(SimpleType, @enumFromInt(data)))}),8262 .simple_type => try w.print("{s}", .{@tagName(@as(SimpleType, @enumFromInt(data)))}),
7702 .simple_value => try w.print("{s}", .{@tagName(@as(SimpleValue, @enumFromInt(data)))}),8263 .simple_value => try w.print("{s}", .{@tagName(@as(SimpleValue, @enumFromInt(data)))}),
77038264
...@@ -7718,7 +8279,6 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {...@@ -7718,7 +8279,6 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
7718 .type_enum_auto,8279 .type_enum_auto,
7719 .type_opaque,8280 .type_opaque,
7720 .type_struct,8281 .type_struct,
7721 .type_struct_ns,
7722 .type_struct_anon,8282 .type_struct_anon,
7723 .type_struct_packed,8283 .type_struct_packed,
7724 .type_struct_packed_inits,8284 .type_struct_packed_inits,
...@@ -8105,6 +8665,8 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -8105,6 +8665,8 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
8105 // This optimization on tags is needed so that indexToKey can call8665 // This optimization on tags is needed so that indexToKey can call
8106 // typeOf without being recursive.8666 // typeOf without being recursive.
8107 _ => switch (ip.items.items(.tag)[@intFromEnum(index)]) {8667 _ => switch (ip.items.items(.tag)[@intFromEnum(index)]) {
8668 .removed => unreachable,
8669
8108 .type_int_signed,8670 .type_int_signed,
8109 .type_int_unsigned,8671 .type_int_unsigned,
8110 .type_array_big,8672 .type_array_big,
...@@ -8124,7 +8686,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -8124,7 +8686,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
8124 .simple_type,8686 .simple_type,
8125 .type_opaque,8687 .type_opaque,
8126 .type_struct,8688 .type_struct,
8127 .type_struct_ns,
8128 .type_struct_anon,8689 .type_struct_anon,
8129 .type_struct_packed,8690 .type_struct_packed,
8130 .type_struct_packed_inits,8691 .type_struct_packed_inits,
...@@ -8218,7 +8779,7 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E {...@@ -8218,7 +8779,7 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E {
82188779
8219pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {8780pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
8220 return switch (ip.indexToKey(ty)) {8781 return switch (ip.indexToKey(ty)) {
8221 .struct_type => |struct_type| struct_type.field_types.len,8782 .struct_type => ip.loadStructType(ty).field_types.len,
8222 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,8783 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
8223 .array_type => |array_type| array_type.len,8784 .array_type => |array_type| array_type.len,
8224 .vector_type => |vector_type| vector_type.len,8785 .vector_type => |vector_type| vector_type.len,
...@@ -8228,7 +8789,7 @@ pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {...@@ -8228,7 +8789,7 @@ pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
82288789
8229pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {8790pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {
8230 return switch (ip.indexToKey(ty)) {8791 return switch (ip.indexToKey(ty)) {
8231 .struct_type => |struct_type| struct_type.field_types.len,8792 .struct_type => ip.loadStructType(ty).field_types.len,
8232 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,8793 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
8233 .array_type => |array_type| array_type.len + @intFromBool(array_type.sentinel != .none),8794 .array_type => |array_type| array_type.len + @intFromBool(array_type.sentinel != .none),
8234 .vector_type => |vector_type| vector_type.len,8795 .vector_type => |vector_type| vector_type.len,
...@@ -8423,6 +8984,8 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois...@@ -8423,6 +8984,8 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
8423 .var_args_param_type => unreachable, // special tag8984 .var_args_param_type => unreachable, // special tag
84248985
8425 _ => switch (ip.items.items(.tag)[@intFromEnum(index)]) {8986 _ => switch (ip.items.items(.tag)[@intFromEnum(index)]) {
8987 .removed => unreachable,
8988
8426 .type_int_signed,8989 .type_int_signed,
8427 .type_int_unsigned,8990 .type_int_unsigned,
8428 => .Int,8991 => .Int,
...@@ -8458,7 +9021,6 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois...@@ -8458,7 +9021,6 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
8458 .type_opaque => .Opaque,9021 .type_opaque => .Opaque,
84599022
8460 .type_struct,9023 .type_struct,
8461 .type_struct_ns,
8462 .type_struct_anon,9024 .type_struct_anon,
8463 .type_struct_packed,9025 .type_struct_packed,
8464 .type_struct_packed_inits,9026 .type_struct_packed_inits,
src/Liveness.zig+2-2
...@@ -131,7 +131,7 @@ fn LivenessPassData(comptime pass: LivenessPass) type {...@@ -131,7 +131,7 @@ fn LivenessPassData(comptime pass: LivenessPass) type {
131 };131 };
132}132}
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 {
135 const tracy = trace(@src());135 const tracy = trace(@src());
136 defer tracy.end();136 defer tracy.end();
137137
...@@ -836,7 +836,7 @@ pub const BigTomb = struct {...@@ -836,7 +836,7 @@ pub const BigTomb = struct {
836const Analysis = struct {836const Analysis = struct {
837 gpa: Allocator,837 gpa: Allocator,
838 air: Air,838 air: Air,
839 intern_pool: *const InternPool,839 intern_pool: *InternPool,
840 tomb_bits: []usize,840 tomb_bits: []usize,
841 special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32),841 special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32),
842 extra: std.ArrayListUnmanaged(u32),842 extra: std.ArrayListUnmanaged(u32),
src/Module.zig+101-138
...@@ -101,17 +101,6 @@ embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .{},...@@ -101,17 +101,6 @@ embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .{},
101/// is not yet implemented.101/// is not yet implemented.
102intern_pool: InternPool = .{},102intern_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
115/// To be eliminated in a future commit by moving more data into InternPool.104/// To be eliminated in a future commit by moving more data into InternPool.
116/// Current uses that must be eliminated:105/// Current uses that must be eliminated:
117/// * comptime pointer mutation106/// * comptime pointer mutation
...@@ -305,28 +294,6 @@ pub const Export = struct {...@@ -305,28 +294,6 @@ pub const Export = struct {
305 }294 }
306};295};
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
330const ValueArena = struct {297const ValueArena = struct {
331 state: std.heap.ArenaAllocator.State,298 state: std.heap.ArenaAllocator.State,
332 state_acquired: ?*std.heap.ArenaAllocator.State = null,299 state_acquired: ?*std.heap.ArenaAllocator.State = null,
...@@ -386,9 +353,6 @@ pub const Decl = struct {...@@ -386,9 +353,6 @@ pub const Decl = struct {
386 /// there is no parent.353 /// there is no parent.
387 src_namespace: Namespace.Index,354 src_namespace: Namespace.Index,
388355
389 /// The scope which lexically contains this decl.
390 src_scope: CaptureScope.Index,
391
392 /// The AST node index of this declaration.356 /// The AST node index of this declaration.
393 /// Must be recomputed when the corresponding source file is modified.357 /// Must be recomputed when the corresponding source file is modified.
394 src_node: Ast.Node.Index,358 src_node: Ast.Node.Index,
...@@ -563,7 +527,7 @@ pub const Decl = struct {...@@ -563,7 +527,7 @@ pub const Decl = struct {
563527
564 /// If the Decl owns its value and it is a union, return it,528 /// If the Decl owns its value and it is a union, return it,
565 /// otherwise null.529 /// otherwise null.
566 pub fn getOwnedUnion(decl: Decl, zcu: *Zcu) ?InternPool.UnionType {530 pub fn getOwnedUnion(decl: Decl, zcu: *Zcu) ?InternPool.LoadedUnionType {
567 if (!decl.owns_tv) return null;531 if (!decl.owns_tv) return null;
568 if (decl.val.ip_index == .none) return null;532 if (decl.val.ip_index == .none) return null;
569 return zcu.typeToUnion(decl.val.toType());533 return zcu.typeToUnion(decl.val.toType());
...@@ -599,14 +563,15 @@ pub const Decl = struct {...@@ -599,14 +563,15 @@ pub const Decl = struct {
599 /// enum, or opaque.563 /// enum, or opaque.
600 pub fn getInnerNamespaceIndex(decl: Decl, zcu: *Zcu) Namespace.OptionalIndex {564 pub fn getInnerNamespaceIndex(decl: Decl, zcu: *Zcu) Namespace.OptionalIndex {
601 if (!decl.has_tv) return .none;565 if (!decl.has_tv) return .none;
566 const ip = &zcu.intern_pool;
602 return switch (decl.val.ip_index) {567 return switch (decl.val.ip_index) {
603 .empty_struct_type => .none,568 .empty_struct_type => .none,
604 .none => .none,569 .none => .none,
605 else => switch (zcu.intern_pool.indexToKey(decl.val.toIntern())) {570 else => switch (ip.indexToKey(decl.val.toIntern())) {
606 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),571 .opaque_type => ip.loadOpaqueType(decl.val.toIntern()).namespace,
607 .struct_type => |struct_type| struct_type.namespace,572 .struct_type => ip.loadStructType(decl.val.toIntern()).namespace,
608 .union_type => |union_type| union_type.namespace.toOptional(),573 .union_type => ip.loadUnionType(decl.val.toIntern()).namespace,
609 .enum_type => |enum_type| enum_type.namespace,574 .enum_type => ip.loadEnumType(decl.val.toIntern()).namespace,
610 else => .none,575 else => .none,
611 },576 },
612 };577 };
...@@ -792,7 +757,6 @@ pub const Namespace = struct {...@@ -792,7 +757,6 @@ pub const Namespace = struct {
792 /// These are only declarations named directly by the AST; anonymous757 /// These are only declarations named directly by the AST; anonymous
793 /// declarations are not stored here.758 /// declarations are not stored here.
794 decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{},759 decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{},
795
796 /// Key is usingnamespace Decl itself. To find the namespace being included,760 /// Key is usingnamespace Decl itself. To find the namespace being included,
797 /// the Decl Value has to be resolved as a Type which has a Namespace.761 /// the Decl Value has to be resolved as a Type which has a Namespace.
798 /// Value is whether the usingnamespace decl is marked `pub`.762 /// Value is whether the usingnamespace decl is marked `pub`.
...@@ -2140,10 +2104,6 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2140,10 +2104,6 @@ pub fn deinit(zcu: *Zcu) void {
21402104
2141 zcu.intern_pool.deinit(gpa);2105 zcu.intern_pool.deinit(gpa);
2142 zcu.tmp_hack_arena.deinit();2106 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);
2147}2107}
21482108
2149pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {2109pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
...@@ -3342,6 +3302,70 @@ pub fn semaPkg(mod: *Module, pkg: *Package.Module) !void {...@@ -3342,6 +3302,70 @@ pub fn semaPkg(mod: *Module, pkg: *Package.Module) !void {
3342 return mod.semaFile(file);3302 return mod.semaFile(file);
3343}3303}
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
3345/// Regardless of the file status, will create a `Decl` so that we3369/// Regardless of the file status, will create a `Decl` so that we
3346/// can track dependencies and re-analyze when the file becomes outdated.3370/// can track dependencies and re-analyze when the file becomes outdated.
3347pub fn semaFile(mod: *Module, file: *File) SemaError!void {3371pub fn semaFile(mod: *Module, file: *File) SemaError!void {
...@@ -3363,15 +3387,14 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -3363,15 +3387,14 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3363 .decl_index = undefined,3387 .decl_index = undefined,
3364 .file_scope = file,3388 .file_scope = file,
3365 });3389 });
3366 const new_namespace = mod.namespacePtr(new_namespace_index);
3367 errdefer mod.destroyNamespace(new_namespace_index);3390 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);
3370 const new_decl = mod.declPtr(new_decl_index);3393 const new_decl = mod.declPtr(new_decl_index);
3371 errdefer @panic("TODO error handling");3394 errdefer @panic("TODO error handling");
33723395
3373 file.root_decl = new_decl_index.toOptional();3396 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
3376 new_decl.name = try file.fullyQualifiedName(mod);3399 new_decl.name = try file.fullyQualifiedName(mod);
3377 new_decl.name_fully_qualified = true;3400 new_decl.name_fully_qualified = true;
...@@ -3390,54 +3413,10 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -3390,54 +3413,10 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3390 }3413 }
3391 assert(file.zir_loaded);3414 assert(file.zir_loaded);
33923415
3393 var sema_arena = std.heap.ArenaAllocator.init(gpa);3416 const struct_ty = try mod.getFileRootStruct(new_decl_index, new_namespace_index, file);
3394 defer sema_arena.deinit();3417 errdefer mod.intern_pool.remove(struct_ty);
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();
34023418
3403 var sema: Sema = .{3419 switch (mod.comp.cache_use) {
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) {
3441 .whole => |whole| if (whole.cache_manifest) |man| {3420 .whole => |whole| if (whole.cache_manifest) |man| {
3442 const source = file.getSource(gpa) catch |err| {3421 const source = file.getSource(gpa) catch |err| {
3443 try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)});3422 try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)});
...@@ -3573,7 +3552,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3573,7 +3552,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
3573 .sema = &sema,3552 .sema = &sema,
3574 .src_decl = decl_index,3553 .src_decl = decl_index,
3575 .namespace = decl.src_namespace,3554 .namespace = decl.src_namespace,
3576 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
3577 .instructions = .{},3555 .instructions = .{},
3578 .inlining = null,3556 .inlining = null,
3579 .is_comptime = true,3557 .is_comptime = true,
...@@ -4205,7 +4183,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void...@@ -4205,7 +4183,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
4205 );4183 );
4206 const comp = zcu.comp;4184 const comp = zcu.comp;
4207 if (!gop.found_existing) {4185 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);
4209 const new_decl = zcu.declPtr(new_decl_index);4187 const new_decl = zcu.declPtr(new_decl_index);
4210 new_decl.kind = kind;4188 new_decl.kind = kind;
4211 new_decl.name = decl_name;4189 new_decl.name = decl_name;
...@@ -4438,7 +4416,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato...@@ -4438,7 +4416,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
4438 .sema = &sema,4416 .sema = &sema,
4439 .src_decl = decl_index,4417 .src_decl = decl_index,
4440 .namespace = decl.src_namespace,4418 .namespace = decl.src_namespace,
4441 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
4442 .instructions = .{},4419 .instructions = .{},
4443 .inlining = null,4420 .inlining = null,
4444 .is_comptime = false,4421 .is_comptime = false,
...@@ -4639,7 +4616,6 @@ pub fn allocateNewDecl(...@@ -4639,7 +4616,6 @@ pub fn allocateNewDecl(
4639 mod: *Module,4616 mod: *Module,
4640 namespace: Namespace.Index,4617 namespace: Namespace.Index,
4641 src_node: Ast.Node.Index,4618 src_node: Ast.Node.Index,
4642 src_scope: CaptureScope.Index,
4643) !Decl.Index {4619) !Decl.Index {
4644 const ip = &mod.intern_pool;4620 const ip = &mod.intern_pool;
4645 const gpa = mod.gpa;4621 const gpa = mod.gpa;
...@@ -4657,7 +4633,6 @@ pub fn allocateNewDecl(...@@ -4657,7 +4633,6 @@ pub fn allocateNewDecl(
4657 .@"addrspace" = .generic,4633 .@"addrspace" = .generic,
4658 .analysis = .unreferenced,4634 .analysis = .unreferenced,
4659 .zir_decl_index = .none,4635 .zir_decl_index = .none,
4660 .src_scope = src_scope,
4661 .is_pub = false,4636 .is_pub = false,
4662 .is_exported = false,4637 .is_exported = false,
4663 .alive = false,4638 .alive = false,
...@@ -4697,17 +4672,16 @@ pub fn errorSetBits(mod: *Module) u16 {...@@ -4697,17 +4672,16 @@ pub fn errorSetBits(mod: *Module) u16 {
46974672
4698pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index {4673pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index {
4699 const src_decl = mod.declPtr(block.src_decl);4674 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);
4701}4676}
47024677
4703pub fn createAnonymousDeclFromDecl(4678pub fn createAnonymousDeclFromDecl(
4704 mod: *Module,4679 mod: *Module,
4705 src_decl: *Decl,4680 src_decl: *Decl,
4706 namespace: Namespace.Index,4681 namespace: Namespace.Index,
4707 src_scope: CaptureScope.Index,
4708 tv: TypedValue,4682 tv: TypedValue,
4709) !Decl.Index {4683) !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);
4711 errdefer mod.destroyDecl(new_decl_index);4685 errdefer mod.destroyDecl(new_decl_index);
4712 const name = try mod.intern_pool.getOrPutStringFmt(mod.gpa, "{}__anon_{d}", .{4686 const name = try mod.intern_pool.getOrPutStringFmt(mod.gpa, "{}__anon_{d}", .{
4713 src_decl.name.fmt(&mod.intern_pool), @intFromEnum(new_decl_index),4687 src_decl.name.fmt(&mod.intern_pool), @intFromEnum(new_decl_index),
...@@ -5276,7 +5250,7 @@ pub fn populateTestFunctions(...@@ -5276,7 +5250,7 @@ pub fn populateTestFunctions(
5276 .len = test_decl_name.len,5250 .len = test_decl_name.len,
5277 .child = .u8_type,5251 .child = .u8_type,
5278 });5252 });
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, .{
5280 .ty = test_name_decl_ty,5254 .ty = test_name_decl_ty,
5281 .val = Value.fromInterned((try mod.intern(.{ .aggregate = .{5255 .val = Value.fromInterned((try mod.intern(.{ .aggregate = .{
5282 .ty = test_name_decl_ty.toIntern(),5256 .ty = test_name_decl_ty.toIntern(),
...@@ -5322,7 +5296,7 @@ pub fn populateTestFunctions(...@@ -5322,7 +5296,7 @@ pub fn populateTestFunctions(
5322 .child = test_fn_ty.toIntern(),5296 .child = test_fn_ty.toIntern(),
5323 .sentinel = .none,5297 .sentinel = .none,
5324 });5298 });
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, .{
5326 .ty = array_decl_ty,5300 .ty = array_decl_ty,
5327 .val = Value.fromInterned((try mod.intern(.{ .aggregate = .{5301 .val = Value.fromInterned((try mod.intern(.{ .aggregate = .{
5328 .ty = array_decl_ty.toIntern(),5302 .ty = array_decl_ty.toIntern(),
...@@ -5686,7 +5660,7 @@ pub fn enumValue(mod: *Module, ty: Type, tag_int: InternPool.Index) Allocator.Er...@@ -5686,7 +5660,7 @@ pub fn enumValue(mod: *Module, ty: Type, tag_int: InternPool.Index) Allocator.Er
5686pub fn enumValueFieldIndex(mod: *Module, ty: Type, field_index: u32) Allocator.Error!Value {5660pub fn enumValueFieldIndex(mod: *Module, ty: Type, field_index: u32) Allocator.Error!Value {
5687 const ip = &mod.intern_pool;5661 const ip = &mod.intern_pool;
5688 const gpa = mod.gpa;5662 const gpa = mod.gpa;
5689 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;5663 const enum_type = ip.loadEnumType(ty.toIntern());
56905664
5691 if (enum_type.values.len == 0) {5665 if (enum_type.values.len == 0) {
5692 // Auto-numbered fields.5666 // Auto-numbered fields.
...@@ -5976,14 +5950,6 @@ pub fn atomicPtrAlignment(...@@ -5976,14 +5950,6 @@ pub fn atomicPtrAlignment(
5976 return .none;5950 return .none;
5977}5951}
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
5987pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {5953pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {
5988 return mod.declPtr(decl_index).getFileScope(mod);5954 return mod.declPtr(decl_index).getFileScope(mod);
5989}5955}
...@@ -5992,28 +5958,26 @@ pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {...@@ -5992,28 +5958,26 @@ pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {
5992/// * `@TypeOf(.{})`5958/// * `@TypeOf(.{})`
5993/// * A struct which has no fields (`struct {}`).5959/// * A struct which has no fields (`struct {}`).
5994/// * Not a struct.5960/// * Not a struct.
5995pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.Key.StructType {5961pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {
5996 if (ty.ip_index == .none) return null;5962 if (ty.ip_index == .none) return null;
5997 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {5963 const ip = &mod.intern_pool;
5998 .struct_type => |t| t,5964 return switch (ip.indexToKey(ty.ip_index)) {
5965 .struct_type => ip.loadStructType(ty.ip_index),
5999 else => null,5966 else => null,
6000 };5967 };
6001}5968}
60025969
6003pub fn typeToPackedStruct(mod: *Module, ty: Type) ?InternPool.Key.StructType {5970pub fn typeToPackedStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {
6004 if (ty.ip_index == .none) return null;5971 const s = mod.typeToStruct(ty) orelse return null;
6005 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {5972 if (s.layout != .Packed) return null;
6006 .struct_type => |t| if (t.layout == .Packed) t else null,5973 return s;
6007 else => null,
6008 };
6009}5974}
60105975
6011/// This asserts that the union's enum tag type has been resolved.5976pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.LoadedUnionType {
6012pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType {
6013 if (ty.ip_index == .none) return null;5977 if (ty.ip_index == .none) return null;
6014 const ip = &mod.intern_pool;5978 const ip = &mod.intern_pool;
6015 return switch (ip.indexToKey(ty.ip_index)) {5979 return switch (ip.indexToKey(ty.ip_index)) {
6016 .union_type => |k| ip.loadUnionType(k),5980 .union_type => ip.loadUnionType(ty.ip_index),
6017 else => null,5981 else => null,
6018 };5982 };
6019}5983}
...@@ -6115,7 +6079,7 @@ pub const UnionLayout = struct {...@@ -6115,7 +6079,7 @@ pub const UnionLayout = struct {
6115 padding: u32,6079 padding: u32,
6116};6080};
61176081
6118pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {6082pub fn getUnionLayout(mod: *Module, u: InternPool.LoadedUnionType) UnionLayout {
6119 const ip = &mod.intern_pool;6083 const ip = &mod.intern_pool;
6120 assert(u.haveLayout(ip));6084 assert(u.haveLayout(ip));
6121 var most_aligned_field: u32 = undefined;6085 var most_aligned_field: u32 = undefined;
...@@ -6161,7 +6125,7 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {...@@ -6161,7 +6125,7 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
6161 const tag_size = Type.fromInterned(u.enum_tag_ty).abiSize(mod);6125 const tag_size = Type.fromInterned(u.enum_tag_ty).abiSize(mod);
6162 const tag_align = Type.fromInterned(u.enum_tag_ty).abiAlignment(mod).max(.@"1");6126 const tag_align = Type.fromInterned(u.enum_tag_ty).abiAlignment(mod).max(.@"1");
6163 return .{6127 return .{
6164 .abi_size = u.size,6128 .abi_size = u.size(ip).*,
6165 .abi_align = tag_align.max(payload_align),6129 .abi_align = tag_align.max(payload_align),
6166 .most_aligned_field = most_aligned_field,6130 .most_aligned_field = most_aligned_field,
6167 .most_aligned_field_size = most_aligned_field_size,6131 .most_aligned_field_size = most_aligned_field_size,
...@@ -6170,16 +6134,16 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {...@@ -6170,16 +6134,16 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
6170 .payload_align = payload_align,6134 .payload_align = payload_align,
6171 .tag_align = tag_align,6135 .tag_align = tag_align,
6172 .tag_size = tag_size,6136 .tag_size = tag_size,
6173 .padding = u.padding,6137 .padding = u.padding(ip).*,
6174 };6138 };
6175}6139}
61766140
6177pub fn unionAbiSize(mod: *Module, u: InternPool.UnionType) u64 {6141pub fn unionAbiSize(mod: *Module, u: InternPool.LoadedUnionType) u64 {
6178 return mod.getUnionLayout(u).abi_size;6142 return mod.getUnionLayout(u).abi_size;
6179}6143}
61806144
6181/// Returns 0 if the union is represented with 0 bits at runtime.6145/// 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 {
6183 const ip = &mod.intern_pool;6147 const ip = &mod.intern_pool;
6184 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();6148 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
6185 var max_align: Alignment = .none;6149 var max_align: Alignment = .none;
...@@ -6196,7 +6160,7 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) Alignment {...@@ -6196,7 +6160,7 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) Alignment {
6196/// Returns the field alignment, assuming the union is not packed.6160/// Returns the field alignment, assuming the union is not packed.
6197/// Keep implementation in sync with `Sema.unionFieldAlignment`.6161/// Keep implementation in sync with `Sema.unionFieldAlignment`.
6198/// Prefer to call that function instead of this one during Sema.6162/// 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 {
6200 const ip = &mod.intern_pool;6164 const ip = &mod.intern_pool;
6201 const field_align = u.fieldAlign(ip, field_index);6165 const field_align = u.fieldAlign(ip, field_index);
6202 if (field_align != .none) return field_align;6166 if (field_align != .none) return field_align;
...@@ -6205,12 +6169,11 @@ pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_in...@@ -6205,12 +6169,11 @@ pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_in
6205}6169}
62066170
6207/// Returns the index of the active field, given the current tag value6171/// 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 {
6209 const ip = &mod.intern_pool;6173 const ip = &mod.intern_pool;
6210 if (enum_tag.toIntern() == .none) return null;6174 if (enum_tag.toIntern() == .none) return null;
6211 assert(ip.typeOf(enum_tag.toIntern()) == u.enum_tag_ty);6175 assert(ip.typeOf(enum_tag.toIntern()) == u.enum_tag_ty);
6212 const enum_type = ip.indexToKey(u.enum_tag_ty).enum_type;6176 return u.loadTagType(ip).tagValueIndex(ip, enum_tag.toIntern());
6213 return enum_type.tagValueIndex(ip, enum_tag.toIntern());
6214}6177}
62156178
6216/// Returns the field alignment of a non-packed struct in byte units.6179/// 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 {...@@ -6257,7 +6220,7 @@ pub fn structFieldAlignmentExtern(mod: *Module, field_ty: Type) Alignment {
6257/// projects.6220/// projects.
6258pub fn structPackedFieldBitOffset(6221pub fn structPackedFieldBitOffset(
6259 mod: *Module,6222 mod: *Module,
6260 struct_type: InternPool.Key.StructType,6223 struct_type: InternPool.LoadedStructType,
6261 field_index: u32,6224 field_index: u32,
6262) u16 {6225) u16 {
6263 const ip = &mod.intern_pool;6226 const ip = &mod.intern_pool;
src/Package/Module.zig+37-3
...@@ -63,6 +63,11 @@ pub const CreateOptions = struct {...@@ -63,6 +63,11 @@ pub const CreateOptions = struct {
6363
64 builtin_mod: ?*Package.Module,64 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
66 pub const Paths = struct {71 pub const Paths = struct {
67 root: Package.Path,72 root: Package.Path,
68 /// Relative to `root`. May contain path separators.73 /// Relative to `root`. May contain path separators.
...@@ -364,11 +369,37 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {...@@ -364,11 +369,37 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
364 .wasi_exec_model = options.global.wasi_exec_model,369 .wasi_exec_model = options.global.wasi_exec_model,
365 }, arena);370 }, 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
367 const new_file = try arena.create(File);382 const new_file = try arena.create(File);
368383
369 const digest = Cache.HashHelper.oneShot(generated_builtin_source);384 const bin_digest, const hex_digest = digest: {
370 const builtin_sub_path = try arena.dupe(u8, "b" ++ std.fs.path.sep_str ++ digest);385 var hasher: Cache.Hasher = Cache.hasher_init;
371 const new = try arena.create(Module);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
372 new.* = .{403 new.* = .{
373 .root = .{404 .root = .{
374 .root_dir = options.global_cache_directory,405 .root_dir = options.global_cache_directory,
...@@ -415,6 +446,9 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {...@@ -415,6 +446,9 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
415 .status = .never_loaded,446 .status = .never_loaded,
416 .mod = new,447 .mod = new,
417 .root_decl = .none,448 .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,
418 };452 };
419 break :b new;453 break :b new;
420 };454 };
src/Sema.zig+993-922
...@@ -155,7 +155,6 @@ const Namespace = Module.Namespace;...@@ -155,7 +155,6 @@ const Namespace = Module.Namespace;
155const CompileError = Module.CompileError;155const CompileError = Module.CompileError;
156const SemaError = Module.SemaError;156const SemaError = Module.SemaError;
157const Decl = Module.Decl;157const Decl = Module.Decl;
158const CaptureScope = Module.CaptureScope;
159const LazySrcLoc = std.zig.LazySrcLoc;158const LazySrcLoc = std.zig.LazySrcLoc;
160const RangeSet = @import("RangeSet.zig");159const RangeSet = @import("RangeSet.zig");
161const target_util = @import("target.zig");160const target_util = @import("target.zig");
...@@ -331,8 +330,6 @@ pub const Block = struct {...@@ -331,8 +330,6 @@ pub const Block = struct {
331 /// used to add a `func_instance` into the `InternPool`.330 /// used to add a `func_instance` into the `InternPool`.
332 params: std.MultiArrayList(Param) = .{},331 params: std.MultiArrayList(Param) = .{},
333332
334 wip_capture_scope: CaptureScope.Index,
335
336 label: ?*Label = null,333 label: ?*Label = null,
337 inlining: ?*Inlining,334 inlining: ?*Inlining,
338 /// If runtime_index is not 0 then one of these is guaranteed to be non null.335 /// If runtime_index is not 0 then one of these is guaranteed to be non null.
...@@ -475,7 +472,6 @@ pub const Block = struct {...@@ -475,7 +472,6 @@ pub const Block = struct {
475 .src_decl = parent.src_decl,472 .src_decl = parent.src_decl,
476 .namespace = parent.namespace,473 .namespace = parent.namespace,
477 .instructions = .{},474 .instructions = .{},
478 .wip_capture_scope = parent.wip_capture_scope,
479 .label = null,475 .label = null,
480 .inlining = parent.inlining,476 .inlining = parent.inlining,
481 .is_comptime = parent.is_comptime,477 .is_comptime = parent.is_comptime,
...@@ -974,12 +970,6 @@ fn analyzeBodyInner(...@@ -974,12 +970,6 @@ fn analyzeBodyInner(
974970
975 try sema.inst_map.ensureSpaceForInstructions(sema.gpa, body);971 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
983 const mod = sema.mod;973 const mod = sema.mod;
984 const map = &sema.inst_map;974 const map = &sema.inst_map;
985 const tags = sema.code.instructions.items(.tag);975 const tags = sema.code.instructions.items(.tag);
...@@ -1028,7 +1018,6 @@ fn analyzeBodyInner(...@@ -1028,7 +1018,6 @@ fn analyzeBodyInner(
1028 .c_import => try sema.zirCImport(block, inst),1018 .c_import => try sema.zirCImport(block, inst),
1029 .call => try sema.zirCall(block, inst, .direct),1019 .call => try sema.zirCall(block, inst, .direct),
1030 .field_call => try sema.zirCall(block, inst, .field),1020 .field_call => try sema.zirCall(block, inst, .field),
1031 .closure_get => try sema.zirClosureGet(block, inst),
1032 .cmp_lt => try sema.zirCmp(block, inst, .lt),1021 .cmp_lt => try sema.zirCmp(block, inst, .lt),
1033 .cmp_lte => try sema.zirCmp(block, inst, .lte),1022 .cmp_lte => try sema.zirCmp(block, inst, .lte),
1034 .cmp_eq => try sema.zirCmpEq(block, inst, .eq, Air.Inst.Tag.fromCmpOp(.eq, block.float_mode == .Optimized)),1023 .cmp_eq => try sema.zirCmpEq(block, inst, .eq, Air.Inst.Tag.fromCmpOp(.eq, block.float_mode == .Optimized)),
...@@ -1275,6 +1264,7 @@ fn analyzeBodyInner(...@@ -1275,6 +1264,7 @@ fn analyzeBodyInner(
1275 .work_group_size => try sema.zirWorkItem( block, extended, extended.opcode),1264 .work_group_size => try sema.zirWorkItem( block, extended, extended.opcode),
1276 .work_group_id => try sema.zirWorkItem( block, extended, extended.opcode),1265 .work_group_id => try sema.zirWorkItem( block, extended, extended.opcode),
1277 .in_comptime => try sema.zirInComptime( block),1266 .in_comptime => try sema.zirInComptime( block),
1267 .closure_get => try sema.zirClosureGet( block, extended),
1278 // zig fmt: on1268 // zig fmt: on
12791269
1280 .fence => {1270 .fence => {
...@@ -1453,11 +1443,6 @@ fn analyzeBodyInner(...@@ -1453,11 +1443,6 @@ fn analyzeBodyInner(
1453 i += 1;1443 i += 1;
1454 continue;1444 continue;
1455 },1445 },
1456 .closure_capture => {
1457 try sema.zirClosureCapture(block, inst);
1458 i += 1;
1459 continue;
1460 },
1461 .memcpy => {1446 .memcpy => {
1462 try sema.zirMemcpy(block, inst);1447 try sema.zirMemcpy(block, inst);
1463 i += 1;1448 i += 1;
...@@ -1534,11 +1519,6 @@ fn analyzeBodyInner(...@@ -1534,11 +1519,6 @@ fn analyzeBodyInner(
1534 // Send comptime control flow back to the beginning of this block.1519 // Send comptime control flow back to the beginning of this block.
1535 const src = LazySrcLoc.nodeOffset(datas[@intFromEnum(inst)].node);1520 const src = LazySrcLoc.nodeOffset(datas[@intFromEnum(inst)].node);
1536 try sema.emitBackwardBranch(block, src);1521 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
1542 i = 0;1522 i = 0;
1543 continue;1523 continue;
1544 } else {1524 } else {
...@@ -1552,11 +1532,6 @@ fn analyzeBodyInner(...@@ -1552,11 +1532,6 @@ fn analyzeBodyInner(
1552 // Send comptime control flow back to the beginning of this block.1532 // Send comptime control flow back to the beginning of this block.
1553 const src = LazySrcLoc.nodeOffset(datas[@intFromEnum(inst)].node);1533 const src = LazySrcLoc.nodeOffset(datas[@intFromEnum(inst)].node);
1554 try sema.emitBackwardBranch(block, src);1534 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
1560 i = 0;1535 i = 0;
1561 continue;1536 continue;
1562 },1537 },
...@@ -1855,10 +1830,6 @@ fn analyzeBodyInner(...@@ -1855,10 +1830,6 @@ fn analyzeBodyInner(
1855 map.putAssumeCapacity(inst, air_inst);1830 map.putAssumeCapacity(inst, air_inst);
1856 i += 1;1831 i += 1;
1857 }1832 }
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;
1862}1833}
18631834
1864pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {1835pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
...@@ -2698,21 +2669,61 @@ fn analyzeAsInt(...@@ -2698,21 +2669,61 @@ fn analyzeAsInt(
2698 return (try val.getUnsignedIntAdvanced(mod, sema)).?;2669 return (try val.getUnsignedIntAdvanced(mod, sema)).?;
2699}2670}
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(
2702 sema: *Sema,2709 sema: *Sema,
2703 decl: InternPool.DeclIndex,2710 block: *Block,
2704 namespace: InternPool.NamespaceIndex,2711 extended: Zir.Inst.Extended.InstData,
2705 tracked_inst: InternPool.TrackedInst.Index,2712 inst: Zir.Inst.Index,
2706) !InternPool.Index {2713) CompileError!Air.Inst.Ref {
2707 const mod = sema.mod;2714 const mod = sema.mod;
2708 const gpa = sema.gpa;2715 const gpa = sema.gpa;
2709 const ip = &mod.intern_pool;2716 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);
2713 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);2717 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;
2716 const fields_len = if (small.has_fields_len) blk: {2727 const fields_len = if (small.has_fields_len) blk: {
2717 const fields_len = sema.code.extra[extra_index];2728 const fields_len = sema.code.extra[extra_index];
2718 extra_index += 1;2729 extra_index += 1;
...@@ -2724,6 +2735,9 @@ pub fn getStructType(...@@ -2724,6 +2735,9 @@ pub fn getStructType(
2724 break :blk decls_len;2735 break :blk decls_len;
2725 } else 0;2736 } else 0;
27262737
2738 const captures = try sema.getCaptures(block, extra_index, captures_len);
2739 extra_index += captures_len;
2740
2727 if (small.has_backing_int) {2741 if (small.has_backing_int) {
2728 const backing_int_body_len = sema.code.extra[extra_index];2742 const backing_int_body_len = sema.code.extra[extra_index];
2729 extra_index += 1; // backing_int_body_len2743 extra_index += 1; // backing_int_body_len
...@@ -2734,49 +2748,38 @@ pub fn getStructType(...@@ -2734,49 +2748,38 @@ pub fn getStructType(
2734 }2748 }
2735 }2749 }
27362750
2737 const decls = sema.code.bodySlice(extra_index, decls_len);2751 const wip_ty = switch (try ip.getStructType(gpa, .{
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(),
2745 .layout = small.layout,2752 .layout = small.layout,
2746 .known_non_opv = small.known_non_opv,
2747 .is_tuple = small.is_tuple,
2748 .fields_len = fields_len,2753 .fields_len = fields_len,
2754 .known_non_opv = small.known_non_opv,
2749 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,2755 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
2750 .any_default_inits = small.any_default_inits,2756 .is_tuple = small.is_tuple,
2751 .any_comptime_fields = small.any_comptime_fields,2757 .any_comptime_fields = small.any_comptime_fields,
2758 .any_default_inits = small.any_default_inits,
2752 .inits_resolved = false,2759 .inits_resolved = false,
2753 .any_aligned_fields = small.any_aligned_fields,2760 .any_aligned_fields = small.any_aligned_fields,
2754 });2761 .has_namespace = true or decls_len > 0, // TODO: see below
27552762 .key = .{ .declared = .{
2756 return ty;2763 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
2757}2764 .captures = captures,
27582765 } },
2759fn zirStructDecl(2766 })) {
2760 sema: *Sema,2767 .existing => |ty| return Air.internedToRef(ty),
2761 block: *Block,2768 .wip => |wip| wip: {
2762 extended: Zir.Inst.Extended.InstData,2769 if (sema.builtin_type_target_index == .none) break :wip wip;
2763 inst: Zir.Inst.Index,2770 var new = wip;
2764) CompileError!Air.Inst.Ref {2771 new.index = sema.builtin_type_target_index;
2765 const mod = sema.mod;2772 ip.resolveBuiltinType(new.index, wip.index);
2766 const ip = &mod.intern_pool;2773 break :wip new;
2767 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);2774 },
2768 const src = sema.code.extraData(Zir.Inst.StructDecl, extended.operand).data.src();2775 };
27692776 errdefer wip_ty.cancel(ip);
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.
27732777
2774 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{2778 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2775 .ty = Type.noreturn,2779 .ty = Type.type,
2776 .val = Value.@"unreachable",2780 .val = Value.fromInterned(wip_ty.index),
2777 }, small.name_strategy, "struct", inst);2781 }, small.name_strategy, "struct", inst);
2778 const new_decl = mod.declPtr(new_decl_index);2782 mod.declPtr(new_decl_index).owns_tv = true;
2779 new_decl.owns_tv = true;
2780 errdefer mod.abortAnonDecl(new_decl_index);2783 errdefer mod.abortAnonDecl(new_decl_index);
27812784
2782 if (sema.mod.comp.debug_incremental) {2785 if (sema.mod.comp.debug_incremental) {
...@@ -2787,31 +2790,21 @@ fn zirStructDecl(...@@ -2787,31 +2790,21 @@ fn zirStructDecl(
2787 );2790 );
2788 }2791 }
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(.{
2791 .parent = block.namespace.toOptional(),2795 .parent = block.namespace.toOptional(),
2792 .decl_index = new_decl_index,2796 .decl_index = new_decl_index,
2793 .file_scope = block.getFileScope(mod),2797 .file_scope = block.getFileScope(mod),
2794 });2798 })).toOptional() else .none;
2795 errdefer mod.destroyNamespace(new_namespace_index);2799 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
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);
28082800
2809 new_decl.ty = Type.type;2801 if (new_namespace_index.unwrap()) |ns| {
2810 new_decl.val = Value.fromInterned(struct_ty);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);
2813 try mod.finalizeAnonDecl(new_decl_index);2806 try mod.finalizeAnonDecl(new_decl_index);
2814 return decl_val;2807 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
2815}2808}
28162809
2817fn createAnonymousDeclTypeNamed(2810fn createAnonymousDeclTypeNamed(
...@@ -2827,10 +2820,9 @@ fn createAnonymousDeclTypeNamed(...@@ -2827,10 +2820,9 @@ fn createAnonymousDeclTypeNamed(
2827 const ip = &mod.intern_pool;2820 const ip = &mod.intern_pool;
2828 const gpa = sema.gpa;2821 const gpa = sema.gpa;
2829 const namespace = block.namespace;2822 const namespace = block.namespace;
2830 const src_scope = block.wip_capture_scope;
2831 const src_decl = mod.declPtr(block.src_decl);2823 const src_decl = mod.declPtr(block.src_decl);
2832 const src_node = src_decl.relativeToNodeIndex(src.node_offset.x);2824 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);
2834 errdefer mod.destroyDecl(new_decl_index);2826 errdefer mod.destroyDecl(new_decl_index);
28352827
2836 switch (name_strategy) {2828 switch (name_strategy) {
...@@ -2922,6 +2914,7 @@ fn zirEnumDecl(...@@ -2922,6 +2914,7 @@ fn zirEnumDecl(
29222914
2923 const mod = sema.mod;2915 const mod = sema.mod;
2924 const gpa = sema.gpa;2916 const gpa = sema.gpa;
2917 const ip = &mod.intern_pool;
2925 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);2918 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
2926 const extra = sema.code.extraData(Zir.Inst.EnumDecl, extended.operand);2919 const extra = sema.code.extraData(Zir.Inst.EnumDecl, extended.operand);
2927 var extra_index: usize = extra.end;2920 var extra_index: usize = extra.end;
...@@ -2935,6 +2928,12 @@ fn zirEnumDecl(...@@ -2935,6 +2928,12 @@ fn zirEnumDecl(
2935 break :blk tag_type_ref;2928 break :blk tag_type_ref;
2936 } else .none;2929 } 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
2938 const body_len = if (small.has_body_len) blk: {2937 const body_len = if (small.has_body_len) blk: {
2939 const body_len = sema.code.extra[extra_index];2938 const body_len = sema.code.extra[extra_index];
2940 extra_index += 1;2939 extra_index += 1;
...@@ -2953,14 +2952,57 @@ fn zirEnumDecl(...@@ -2953,14 +2952,57 @@ fn zirEnumDecl(
2953 break :blk decls_len;2952 break :blk decls_len;
2954 } else 0;2953 } else 0;
29552954
2956 // Because these three things each reference each other, `undefined`2955 const captures = try sema.getCaptures(block, extra_index, captures_len);
2957 // placeholders are used before being set after the enum type gains an2956 extra_index += captures_len;
2958 // InternPool index.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.
2960 var done = false;2999 var done = false;
3000
3001 errdefer if (!done) wip_ty.cancel(ip);
3002
2961 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{3003 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2962 .ty = Type.noreturn,3004 .ty = Type.type,
2963 .val = Value.@"unreachable",3005 .val = Value.fromInterned(wip_ty.index),
2964 }, small.name_strategy, "enum", inst);3006 }, small.name_strategy, "enum", inst);
2965 const new_decl = mod.declPtr(new_decl_index);3007 const new_decl = mod.declPtr(new_decl_index);
2966 new_decl.owns_tv = true;3008 new_decl.owns_tv = true;
...@@ -2974,56 +3016,21 @@ fn zirEnumDecl(...@@ -2974,56 +3016,21 @@ fn zirEnumDecl(
2974 );3016 );
2975 }3017 }
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(.{
2978 .parent = block.namespace.toOptional(),3021 .parent = block.namespace.toOptional(),
2979 .decl_index = new_decl_index,3022 .decl_index = new_decl_index,
2980 .file_scope = block.getFileScope(mod),3023 .file_scope = block.getFileScope(mod),
2981 });3024 })).toOptional() else .none;
2982 errdefer if (!done) mod.destroyNamespace(new_namespace_index);3025 errdefer if (!done) if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
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;
29873026
2988 const body = sema.code.bodySlice(extra_index, body_len);3027 if (new_namespace_index.unwrap()) |ns| {
2989 extra_index += body.len;3028 try mod.scanNamespace(ns, decls, new_decl);
29903029 }
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);
30243030
3025 const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);3031 // We've finished the initial construction of this type, and are about to perform analysis.
3026 try mod.finalizeAnonDecl(new_decl_index);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);
3027 done = true;3034 done = true;
30283035
3029 const int_tag_ty = ty: {3036 const int_tag_ty = ty: {
...@@ -3053,8 +3060,7 @@ fn zirEnumDecl(...@@ -3053,8 +3060,7 @@ fn zirEnumDecl(
3053 .parent = null,3060 .parent = null,
3054 .sema = sema,3061 .sema = sema,
3055 .src_decl = new_decl_index,3062 .src_decl = new_decl_index,
3056 .namespace = new_namespace_index,3063 .namespace = new_namespace_index.unwrap() orelse block.namespace,
3057 .wip_capture_scope = try mod.createCaptureScope(new_decl.src_scope),
3058 .instructions = .{},3064 .instructions = .{},
3059 .inlining = null,3065 .inlining = null,
3060 .is_comptime = true,3066 .is_comptime = true,
...@@ -3070,7 +3076,6 @@ fn zirEnumDecl(...@@ -3070,7 +3076,6 @@ fn zirEnumDecl(
3070 if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) {3076 if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) {
3071 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});3077 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
3072 }3078 }
3073 incomplete_enum.setTagType(&mod.intern_pool, ty.toIntern());
3074 break :ty ty;3079 break :ty ty;
3075 } else if (fields_len == 0) {3080 } else if (fields_len == 0) {
3076 break :ty try mod.intType(.unsigned, 0);3081 break :ty try mod.intType(.unsigned, 0);
...@@ -3080,6 +3085,8 @@ fn zirEnumDecl(...@@ -3080,6 +3085,8 @@ fn zirEnumDecl(
3080 }3085 }
3081 };3086 };
30823087
3088 wip_ty.setTagTy(ip, int_tag_ty.toIntern());
3089
3083 if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {3090 if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
3084 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(mod)) {3091 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(mod)) {
3085 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});3092 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
...@@ -3103,7 +3110,6 @@ fn zirEnumDecl(...@@ -3103,7 +3110,6 @@ fn zirEnumDecl(
3103 extra_index += 2; // field name, doc comment3110 extra_index += 2; // field name, doc comment
31043111
3105 const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir);3112 const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir);
3106 assert(incomplete_enum.addFieldName(&mod.intern_pool, field_name) == null);
31073113
3108 const tag_overflow = if (has_tag_value) overflow: {3114 const tag_overflow = if (has_tag_value) overflow: {
3109 const tag_val_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);3115 const tag_val_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
...@@ -3124,12 +3130,13 @@ fn zirEnumDecl(...@@ -3124,12 +3130,13 @@ fn zirEnumDecl(
3124 };3130 };
3125 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;3131 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;
3126 last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty);3132 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
3128 const value_src = mod.fieldSrcLoc(new_decl_index, .{3135 const value_src = mod.fieldSrcLoc(new_decl_index, .{
3129 .index = field_i,3136 .index = field_i,
3130 .range = .value,3137 .range = .value,
3131 }).lazy;3138 }).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;
3133 const msg = msg: {3140 const msg = msg: {
3134 const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});3141 const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});
3135 errdefer msg.destroy(gpa);3142 errdefer msg.destroy(gpa);
...@@ -3146,9 +3153,10 @@ fn zirEnumDecl(...@@ -3146,9 +3153,10 @@ fn zirEnumDecl(
3146 else3153 else
3147 try mod.intValue(int_tag_ty, 0);3154 try mod.intValue(int_tag_ty, 0);
3148 if (overflow != null) break :overflow true;3155 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
3150 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;3158 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;
3152 const msg = msg: {3160 const msg = msg: {
3153 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});3161 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});
3154 errdefer msg.destroy(gpa);3162 errdefer msg.destroy(gpa);
...@@ -3159,6 +3167,7 @@ fn zirEnumDecl(...@@ -3159,6 +3167,7 @@ fn zirEnumDecl(
3159 }3167 }
3160 break :overflow false;3168 break :overflow false;
3161 } else overflow: {3169 } else overflow: {
3170 assert(wip_ty.nextField(&mod.intern_pool, field_name, .none) == null);
3162 last_tag_val = try mod.intValue(Type.comptime_int, field_i);3171 last_tag_val = try mod.intValue(Type.comptime_int, field_i);
3163 if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true;3172 if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true;
3164 last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty);3173 last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty);
...@@ -3176,7 +3185,9 @@ fn zirEnumDecl(...@@ -3176,7 +3185,9 @@ fn zirEnumDecl(
3176 return sema.failWithOwnedErrorMsg(block, msg);3185 return sema.failWithOwnedErrorMsg(block, msg);
3177 }3186 }
3178 }3187 }
3179 return decl_val;3188
3189 try mod.finalizeAnonDecl(new_decl_index);
3190 return Air.internedToRef(wip_ty.index);
3180}3191}
31813192
3182fn zirUnionDecl(3193fn zirUnionDecl(
...@@ -3190,6 +3201,7 @@ fn zirUnionDecl(...@@ -3190,6 +3201,7 @@ fn zirUnionDecl(
31903201
3191 const mod = sema.mod;3202 const mod = sema.mod;
3192 const gpa = sema.gpa;3203 const gpa = sema.gpa;
3204 const ip = &mod.intern_pool;
3193 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);3205 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
3194 const extra = sema.code.extraData(Zir.Inst.UnionDecl, extended.operand);3206 const extra = sema.code.extraData(Zir.Inst.UnionDecl, extended.operand);
3195 var extra_index: usize = extra.end;3207 var extra_index: usize = extra.end;
...@@ -3197,6 +3209,11 @@ fn zirUnionDecl(...@@ -3197,6 +3209,11 @@ fn zirUnionDecl(
3197 const src = extra.data.src();3209 const src = extra.data.src();
31983210
3199 extra_index += @intFromBool(small.has_tag_type);3211 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;
3200 extra_index += @intFromBool(small.has_body_len);3217 extra_index += @intFromBool(small.has_body_len);
3201 const fields_len = if (small.has_fields_len) blk: {3218 const fields_len = if (small.has_fields_len) blk: {
3202 const fields_len = sema.code.extra[extra_index];3219 const fields_len = sema.code.extra[extra_index];
...@@ -3210,16 +3227,53 @@ fn zirUnionDecl(...@@ -3210,16 +3227,53 @@ fn zirUnionDecl(
3210 break :blk decls_len;3227 break :blk decls_len;
3211 } else 0;3228 } else 0;
32123229
3213 // Because these three things each reference each other, `undefined`3230 const captures = try sema.getCaptures(block, extra_index, captures_len);
3214 // placeholders are used before being set after the union type gains an3231 extra_index += captures_len;
3215 // InternPool index.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
3217 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{3272 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
3218 .ty = Type.noreturn,3273 .ty = Type.type,
3219 .val = Value.@"unreachable",3274 .val = Value.fromInterned(wip_ty.index),
3220 }, small.name_strategy, "union", inst);3275 }, small.name_strategy, "union", inst);
3221 const new_decl = mod.declPtr(new_decl_index);3276 mod.declPtr(new_decl_index).owns_tv = true;
3222 new_decl.owns_tv = true;
3223 errdefer mod.abortAnonDecl(new_decl_index);3277 errdefer mod.abortAnonDecl(new_decl_index);
32243278
3225 if (sema.mod.comp.debug_incremental) {3279 if (sema.mod.comp.debug_incremental) {
...@@ -3230,58 +3284,22 @@ fn zirUnionDecl(...@@ -3230,58 +3284,22 @@ fn zirUnionDecl(
3230 );3284 );
3231 }3285 }
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(.{
3234 .parent = block.namespace.toOptional(),3289 .parent = block.namespace.toOptional(),
3235 .decl_index = new_decl_index,3290 .decl_index = new_decl_index,
3236 .file_scope = block.getFileScope(mod),3291 .file_scope = block.getFileScope(mod),
3237 });3292 })).toOptional() else .none;
3238 errdefer mod.destroyNamespace(new_namespace_index);3293 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
32393294
3240 const union_ty = ty: {3295 if (new_namespace_index.unwrap()) |ns| {
3241 const ty = try mod.intern_pool.getUnionType(gpa, .{3296 const decls = sema.code.bodySlice(extra_index, decls_len);
3242 .flags = .{3297 try mod.scanNamespace(ns, decls, mod.declPtr(new_decl_index));
3243 .layout = small.layout,3298 }
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);
32813299
3282 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
3283 try mod.finalizeAnonDecl(new_decl_index);3300 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));
3285}3303}
32863304
3287fn zirOpaqueDecl(3305fn zirOpaqueDecl(
...@@ -3294,62 +3312,72 @@ fn zirOpaqueDecl(...@@ -3294,62 +3312,72 @@ fn zirOpaqueDecl(
3294 defer tracy.end();3312 defer tracy.end();
32953313
3296 const mod = sema.mod;3314 const mod = sema.mod;
3315 const gpa = sema.gpa;
3316 const ip = &mod.intern_pool;
3317
3297 const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);3318 const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
3298 const extra = sema.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);3319 const extra = sema.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
3299 var extra_index: usize = extra.end;3320 var extra_index: usize = extra.end;
33003321
3301 const src = extra.data.src();3322 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
3303 const decls_len = if (small.has_decls_len) blk: {3330 const decls_len = if (small.has_decls_len) blk: {
3304 const decls_len = sema.code.extra[extra_index];3331 const decls_len = sema.code.extra[extra_index];
3305 extra_index += 1;3332 extra_index += 1;
3306 break :blk decls_len;3333 break :blk decls_len;
3307 } else 0;3334 } else 0;
33083335
3309 // Because these three things each reference each other, `undefined`3336 const captures = try sema.getCaptures(block, extra_index, captures_len);
3310 // placeholders are used in two places before being set after the opaque3337 extra_index += captures_len;
3311 // type gains an InternPool index.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
3313 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{3351 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
3314 .ty = Type.noreturn,3352 .ty = Type.type,
3315 .val = Value.@"unreachable",3353 .val = Value.fromInterned(wip_ty.index),
3316 }, small.name_strategy, "opaque", inst);3354 }, small.name_strategy, "opaque", inst);
3317 const new_decl = mod.declPtr(new_decl_index);3355 mod.declPtr(new_decl_index).owns_tv = true;
3318 new_decl.owns_tv = true;
3319 errdefer mod.abortAnonDecl(new_decl_index);3356 errdefer mod.abortAnonDecl(new_decl_index);
33203357
3321 if (sema.mod.comp.debug_incremental) {3358 if (sema.mod.comp.debug_incremental) {
3322 try mod.intern_pool.addDependency(3359 try ip.addDependency(
3323 sema.gpa,3360 gpa,
3324 InternPool.Depender.wrap(.{ .decl = new_decl_index }),3361 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) },
3326 );3363 );
3327 }3364 }
33283365
3329 const new_namespace_index = try mod.createNamespace(.{3366 const new_namespace_index: InternPool.OptionalNamespaceIndex = if (decls_len > 0) (try mod.createNamespace(.{
3330 .parent = block.namespace.toOptional(),3367 .parent = block.namespace.toOptional(),
3331 .decl_index = new_decl_index,3368 .decl_index = new_decl_index,
3332 .file_scope = block.getFileScope(mod),3369 .file_scope = block.getFileScope(mod),
3333 });3370 })).toOptional() else .none;
3334 errdefer mod.destroyNamespace(new_namespace_index);3371 errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
33353372
3336 const opaque_ty = try mod.intern(.{ .opaque_type = .{3373 if (new_namespace_index.unwrap()) |ns| {
3337 .decl = new_decl_index,3374 const decls = sema.code.bodySlice(extra_index, decls_len);
3338 .namespace = new_namespace_index,3375 try mod.scanNamespace(ns, decls, mod.declPtr(new_decl_index));
3339 .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),3376 }
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);
33493377
3350 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
3351 try mod.finalizeAnonDecl(new_decl_index);3378 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));
3353}3381}
33543382
3355fn zirErrorSetDecl(3383fn zirErrorSetDecl(
...@@ -5333,7 +5361,7 @@ fn failWithBadMemberAccess(...@@ -5333,7 +5361,7 @@ fn failWithBadMemberAccess(
5333fn failWithBadStructFieldAccess(5361fn failWithBadStructFieldAccess(
5334 sema: *Sema,5362 sema: *Sema,
5335 block: *Block,5363 block: *Block,
5336 struct_type: InternPool.Key.StructType,5364 struct_type: InternPool.LoadedStructType,
5337 field_src: LazySrcLoc,5365 field_src: LazySrcLoc,
5338 field_name: InternPool.NullTerminatedString,5366 field_name: InternPool.NullTerminatedString,
5339) CompileError {5367) CompileError {
...@@ -5359,7 +5387,7 @@ fn failWithBadStructFieldAccess(...@@ -5359,7 +5387,7 @@ fn failWithBadStructFieldAccess(
5359fn failWithBadUnionFieldAccess(5387fn failWithBadUnionFieldAccess(
5360 sema: *Sema,5388 sema: *Sema,
5361 block: *Block,5389 block: *Block,
5362 union_obj: InternPool.UnionType,5390 union_obj: InternPool.LoadedUnionType,
5363 field_src: LazySrcLoc,5391 field_src: LazySrcLoc,
5364 field_name: InternPool.NullTerminatedString,5392 field_name: InternPool.NullTerminatedString,
5365) CompileError {5393) CompileError {
...@@ -5780,7 +5808,6 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5780,7 +5808,6 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
5780 .sema = sema,5808 .sema = sema,
5781 .src_decl = parent_block.src_decl,5809 .src_decl = parent_block.src_decl,
5782 .namespace = parent_block.namespace,5810 .namespace = parent_block.namespace,
5783 .wip_capture_scope = parent_block.wip_capture_scope,
5784 .instructions = .{},5811 .instructions = .{},
5785 .inlining = parent_block.inlining,5812 .inlining = parent_block.inlining,
5786 .is_comptime = true,5813 .is_comptime = true,
...@@ -5831,6 +5858,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5831,6 +5858,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
5831 .global = comp.config,5858 .global = comp.config,
5832 .parent = parent_mod,5859 .parent = parent_mod,
5833 .builtin_mod = parent_mod.getBuiltinDependency(),5860 .builtin_mod = parent_mod.getBuiltinDependency(),
5861 .builtin_modules = null, // `builtin_mod` is set
5834 }) catch |err| switch (err) {5862 }) catch |err| switch (err) {
5835 // None of these are possible because we are creating a package with5863 // None of these are possible because we are creating a package with
5836 // the exact same configuration as the parent package, which already5864 // 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...@@ -5900,7 +5928,6 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index, force_compt
5900 .sema = sema,5928 .sema = sema,
5901 .src_decl = parent_block.src_decl,5929 .src_decl = parent_block.src_decl,
5902 .namespace = parent_block.namespace,5930 .namespace = parent_block.namespace,
5903 .wip_capture_scope = parent_block.wip_capture_scope,
5904 .instructions = .{},5931 .instructions = .{},
5905 .label = &label,5932 .label = &label,
5906 .inlining = parent_block.inlining,5933 .inlining = parent_block.inlining,
...@@ -7515,7 +7542,6 @@ fn analyzeCall(...@@ -7515,7 +7542,6 @@ fn analyzeCall(
7515 .sema = sema,7542 .sema = sema,
7516 .src_decl = module_fn.owner_decl,7543 .src_decl = module_fn.owner_decl,
7517 .namespace = fn_owner_decl.src_namespace,7544 .namespace = fn_owner_decl.src_namespace,
7518 .wip_capture_scope = try mod.createCaptureScope(fn_owner_decl.src_scope),
7519 .instructions = .{},7545 .instructions = .{},
7520 .label = null,7546 .label = null,
7521 .inlining = &inlining,7547 .inlining = &inlining,
...@@ -8036,7 +8062,6 @@ fn instantiateGenericCall(...@@ -8036,7 +8062,6 @@ fn instantiateGenericCall(
8036 .sema = &child_sema,8062 .sema = &child_sema,
8037 .src_decl = generic_owner_func.owner_decl,8063 .src_decl = generic_owner_func.owner_decl,
8038 .namespace = namespace_index,8064 .namespace = namespace_index,
8039 .wip_capture_scope = try mod.createCaptureScope(fn_owner_decl.src_scope),
8040 .instructions = .{},8065 .instructions = .{},
8041 .inlining = null,8066 .inlining = null,
8042 .is_comptime = true,8067 .is_comptime = true,
...@@ -11409,7 +11434,6 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp...@@ -11409,7 +11434,6 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
11409 .sema = sema,11434 .sema = sema,
11410 .src_decl = block.src_decl,11435 .src_decl = block.src_decl,
11411 .namespace = block.namespace,11436 .namespace = block.namespace,
11412 .wip_capture_scope = block.wip_capture_scope,
11413 .instructions = .{},11437 .instructions = .{},
11414 .label = &label,11438 .label = &label,
11415 .inlining = block.inlining,11439 .inlining = block.inlining,
...@@ -12117,7 +12141,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r...@@ -12117,7 +12141,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
12117 .sema = sema,12141 .sema = sema,
12118 .src_decl = block.src_decl,12142 .src_decl = block.src_decl,
12119 .namespace = block.namespace,12143 .namespace = block.namespace,
12120 .wip_capture_scope = block.wip_capture_scope,
12121 .instructions = .{},12144 .instructions = .{},
12122 .label = &label,12145 .label = &label,
12123 .inlining = block.inlining,12146 .inlining = block.inlining,
...@@ -12281,7 +12304,6 @@ fn analyzeSwitchRuntimeBlock(...@@ -12281,7 +12304,6 @@ fn analyzeSwitchRuntimeBlock(
12281 extra_index += info.body_len;12304 extra_index += info.body_len;
1228212305
12283 case_block.instructions.shrinkRetainingCapacity(0);12306 case_block.instructions.shrinkRetainingCapacity(0);
12284 case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
1228512307
12286 const item = case_vals.items[scalar_i];12308 const item = case_vals.items[scalar_i];
12287 // `item` is already guaranteed to be constant known.12309 // `item` is already guaranteed to be constant known.
...@@ -12339,7 +12361,6 @@ fn analyzeSwitchRuntimeBlock(...@@ -12339,7 +12361,6 @@ fn analyzeSwitchRuntimeBlock(
12339 case_val_idx += items_len;12361 case_val_idx += items_len;
1234012362
12341 case_block.instructions.shrinkRetainingCapacity(0);12363 case_block.instructions.shrinkRetainingCapacity(0);
12342 case_block.wip_capture_scope = child_block.wip_capture_scope;
1234312364
12344 // Generate all possible cases as scalar prongs.12365 // Generate all possible cases as scalar prongs.
12345 if (info.is_inline) {12366 if (info.is_inline) {
...@@ -12371,7 +12392,6 @@ fn analyzeSwitchRuntimeBlock(...@@ -12371,7 +12392,6 @@ fn analyzeSwitchRuntimeBlock(
12371 const item_ref = Air.internedToRef(item.toIntern());12392 const item_ref = Air.internedToRef(item.toIntern());
1237212393
12373 case_block.instructions.shrinkRetainingCapacity(0);12394 case_block.instructions.shrinkRetainingCapacity(0);
12374 case_block.wip_capture_scope = child_block.wip_capture_scope;
1237512395
12376 if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) {12396 if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) {
12377 error.NeededSourceLocation => {12397 error.NeededSourceLocation => {
...@@ -12411,7 +12431,6 @@ fn analyzeSwitchRuntimeBlock(...@@ -12411,7 +12431,6 @@ fn analyzeSwitchRuntimeBlock(
12411 cases_len += 1;12431 cases_len += 1;
1241212432
12413 case_block.instructions.shrinkRetainingCapacity(0);12433 case_block.instructions.shrinkRetainingCapacity(0);
12414 case_block.wip_capture_scope = child_block.wip_capture_scope;
1241512434
12416 const analyze_body = if (union_originally) blk: {12435 const analyze_body = if (union_originally) blk: {
12417 const item_val = sema.resolveConstDefinedValue(block, .unneeded, item, undefined) catch unreachable;12436 const item_val = sema.resolveConstDefinedValue(block, .unneeded, item, undefined) catch unreachable;
...@@ -12557,7 +12576,6 @@ fn analyzeSwitchRuntimeBlock(...@@ -12557,7 +12576,6 @@ fn analyzeSwitchRuntimeBlock(
12557 defer gpa.free(cond_body);12576 defer gpa.free(cond_body);
1255812577
12559 case_block.instructions.shrinkRetainingCapacity(0);12578 case_block.instructions.shrinkRetainingCapacity(0);
12560 case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
1256112579
12562 const body = sema.code.bodySlice(extra_index, info.body_len);12580 const body = sema.code.bodySlice(extra_index, info.body_len);
12563 extra_index += info.body_len;12581 extra_index += info.body_len;
...@@ -12618,7 +12636,6 @@ fn analyzeSwitchRuntimeBlock(...@@ -12618,7 +12636,6 @@ fn analyzeSwitchRuntimeBlock(
12618 const item_ref = Air.internedToRef(item_val.toIntern());12636 const item_ref = Air.internedToRef(item_val.toIntern());
1261912637
12620 case_block.instructions.shrinkRetainingCapacity(0);12638 case_block.instructions.shrinkRetainingCapacity(0);
12621 case_block.wip_capture_scope = child_block.wip_capture_scope;
1262212639
12623 const analyze_body = if (union_originally) blk: {12640 const analyze_body = if (union_originally) blk: {
12624 const field_ty = maybe_union_ty.unionFieldType(item_val, mod).?;12641 const field_ty = maybe_union_ty.unionFieldType(item_val, mod).?;
...@@ -12669,7 +12686,6 @@ fn analyzeSwitchRuntimeBlock(...@@ -12669,7 +12686,6 @@ fn analyzeSwitchRuntimeBlock(
12669 const item_ref = Air.internedToRef(item_val);12686 const item_ref = Air.internedToRef(item_val);
1267012687
12671 case_block.instructions.shrinkRetainingCapacity(0);12688 case_block.instructions.shrinkRetainingCapacity(0);
12672 case_block.wip_capture_scope = child_block.wip_capture_scope;
1267312689
12674 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);12690 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
12675 emit_bb = true;12691 emit_bb = true;
...@@ -12700,7 +12716,6 @@ fn analyzeSwitchRuntimeBlock(...@@ -12700,7 +12716,6 @@ fn analyzeSwitchRuntimeBlock(
12700 const item_ref = Air.internedToRef(cur);12716 const item_ref = Air.internedToRef(cur);
1270112717
12702 case_block.instructions.shrinkRetainingCapacity(0);12718 case_block.instructions.shrinkRetainingCapacity(0);
12703 case_block.wip_capture_scope = child_block.wip_capture_scope;
1270412719
12705 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);12720 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
12706 emit_bb = true;12721 emit_bb = true;
...@@ -12728,7 +12743,6 @@ fn analyzeSwitchRuntimeBlock(...@@ -12728,7 +12743,6 @@ fn analyzeSwitchRuntimeBlock(
12728 cases_len += 1;12743 cases_len += 1;
1272912744
12730 case_block.instructions.shrinkRetainingCapacity(0);12745 case_block.instructions.shrinkRetainingCapacity(0);
12731 case_block.wip_capture_scope = child_block.wip_capture_scope;
1273212746
12733 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);12747 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
12734 emit_bb = true;12748 emit_bb = true;
...@@ -12754,7 +12768,6 @@ fn analyzeSwitchRuntimeBlock(...@@ -12754,7 +12768,6 @@ fn analyzeSwitchRuntimeBlock(
12754 cases_len += 1;12768 cases_len += 1;
1275512769
12756 case_block.instructions.shrinkRetainingCapacity(0);12770 case_block.instructions.shrinkRetainingCapacity(0);
12757 case_block.wip_capture_scope = child_block.wip_capture_scope;
1275812771
12759 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);12772 if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
12760 emit_bb = true;12773 emit_bb = true;
...@@ -12783,7 +12796,6 @@ fn analyzeSwitchRuntimeBlock(...@@ -12783,7 +12796,6 @@ fn analyzeSwitchRuntimeBlock(
12783 };12796 };
1278412797
12785 case_block.instructions.shrinkRetainingCapacity(0);12798 case_block.instructions.shrinkRetainingCapacity(0);
12786 case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
1278712799
12788 if (mod.backendSupportsFeature(.is_named_enum_value) and12800 if (mod.backendSupportsFeature(.is_named_enum_value) and
12789 special.body.len != 0 and block.wantSafety() and12801 special.body.len != 0 and block.wantSafety() and
...@@ -13327,7 +13339,7 @@ fn validateSwitchItemEnum(...@@ -13327,7 +13339,7 @@ fn validateSwitchItemEnum(
13327 const ip = &sema.mod.intern_pool;13339 const ip = &sema.mod.intern_pool;
13328 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);13340 const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
13329 const int = ip.indexToKey(item.val).enum_tag.int;13341 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 {
13331 const maybe_prev_src = try range_set.add(int, int, switch_prong_src);13343 const maybe_prev_src = try range_set.add(int, int, switch_prong_src);
13332 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);13344 try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
13333 return item.ref;13345 return item.ref;
...@@ -13607,15 +13619,15 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -13607,15 +13619,15 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
13607 break :hf field_index < ty.structFieldCount(mod);13619 break :hf field_index < ty.structFieldCount(mod);
13608 }13620 }
13609 },13621 },
13610 .struct_type => |struct_type| {13622 .struct_type => {
13611 break :hf struct_type.nameIndex(ip, field_name) != null;13623 break :hf ip.loadStructType(ty.toIntern()).nameIndex(ip, field_name) != null;
13612 },13624 },
13613 .union_type => |union_type| {13625 .union_type => {
13614 const union_obj = ip.loadUnionType(union_type);13626 const union_type = ip.loadUnionType(ty.toIntern());
13615 break :hf union_obj.nameIndex(ip, field_name) != null;13627 break :hf union_type.loadTagType(ip).nameIndex(ip, field_name) != null;
13616 },13628 },
13617 .enum_type => |enum_type| {13629 .enum_type => {
13618 break :hf enum_type.nameIndex(ip, field_name) != null;13630 break :hf ip.loadEnumType(ty.toIntern()).nameIndex(ip, field_name) != null;
13619 },13631 },
13620 .array_type => break :hf ip.stringEqlSlice(field_name, "len"),13632 .array_type => break :hf ip.stringEqlSlice(field_name, "len"),
13621 else => {},13633 else => {},
...@@ -17264,49 +17276,19 @@ fn zirThis(...@@ -17264,49 +17276,19 @@ fn zirThis(
17264 return sema.analyzeDeclVal(block, src, this_decl_index);17276 return sema.analyzeDeclVal(block, src, this_decl_index);
17265}17277}
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 {
17268 const mod = sema.mod;17280 const mod = sema.mod;
17269 const gpa = sema.gpa;17281 const ip = &mod.intern_pool;
17270 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_tok;17282 const captures = mod.namespacePtr(block.namespace).getType(mod).getCaptures(mod);
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}
1728817283
17289fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {17284 const src_node: i32 = @bitCast(extended.operand);
17290 const mod = sema.mod;17285 const src = LazySrcLoc.nodeOffset(src_node);
17291 //const ip = &mod.intern_pool;17286
17292 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].inst_node;17287 const capture_ty = switch (captures.get(ip)[extended.small].unwrap()) {
17293 var scope: CaptureScope.Index = mod.declPtr(block.src_decl).src_scope;17288 .@"comptime" => |index| return Air.internedToRef(index),
17294 assert(scope != .none);17289 .runtime => |index| index,
17295 // Note: The target closure must be in this scope list.17290 .decl_val => |decl_index| return sema.analyzeDeclVal(block, src, decl_index),
17296 // If it's not here, the zir is invalid, or the list is broken.17291 .decl_ref => |decl_index| return sema.analyzeDeclRef(decl_index),
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);
17310 };17292 };
1731117293
17312 // The comptime case is handled already above. Runtime case below.17294 // 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!...@@ -17322,15 +17304,15 @@ fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
17322 });17304 });
17323 break :name null;17305 break :name null;
17324 };17306 };
17325 const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node);17307 const node = sema.owner_decl.relativeToNodeIndex(src_node);
17326 const token = tree.nodes.items(.main_token)[node];17308 const token = tree.nodes.items(.main_token)[node];
17327 break :name tree.tokenSlice(token);17309 break :name tree.tokenSlice(token);
17328 };17310 };
1732917311
17330 const msg = if (name) |some|17312 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})
17332 else17314 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", .{});
17334 errdefer msg.destroy(sema.gpa);17316 errdefer msg.destroy(sema.gpa);
1733517317
17336 // TODO add "declared here" note17318 // TODO add "declared here" note
...@@ -17350,15 +17332,15 @@ fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -17350,15 +17332,15 @@ fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
17350 });17332 });
17351 break :name null;17333 break :name null;
17352 };17334 };
17353 const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node);17335 const node = sema.owner_decl.relativeToNodeIndex(src_node);
17354 const token = tree.nodes.items(.main_token)[node];17336 const token = tree.nodes.items(.main_token)[node];
17355 break :name tree.tokenSlice(token);17337 break :name tree.tokenSlice(token);
17356 };17338 };
1735717339
17358 const msg = if (name) |some|17340 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})
17360 else17342 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", .{});
17362 errdefer msg.destroy(sema.gpa);17344 errdefer msg.destroy(sema.gpa);
1736317345
17364 try sema.errNote(block, LazySrcLoc.nodeOffset(0), msg, "crossed function definition here", .{});17346 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...@@ -17954,7 +17936,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17954 } })));17936 } })));
17955 },17937 },
17956 .Enum => {17938 .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
17959 const enum_field_ty = t: {17941 const enum_field_ty = t: {
17960 const enum_field_ty_decl_index = (try sema.namespaceLookup(17942 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...@@ -17968,9 +17950,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17968 break :t enum_field_ty_decl.val.toType();17950 break :t enum_field_ty_decl.val.toType();
17969 };17951 };
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);
17972 for (enum_field_vals, 0..) |*field_val, i| {17954 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());
17974 const value_val = if (enum_type.values.len > 0)17956 const value_val = if (enum_type.values.len > 0)
17975 try mod.intern_pool.getCoercedInts(17957 try mod.intern_pool.getCoercedInts(
17976 mod.gpa,17958 mod.gpa,
...@@ -18045,7 +18027,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18045,7 +18027,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18045 } });18027 } });
18046 };18028 };
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
18050 const type_enum_ty = t: {18032 const type_enum_ty = t: {
18051 const type_enum_ty_decl_index = (try sema.namespaceLookup(18033 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...@@ -18061,7 +18043,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1806118043
18062 const field_values = .{18044 const field_values = .{
18063 // tag_type: type,18045 // tag_type: type,
18064 ip.indexToKey(ty.toIntern()).enum_type.tag_ty,18046 ip.loadEnumType(ty.toIntern()).tag_ty,
18065 // fields: []const EnumField,18047 // fields: []const EnumField,
18066 fields_val,18048 fields_val,
18067 // decls: []const Declaration,18049 // decls: []const Declaration,
...@@ -18105,14 +18087,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18105,14 +18087,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1810518087
18106 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout18088 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
18107 const union_obj = mod.typeToUnion(ty).?;18089 const union_obj = mod.typeToUnion(ty).?;
18090 const tag_type = union_obj.loadTagType(ip);
18108 const layout = union_obj.getLayout(ip);18091 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);
18111 defer gpa.free(union_field_vals);18094 defer gpa.free(union_field_vals);
1811218095
18113 for (union_field_vals, 0..) |*field_val, i| {18096 for (union_field_vals, 0..) |*field_val, i| {
18114 // TODO: write something like getCoercedInts to avoid needing to dupe18097 // 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]));
18116 const name_val = v: {18099 const name_val = v: {
18117 const new_decl_ty = try mod.arrayType(.{18100 const new_decl_ty = try mod.arrayType(.{
18118 .len = name.len,18101 .len = name.len,
...@@ -18314,7 +18297,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18314,7 +18297,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18314 }18297 }
18315 break :fv;18298 break :fv;
18316 },18299 },
18317 .struct_type => |s| s,18300 .struct_type => ip.loadStructType(ty.toIntern()),
18318 else => unreachable,18301 else => unreachable,
18319 };18302 };
18320 struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);18303 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...@@ -18631,7 +18614,6 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
18631 .sema = sema,18614 .sema = sema,
18632 .src_decl = block.src_decl,18615 .src_decl = block.src_decl,
18633 .namespace = block.namespace,18616 .namespace = block.namespace,
18634 .wip_capture_scope = block.wip_capture_scope,
18635 .instructions = .{},18617 .instructions = .{},
18636 .inlining = block.inlining,18618 .inlining = block.inlining,
18637 .is_comptime = false,18619 .is_comptime = false,
...@@ -18710,7 +18692,6 @@ fn zirTypeofPeer(...@@ -18710,7 +18692,6 @@ fn zirTypeofPeer(
18710 .sema = sema,18692 .sema = sema,
18711 .src_decl = block.src_decl,18693 .src_decl = block.src_decl,
18712 .namespace = block.namespace,18694 .namespace = block.namespace,
18713 .wip_capture_scope = block.wip_capture_scope,
18714 .instructions = .{},18695 .instructions = .{},
18715 .inlining = block.inlining,18696 .inlining = block.inlining,
18716 .is_comptime = false,18697 .is_comptime = false,
...@@ -19186,7 +19167,6 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label...@@ -19186,7 +19167,6 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label
19186 .sema = sema,19167 .sema = sema,
19187 .src_decl = block.src_decl,19168 .src_decl = block.src_decl,
19188 .namespace = block.namespace,19169 .namespace = block.namespace,
19189 .wip_capture_scope = block.wip_capture_scope,
19190 .instructions = .{},19170 .instructions = .{},
19191 .label = &labeled_block.label,19171 .label = &labeled_block.label,
19192 .inlining = block.inlining,19172 .inlining = block.inlining,
...@@ -20082,7 +20062,8 @@ fn finishStructInit(...@@ -20082,7 +20062,8 @@ fn finishStructInit(
20082 }20062 }
20083 }20063 }
20084 },20064 },
20085 .struct_type => |struct_type| {20065 .struct_type => {
20066 const struct_type = ip.loadStructType(struct_ty.toIntern());
20086 for (0..struct_type.field_types.len) |i| {20067 for (0..struct_type.field_types.len) |i| {
20087 if (field_inits[i] != .none) {20068 if (field_inits[i] != .none) {
20088 // Coerce the init value to the field type.20069 // Coerce the init value to the field type.
...@@ -20683,7 +20664,8 @@ fn fieldType(...@@ -20683,7 +20664,8 @@ fn fieldType(
20683 try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);20664 try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);
20684 return Air.internedToRef(anon_struct.types.get(ip)[field_index]);20665 return Air.internedToRef(anon_struct.types.get(ip)[field_index]);
20685 },20666 },
20686 .struct_type => |struct_type| {20667 .struct_type => {
20668 const struct_type = ip.loadStructType(cur_ty.toIntern());
20687 const field_index = struct_type.nameIndex(ip, field_name) orelse20669 const field_index = struct_type.nameIndex(ip, field_name) orelse
20688 return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name);20670 return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name);
20689 const field_ty = struct_type.field_types.get(ip)[field_index];20671 const field_ty = struct_type.field_types.get(ip)[field_index];
...@@ -20693,7 +20675,7 @@ fn fieldType(...@@ -20693,7 +20675,7 @@ fn fieldType(
20693 },20675 },
20694 .Union => {20676 .Union => {
20695 const union_obj = mod.typeToUnion(cur_ty).?;20677 const union_obj = mod.typeToUnion(cur_ty).?;
20696 const field_index = union_obj.nameIndex(ip, field_name) orelse20678 const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse
20697 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);20679 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
20698 const field_ty = union_obj.field_types.get(ip)[field_index];20680 const field_ty = union_obj.field_types.get(ip)[field_index];
20699 return Air.internedToRef(field_ty);20681 return Air.internedToRef(field_ty);
...@@ -21022,7 +21004,7 @@ fn zirReify(...@@ -21022,7 +21004,7 @@ fn zirReify(
21022 .AnyFrame => return sema.failWithUseOfAsync(block, src),21004 .AnyFrame => return sema.failWithUseOfAsync(block, src),
21023 .EnumLiteral => return .enum_literal_type,21005 .EnumLiteral => return .enum_literal_type,
21024 .Int => {21006 .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));
21026 const signedness_val = try Value.fromInterned(union_val.val).fieldValue(21008 const signedness_val = try Value.fromInterned(union_val.val).fieldValue(
21027 mod,21009 mod,
21028 struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "signedness")).?,21010 struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "signedness")).?,
...@@ -21038,7 +21020,7 @@ fn zirReify(...@@ -21038,7 +21020,7 @@ fn zirReify(
21038 return Air.internedToRef(ty.toIntern());21020 return Air.internedToRef(ty.toIntern());
21039 },21021 },
21040 .Vector => {21022 .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));
21042 const len_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21024 const len_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21043 ip,21025 ip,
21044 try ip.getOrPutString(gpa, "len"),21026 try ip.getOrPutString(gpa, "len"),
...@@ -21060,7 +21042,7 @@ fn zirReify(...@@ -21060,7 +21042,7 @@ fn zirReify(
21060 return Air.internedToRef(ty.toIntern());21042 return Air.internedToRef(ty.toIntern());
21061 },21043 },
21062 .Float => {21044 .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));
21064 const bits_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21046 const bits_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21065 ip,21047 ip,
21066 try ip.getOrPutString(gpa, "bits"),21048 try ip.getOrPutString(gpa, "bits"),
...@@ -21078,7 +21060,7 @@ fn zirReify(...@@ -21078,7 +21060,7 @@ fn zirReify(
21078 return Air.internedToRef(ty.toIntern());21060 return Air.internedToRef(ty.toIntern());
21079 },21061 },
21080 .Pointer => {21062 .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));
21082 const size_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21064 const size_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21083 ip,21065 ip,
21084 try ip.getOrPutString(gpa, "size"),21066 try ip.getOrPutString(gpa, "size"),
...@@ -21190,7 +21172,7 @@ fn zirReify(...@@ -21190,7 +21172,7 @@ fn zirReify(
21190 return Air.internedToRef(ty.toIntern());21172 return Air.internedToRef(ty.toIntern());
21191 },21173 },
21192 .Array => {21174 .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));
21194 const len_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21176 const len_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21195 ip,21177 ip,
21196 try ip.getOrPutString(gpa, "len"),21178 try ip.getOrPutString(gpa, "len"),
...@@ -21219,7 +21201,7 @@ fn zirReify(...@@ -21219,7 +21201,7 @@ fn zirReify(
21219 return Air.internedToRef(ty.toIntern());21201 return Air.internedToRef(ty.toIntern());
21220 },21202 },
21221 .Optional => {21203 .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));
21223 const child_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21205 const child_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21224 ip,21206 ip,
21225 try ip.getOrPutString(gpa, "child"),21207 try ip.getOrPutString(gpa, "child"),
...@@ -21231,7 +21213,7 @@ fn zirReify(...@@ -21231,7 +21213,7 @@ fn zirReify(
21231 return Air.internedToRef(ty.toIntern());21213 return Air.internedToRef(ty.toIntern());
21232 },21214 },
21233 .ErrorUnion => {21215 .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));
21235 const error_set_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21217 const error_set_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21236 ip,21218 ip,
21237 try ip.getOrPutString(gpa, "error_set"),21219 try ip.getOrPutString(gpa, "error_set"),
...@@ -21260,7 +21242,7 @@ fn zirReify(...@@ -21260,7 +21242,7 @@ fn zirReify(
21260 try names.ensureUnusedCapacity(sema.arena, len);21242 try names.ensureUnusedCapacity(sema.arena, len);
21261 for (0..len) |i| {21243 for (0..len) |i| {
21262 const elem_val = try payload_val.elemValue(mod, i);21244 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()));
21264 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(21246 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21265 ip,21247 ip,
21266 try ip.getOrPutString(gpa, "name"),21248 try ip.getOrPutString(gpa, "name"),
...@@ -21280,7 +21262,7 @@ fn zirReify(...@@ -21280,7 +21262,7 @@ fn zirReify(
21280 return Air.internedToRef(ty.toIntern());21262 return Air.internedToRef(ty.toIntern());
21281 },21263 },
21282 .Struct => {21264 .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));
21284 const layout_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21266 const layout_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21285 ip,21267 ip,
21286 try ip.getOrPutString(gpa, "layout"),21268 try ip.getOrPutString(gpa, "layout"),
...@@ -21316,7 +21298,7 @@ fn zirReify(...@@ -21316,7 +21298,7 @@ fn zirReify(
21316 return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());21298 return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());
21317 },21299 },
21318 .Enum => {21300 .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));
21320 const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21302 const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21321 ip,21303 ip,
21322 try ip.getOrPutString(gpa, "tag_type"),21304 try ip.getOrPutString(gpa, "tag_type"),
...@@ -21334,105 +21316,14 @@ fn zirReify(...@@ -21334,105 +21316,14 @@ fn zirReify(
21334 try ip.getOrPutString(gpa, "is_exhaustive"),21316 try ip.getOrPutString(gpa, "is_exhaustive"),
21335 ).?);21317 ).?);
2133621318
21337 // Decls
21338 if (decls_val.sliceLen(mod) > 0) {21319 if (decls_val.sliceLen(mod) > 0) {
21339 return sema.fail(block, src, "reified enums must have no decls", .{});21320 return sema.fail(block, src, "reified enums must have no decls", .{});
21340 }21321 }
2134121322
21342 const int_tag_ty = tag_type_val.toType();21323 return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_val, name_strategy);
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;
21433 },21324 },
21434 .Opaque => {21325 .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));
21436 const decls_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21327 const decls_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21437 ip,21328 ip,
21438 try ip.getOrPutString(gpa, "decls"),21329 try ip.getOrPutString(gpa, "decls"),
...@@ -21443,45 +21334,30 @@ fn zirReify(...@@ -21443,45 +21334,30 @@ fn zirReify(
21443 return sema.fail(block, src, "reified opaque must have no decls", .{});21334 return sema.fail(block, src, "reified opaque must have no decls", .{});
21444 }21335 }
2144521336
21446 // Because these three things each reference each other,21337 const wip_ty = switch (try ip.getOpaqueType(gpa, .{
21447 // `undefined` placeholders are used in two places before being set21338 .has_namespace = false,
21448 // after the opaque type gains an InternPool index.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
21450 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{21348 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21451 .ty = Type.noreturn,21349 .ty = Type.type,
21452 .val = Value.@"unreachable",21350 .val = Value.fromInterned(wip_ty.index),
21453 }, name_strategy, "opaque", inst);21351 }, name_strategy, "opaque", inst);
21454 const new_decl = mod.declPtr(new_decl_index);21352 mod.declPtr(new_decl_index).owns_tv = true;
21455 new_decl.owns_tv = true;21353 errdefer mod.abortAnonDecl(new_decl_index);
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);
2147821354
21479 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
21480 try mod.finalizeAnonDecl(new_decl_index);21355 try mod.finalizeAnonDecl(new_decl_index);
21481 return decl_val;21356
21357 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
21482 },21358 },
21483 .Union => {21359 .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));
21485 const layout_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21361 const layout_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21486 ip,21362 ip,
21487 try ip.getOrPutString(gpa, "layout"),21363 try ip.getOrPutString(gpa, "layout"),
...@@ -21499,216 +21375,15 @@ fn zirReify(...@@ -21499,216 +21375,15 @@ fn zirReify(
21499 try ip.getOrPutString(gpa, "decls"),21375 try ip.getOrPutString(gpa, "decls"),
21500 ).?);21376 ).?);
2150121377
21502 // Decls
21503 if (decls_val.sliceLen(mod) > 0) {21378 if (decls_val.sliceLen(mod) > 0) {
21504 return sema.fail(block, src, "reified unions must have no decls", .{});21379 return sema.fail(block, src, "reified unions must have no decls", .{});
21505 }21380 }
21506 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);21381 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) {21383 return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_val, name_strategy);
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;
21709 },21384 },
21710 .Fn => {21385 .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));
21712 const calling_convention_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21387 const calling_convention_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21713 ip,21388 ip,
21714 try ip.getOrPutString(gpa, "calling_convention"),21389 try ip.getOrPutString(gpa, "calling_convention"),
...@@ -21759,7 +21434,7 @@ fn zirReify(...@@ -21759,7 +21434,7 @@ fn zirReify(
21759 var noalias_bits: u32 = 0;21434 var noalias_bits: u32 = 0;
21760 for (param_types, 0..) |*param_type, i| {21435 for (param_types, 0..) |*param_type, i| {
21761 const elem_val = try params_val.elemValue(mod, i);21436 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()));
21763 const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(21438 const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21764 ip,21439 ip,
21765 try ip.getOrPutString(gpa, "is_generic"),21440 try ip.getOrPutString(gpa, "is_generic"),
...@@ -21804,126 +21479,492 @@ fn zirReify(...@@ -21804,126 +21479,492 @@ fn zirReify(
21804 }21479 }
21805}21480}
2180621481
21807fn reifyStruct(21482fn reifyEnum(
21808 sema: *Sema,21483 sema: *Sema,
21809 block: *Block,21484 block: *Block,
21810 inst: Zir.Inst.Index,21485 inst: Zir.Inst.Index,
21811 src: LazySrcLoc,21486 src: LazySrcLoc,
21812 layout: std.builtin.Type.ContainerLayout,21487 tag_ty: Type,
21813 backing_int_val: Value,21488 is_exhaustive: bool,
21814 fields_val: Value,21489 fields_val: Value,
21815 name_strategy: Zir.Inst.NameStrategy,21490 name_strategy: Zir.Inst.NameStrategy,
21816 is_tuple: bool,
21817) CompileError!Air.Inst.Ref {21491) CompileError!Air.Inst.Ref {
21818 const mod = sema.mod;21492 const mod = sema.mod;
21819 const gpa = sema.gpa;21493 const gpa = sema.gpa;
21820 const ip = &mod.intern_pool;21494 const ip = &mod.intern_pool;
2182121495
21822 if (is_tuple) switch (layout) {21496 // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`.
21823 .Extern => return sema.fail(block, src, "extern tuples are not supported", .{}),21497
21824 .Packed => return sema.fail(block, src, "packed tuples are not supported", .{}),21498 const fields_len: u32 = @intCast(fields_val.sliceLen(mod));
21825 .Auto => {},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),
21826 };21537 };
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`21600fn reifyUnion(
21831 // placeholders are used before being set after the struct type gains an21601 sema: *Sema,
21832 // InternPool index.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
21834 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{21684 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
21835 .ty = Type.noreturn,21685 .ty = Type.type,
21836 .val = Value.@"unreachable",21686 .val = Value.fromInterned(wip_ty.index),
21837 }, name_strategy, "struct", inst);21687 }, name_strategy, "union", inst);
21838 const new_decl = mod.declPtr(new_decl_index);21688 mod.declPtr(new_decl_index).owns_tv = true;
21839 new_decl.owns_tv = true;21689 errdefer mod.abortAnonDecl(new_decl_index);
21840 errdefer {21690
21841 new_decl.has_tv = false; // namespace and val were destroyed by later errdefers21691 const field_types = try sema.arena.alloc(InternPool.Index, fields_len);
21842 mod.abortAnonDecl(new_decl_index);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 }
21843 }21819 }
2184421820
21845 const ty = try ip.getStructType(gpa, .{21821 const loaded_union = ip.loadUnionType(wip_ty.index);
21846 .decl = new_decl_index,21822 loaded_union.setFieldTypes(ip, field_types);
21847 .namespace = .none,21823 if (any_aligns) {
21848 .zir_index = .none,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, .{
21849 .layout = layout,21909 .layout = layout,
21850 .known_non_opv = false,
21851 .fields_len = fields_len,21910 .fields_len = fields_len,
21911 .known_non_opv = false,
21852 .requires_comptime = .unknown,21912 .requires_comptime = .unknown,
21853 .is_tuple = is_tuple,21913 .is_tuple = is_tuple,
21854 // So that we don't have to scan ahead, we allocate space in the struct21914 .any_comptime_fields = any_comptime_fields,
21855 // type for alignments, comptime fields, and default inits. This might21915 .any_default_inits = any_default_inits,
21856 // result in wasted space, however, this is a permitted encoding of21916 .any_aligned_fields = any_aligned_fields,
21857 // struct types.
21858 .any_comptime_fields = true,
21859 .any_default_inits = true,
21860 .inits_resolved = true,21917 .inits_resolved = true,
21861 .any_aligned_fields = true,21918 .has_namespace = false,
21862 });21919 .key = .{ .reified = .{
21863 // TODO: figure out InternPool removals for incremental compilation21920 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
21864 //errdefer ip.remove(ty);21921 .type_hash = hasher.final(),
21865 const struct_type = ip.indexToKey(ty).struct_type;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;21929 if (is_tuple) switch (layout) {
21868 new_decl.val = Value.fromInterned(ty);21930 .Extern => return sema.fail(block, src, "extern tuples are not supported", .{}),
2186921931 .Packed => return sema.fail(block, src, "packed tuples are not supported", .{}),
21870 // Fields21932 .Auto => {},
21871 for (0..fields_len) |i| {21933 };
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 }
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);
21913 if (is_tuple) {21955 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(
21915 block,21957 block,
21916 src,21958 src,
21917 "tuple cannot have non-numeric field '{}'",21959 "tuple cannot have non-numeric field '{}'",
21918 .{field_name.fmt(ip)},21960 .{field_name.fmt(ip)},
21919 );21961 );
2192021962 if (field_name_index != field_idx) {
21921 if (field_index >= fields_len) {
21922 return sema.fail(21963 return sema.fail(
21923 block,21964 block,
21924 src,21965 src,
21925 "tuple field {} exceeds tuple field count",21966 "tuple field name '{}' does not match field index {}",
21926 .{field_index},21967 .{ field_name_index, field_idx },
21927 );21968 );
21928 }21969 }
21929 } else if (struct_type.addFieldName(ip, field_name)) |prev_index| {21970 } else if (struct_type.addFieldName(ip, field_name)) |prev_index| {
...@@ -21931,45 +21972,72 @@ fn reifyStruct(...@@ -21931,45 +21972,72 @@ fn reifyStruct(
21931 return sema.fail(block, src, "duplicate struct field name {}", .{field_name.fmt(ip)});21972 return sema.fail(block, src, "duplicate struct field name {}", .{field_name.fmt(ip)});
21932 }21973 }
2193321974
21934 const field_ty = type_val.toType();21975 if (any_aligned_fields) {
21935 const default_val = if (default_value_val.optionalValue(mod)) |opt_val|21976 if (!try sema.intFitsInType(field_alignment_val, Type.u32, null)) {
21936 (try sema.pointerDeref(block, src, opt_val, try mod.singleConstPtrType(field_ty)) orelse21977 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
21937 return sema.failWithNeededComptime(block, src, .{21978 }
21938 .needed_comptime_reason = "struct field default value must be comptime-known",21979
21939 })).toIntern()21980 const byte_align = try field_alignment_val.toUnsignedIntAdvanced(sema);
21940 else21981 if (byte_align == 0) {
21941 .none;21982 if (layout != .Packed) {
21942 if (is_comptime_val.toBool() and default_val == .none) {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) {
21943 return sema.fail(block, src, "comptime field without default initialization value", .{});22013 return sema.fail(block, src, "comptime field without default initialization value", .{});
21944 }22014 }
2194522015
21946 struct_type.field_types.get(ip)[i] = field_ty.toIntern();22016 struct_type.field_types.get(ip)[field_idx] = field_type_val.toIntern();
21947 struct_type.field_inits.get(ip)[i] = default_val;22017 if (field_default != .none) {
21948 if (is_comptime_val.toBool())22018 struct_type.field_inits.get(ip)[field_idx] = field_default;
21949 struct_type.setFieldComptime(ip, i);22019 }
2195022020
21951 if (field_ty.zigTypeTag(mod) == .Opaque) {22021 if (field_ty.zigTypeTag(mod) == .Opaque) {
21952 const msg = msg: {22022 return sema.failWithOwnedErrorMsg(block, msg: {
21953 const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});22023 const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
21954 errdefer msg.destroy(gpa);22024 errdefer msg.destroy(gpa);
2195522025
21956 try sema.addDeclaredHereNote(msg, field_ty);22026 try sema.addDeclaredHereNote(msg, field_ty);
21957 break :msg msg;22027 break :msg msg;
21958 };22028 });
21959 return sema.failWithOwnedErrorMsg(block, msg);
21960 }22029 }
21961 if (field_ty.zigTypeTag(mod) == .NoReturn) {22030 if (field_ty.zigTypeTag(mod) == .NoReturn) {
21962 const msg = msg: {22031 return sema.failWithOwnedErrorMsg(block, msg: {
21963 const msg = try sema.errMsg(block, src, "struct fields cannot be 'noreturn'", .{});22032 const msg = try sema.errMsg(block, src, "struct fields cannot be 'noreturn'", .{});
21964 errdefer msg.destroy(gpa);22033 errdefer msg.destroy(gpa);
2196522034
21966 try sema.addDeclaredHereNote(msg, field_ty);22035 try sema.addDeclaredHereNote(msg, field_ty);
21967 break :msg msg;22036 break :msg msg;
21968 };22037 });
21969 return sema.failWithOwnedErrorMsg(block, msg);
21970 }22038 }
21971 if (layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) {22039 if (layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) {
21972 const msg = msg: {22040 return sema.failWithOwnedErrorMsg(block, msg: {
21973 const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});22041 const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
21974 errdefer msg.destroy(gpa);22042 errdefer msg.destroy(gpa);
2197522043
...@@ -21978,10 +22046,9 @@ fn reifyStruct(...@@ -21978,10 +22046,9 @@ fn reifyStruct(
2197822046
21979 try sema.addDeclaredHereNote(msg, field_ty);22047 try sema.addDeclaredHereNote(msg, field_ty);
21980 break :msg msg;22048 break :msg msg;
21981 };22049 });
21982 return sema.failWithOwnedErrorMsg(block, msg);
21983 } else if (layout == .Packed and !try sema.validatePackedType(field_ty)) {22050 } else if (layout == .Packed and !try sema.validatePackedType(field_ty)) {
21984 const msg = msg: {22051 return sema.failWithOwnedErrorMsg(block, msg: {
21985 const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});22052 const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
21986 errdefer msg.destroy(gpa);22053 errdefer msg.destroy(gpa);
2198722054
...@@ -21990,32 +22057,27 @@ fn reifyStruct(...@@ -21990,32 +22057,27 @@ fn reifyStruct(
2199022057
21991 try sema.addDeclaredHereNote(msg, field_ty);22058 try sema.addDeclaredHereNote(msg, field_ty);
21992 break :msg msg;22059 break :msg msg;
21993 };22060 });
21994 return sema.failWithOwnedErrorMsg(block, msg);
21995 }22061 }
21996 }22062 }
2199722063
21998 if (layout == .Packed) {22064 if (layout == .Packed) {
21999 for (0..struct_type.field_types.len) |index| {22065 var fields_bit_sum: u64 = 0;
22000 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);22066 for (0..struct_type.field_types.len) |field_idx| {
22067 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_idx]);
22001 sema.resolveTypeLayout(field_ty) catch |err| switch (err) {22068 sema.resolveTypeLayout(field_ty) catch |err| switch (err) {
22002 error.AnalysisFail => {22069 error.AnalysisFail => {
22003 const msg = sema.err orelse return err;22070 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", .{});
22005 return err;22072 return err;
22006 },22073 },
22007 else => return err,22074 else => return err,
22008 };22075 };
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]);
22014 fields_bit_sum += field_ty.bitSize(mod);22076 fields_bit_sum += field_ty.bitSize(mod);
22015 }22077 }
2201622078
22017 if (backing_int_val.optionalValue(mod)) |backing_int_ty_val| {22079 if (opt_backing_int_val.optionalValue(mod)) |backing_int_val| {
22018 const backing_int_ty = backing_int_ty_val.toType();22080 const backing_int_ty = backing_int_val.toType();
22019 try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);22081 try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
22020 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();22082 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
22021 } else {22083 } else {
...@@ -22024,9 +22086,8 @@ fn reifyStruct(...@@ -22024,9 +22086,8 @@ fn reifyStruct(
22024 }22086 }
22025 }22087 }
2202622088
22027 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
22028 try mod.finalizeAnonDecl(new_decl_index);22089 try mod.finalizeAnonDecl(new_decl_index);
22029 return decl_val;22090 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
22030}22091}
2203122092
22032fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {22093fn 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...@@ -23241,7 +23302,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
23241 switch (ty.containerLayout(mod)) {23302 switch (ty.containerLayout(mod)) {
23242 .Packed => {23303 .Packed => {
23243 var bit_sum: u64 = 0;23304 var bit_sum: u64 = 0;
23244 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;23305 const struct_type = ip.loadStructType(ty.toIntern());
23245 for (0..struct_type.field_types.len) |i| {23306 for (0..struct_type.field_types.len) |i| {
23246 if (i == field_index) {23307 if (i == field_index) {
23247 return bit_sum;23308 return bit_sum;
...@@ -25919,7 +25980,7 @@ fn zirBuiltinExtern(...@@ -25919,7 +25980,7 @@ fn zirBuiltinExtern(
2591925980
25920 // TODO check duplicate extern25981 // 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);
25923 errdefer mod.destroyDecl(new_decl_index);25984 errdefer mod.destroyDecl(new_decl_index);
25924 const new_decl = mod.declPtr(new_decl_index);25985 const new_decl = mod.declPtr(new_decl_index);
25925 new_decl.name = options.name;25986 new_decl.name = options.name;
...@@ -26515,7 +26576,6 @@ fn addSafetyCheck(...@@ -26515,7 +26576,6 @@ fn addSafetyCheck(
26515 .sema = sema,26576 .sema = sema,
26516 .src_decl = parent_block.src_decl,26577 .src_decl = parent_block.src_decl,
26517 .namespace = parent_block.namespace,26578 .namespace = parent_block.namespace,
26518 .wip_capture_scope = parent_block.wip_capture_scope,
26519 .instructions = .{},26579 .instructions = .{},
26520 .inlining = parent_block.inlining,26580 .inlining = parent_block.inlining,
26521 .is_comptime = false,26581 .is_comptime = false,
...@@ -26624,7 +26684,6 @@ fn panicUnwrapError(...@@ -26624,7 +26684,6 @@ fn panicUnwrapError(
26624 .sema = sema,26684 .sema = sema,
26625 .src_decl = parent_block.src_decl,26685 .src_decl = parent_block.src_decl,
26626 .namespace = parent_block.namespace,26686 .namespace = parent_block.namespace,
26627 .wip_capture_scope = parent_block.wip_capture_scope,
26628 .instructions = .{},26687 .instructions = .{},
26629 .inlining = parent_block.inlining,26688 .inlining = parent_block.inlining,
26630 .is_comptime = false,26689 .is_comptime = false,
...@@ -26741,7 +26800,6 @@ fn safetyCheckFormatted(...@@ -26741,7 +26800,6 @@ fn safetyCheckFormatted(
26741 .sema = sema,26800 .sema = sema,
26742 .src_decl = parent_block.src_decl,26801 .src_decl = parent_block.src_decl,
26743 .namespace = parent_block.namespace,26802 .namespace = parent_block.namespace,
26744 .wip_capture_scope = parent_block.wip_capture_scope,
26745 .instructions = .{},26803 .instructions = .{},
26746 .inlining = parent_block.inlining,26804 .inlining = parent_block.inlining,
26747 .is_comptime = false,26805 .is_comptime = false,
...@@ -27268,8 +27326,7 @@ fn fieldCallBind(...@@ -27268,8 +27326,7 @@ fn fieldCallBind(
27268 .Union => {27326 .Union => {
27269 try sema.resolveTypeFields(concrete_ty);27327 try sema.resolveTypeFields(concrete_ty);
27270 const union_obj = mod.typeToUnion(concrete_ty).?;27328 const union_obj = mod.typeToUnion(concrete_ty).?;
27271 _ = union_obj.nameIndex(ip, field_name) orelse break :find_field;27329 _ = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse break :find_field;
27272
27273 const field_ptr = try unionFieldPtr(sema, block, src, object_ptr, field_name, field_name_src, concrete_ty, false);27330 const field_ptr = try unionFieldPtr(sema, block, src, object_ptr, field_name, field_name_src, concrete_ty, false);
27274 return .{ .direct = try sema.analyzeLoad(block, src, field_ptr, src) };27331 return .{ .direct = try sema.analyzeLoad(block, src, field_ptr, src) };
27275 },27332 },
...@@ -27643,7 +27700,8 @@ fn structFieldVal(...@@ -27643,7 +27700,8 @@ fn structFieldVal(
27643 try sema.resolveTypeFields(struct_ty);27700 try sema.resolveTypeFields(struct_ty);
2764427701
27645 switch (ip.indexToKey(struct_ty.toIntern())) {27702 switch (ip.indexToKey(struct_ty.toIntern())) {
27646 .struct_type => |struct_type| {27703 .struct_type => {
27704 const struct_type = ip.loadStructType(struct_ty.toIntern());
27647 if (struct_type.isTuple(ip))27705 if (struct_type.isTuple(ip))
27648 return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);27706 return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);
2764927707
...@@ -27849,7 +27907,7 @@ fn unionFieldPtr(...@@ -27849,7 +27907,7 @@ fn unionFieldPtr(
2784927907
27850 try sema.requireRuntimeBlock(block, src, null);27908 try sema.requireRuntimeBlock(block, src, null);
27851 if (!initializing and union_obj.getLayout(ip) == .Auto and block.wantSafety() and27909 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)
27853 {27911 {
27854 const wanted_tag_val = try mod.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);27912 const wanted_tag_val = try mod.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
27855 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());27913 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
...@@ -27927,7 +27985,7 @@ fn unionFieldVal(...@@ -27927,7 +27985,7 @@ fn unionFieldVal(
2792727985
27928 try sema.requireRuntimeBlock(block, src, null);27986 try sema.requireRuntimeBlock(block, src, null);
27929 if (union_obj.getLayout(ip) == .Auto and block.wantSafety() and27987 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)
27931 {27989 {
27932 const wanted_tag_val = try mod.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);27990 const wanted_tag_val = try mod.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
27933 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());27991 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
...@@ -31686,7 +31744,7 @@ fn coerceEnumToUnion(...@@ -31686,7 +31744,7 @@ fn coerceEnumToUnion(
31686 const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{});31744 const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{});
31687 errdefer msg.destroy(sema.gpa);31745 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];
31690 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{31748 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{
31691 field_name.fmt(ip),31749 field_name.fmt(ip),
31692 });31750 });
...@@ -31697,7 +31755,7 @@ fn coerceEnumToUnion(...@@ -31697,7 +31755,7 @@ fn coerceEnumToUnion(
31697 }31755 }
31698 const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse {31756 const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse {
31699 const msg = msg: {31757 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];
31701 const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{31759 const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{
31702 inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod),31760 inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod),
31703 field_ty.fmt(sema.mod), field_name.fmt(ip),31761 field_ty.fmt(sema.mod), field_name.fmt(ip),
...@@ -31769,8 +31827,8 @@ fn coerceEnumToUnion(...@@ -31769,8 +31827,8 @@ fn coerceEnumToUnion(
31769 );31827 );
31770 errdefer msg.destroy(sema.gpa);31828 errdefer msg.destroy(sema.gpa);
3177131829
31772 for (0..union_obj.field_names.len) |field_index| {31830 for (0..union_obj.field_types.len) |field_index| {
31773 const field_name = union_obj.field_names.get(ip)[field_index];31831 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
31774 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);31832 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
31775 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;31833 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
31776 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' has type '{}'", .{31834 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' has type '{}'", .{
...@@ -31803,8 +31861,8 @@ fn coerceAnonStructToUnion(...@@ -31803,8 +31861,8 @@ fn coerceAnonStructToUnion(
31803 .{ .name = anon_struct_type.names.get(ip)[0] }31861 .{ .name = anon_struct_type.names.get(ip)[0] }
31804 else31862 else
31805 .{ .count = anon_struct_type.names.len },31863 .{ .count = anon_struct_type.names.len },
31806 .struct_type => |struct_type| name: {31864 .struct_type => name: {
31807 const field_names = struct_type.field_names.get(ip);31865 const field_names = ip.loadStructType(inst_ty.toIntern()).field_names.get(ip);
31808 break :name if (field_names.len == 1)31866 break :name if (field_names.len == 1)
31809 .{ .name = field_names[0] }31867 .{ .name = field_names[0] }
31810 else31868 else
...@@ -32113,7 +32171,7 @@ fn coerceTupleToStruct(...@@ -32113,7 +32171,7 @@ fn coerceTupleToStruct(
32113 var runtime_src: ?LazySrcLoc = null;32171 var runtime_src: ?LazySrcLoc = null;
32114 const field_count = switch (ip.indexToKey(inst_ty.toIntern())) {32172 const field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
32115 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,32173 .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,
32117 else => unreachable,32175 else => unreachable,
32118 };32176 };
32119 for (0..field_count) |field_index_usize| {32177 for (0..field_count) |field_index_usize| {
...@@ -32125,7 +32183,7 @@ fn coerceTupleToStruct(...@@ -32125,7 +32183,7 @@ fn coerceTupleToStruct(
32125 anon_struct_type.names.get(ip)[field_i]32183 anon_struct_type.names.get(ip)[field_i]
32126 else32184 else
32127 try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),32185 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],
32129 else => unreachable,32187 else => unreachable,
32130 };32188 };
32131 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);32189 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
...@@ -32213,7 +32271,7 @@ fn coerceTupleToTuple(...@@ -32213,7 +32271,7 @@ fn coerceTupleToTuple(
32213 const ip = &mod.intern_pool;32271 const ip = &mod.intern_pool;
32214 const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) {32272 const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) {
32215 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,32273 .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,
32217 else => unreachable,32275 else => unreachable,
32218 };32276 };
32219 const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count);32277 const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count);
...@@ -32223,7 +32281,7 @@ fn coerceTupleToTuple(...@@ -32223,7 +32281,7 @@ fn coerceTupleToTuple(
32223 const inst_ty = sema.typeOf(inst);32281 const inst_ty = sema.typeOf(inst);
32224 const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) {32282 const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
32225 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,32283 .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,
32227 else => unreachable,32285 else => unreachable,
32228 };32286 };
32229 if (src_field_count > dest_field_count) return error.NotCoercible;32287 if (src_field_count > dest_field_count) return error.NotCoercible;
...@@ -32238,10 +32296,14 @@ fn coerceTupleToTuple(...@@ -32238,10 +32296,14 @@ fn coerceTupleToTuple(
32238 anon_struct_type.names.get(ip)[field_i]32296 anon_struct_type.names.get(ip)[field_i]
32239 else32297 else
32240 try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),32298 try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
32241 .struct_type => |struct_type| if (struct_type.field_names.len > 0)32299 .struct_type => s: {
32242 struct_type.field_names.get(ip)[field_i]32300 const struct_type = ip.loadStructType(inst_ty.toIntern());
32243 else32301 if (struct_type.field_names.len > 0) {
32244 try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),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 },
32245 else => unreachable,32307 else => unreachable,
32246 };32308 };
3224732309
...@@ -32250,12 +32312,12 @@ fn coerceTupleToTuple(...@@ -32250,12 +32312,12 @@ fn coerceTupleToTuple(
3225032312
32251 const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) {32313 const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) {
32252 .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[field_index_usize],32314 .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],
32254 else => unreachable,32316 else => unreachable,
32255 };32317 };
32256 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {32318 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
32257 .anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[field_index_usize],32319 .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),
32259 else => unreachable,32321 else => unreachable,
32260 };32322 };
3226132323
...@@ -32294,7 +32356,7 @@ fn coerceTupleToTuple(...@@ -32294,7 +32356,7 @@ fn coerceTupleToTuple(
3229432356
32295 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {32357 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
32296 .anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[i],32358 .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),
32298 else => unreachable,32360 else => unreachable,
32299 };32361 };
3230032362
...@@ -35534,7 +35596,7 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -35534,7 +35596,7 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
35534pub fn resolveStructAlignment(35596pub fn resolveStructAlignment(
35535 sema: *Sema,35597 sema: *Sema,
35536 ty: InternPool.Index,35598 ty: InternPool.Index,
35537 struct_type: InternPool.Key.StructType,35599 struct_type: InternPool.LoadedStructType,
35538) CompileError!Alignment {35600) CompileError!Alignment {
35539 const mod = sema.mod;35601 const mod = sema.mod;
35540 const ip = &mod.intern_pool;35602 const ip = &mod.intern_pool;
...@@ -35674,7 +35736,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -35674,7 +35736,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
35674 }35736 }
35675 }35737 }
3567635738
35677 const RuntimeOrder = InternPool.Key.StructType.RuntimeOrder;35739 const RuntimeOrder = InternPool.LoadedStructType.RuntimeOrder;
3567835740
35679 const AlignSortContext = struct {35741 const AlignSortContext = struct {
35680 aligns: []const Alignment,35742 aligns: []const Alignment,
...@@ -35726,7 +35788,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -35726,7 +35788,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
35726 _ = try sema.typeRequiresComptime(ty);35788 _ = try sema.typeRequiresComptime(ty);
35727}35789}
3572835790
35729fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) CompileError!void {35791fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) CompileError!void {
35730 const gpa = mod.gpa;35792 const gpa = mod.gpa;
35731 const ip = &mod.intern_pool;35793 const ip = &mod.intern_pool;
3573235794
...@@ -35766,7 +35828,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp...@@ -35766,7 +35828,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
35766 .sema = &sema,35828 .sema = &sema,
35767 .src_decl = decl_index,35829 .src_decl = decl_index,
35768 .namespace = struct_type.namespace.unwrap() orelse decl.src_namespace,35830 .namespace = struct_type.namespace.unwrap() orelse decl.src_namespace,
35769 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
35770 .instructions = .{},35831 .instructions = .{},
35771 .inlining = null,35832 .inlining = null,
35772 .is_comptime = true,35833 .is_comptime = true,
...@@ -35789,9 +35850,16 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp...@@ -35789,9 +35850,16 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
3578935850
35790 if (small.has_backing_int) {35851 if (small.has_backing_int) {
35791 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;35852 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;
35792 extra_index += @intFromBool(small.has_fields_len);35858 extra_index += @intFromBool(small.has_fields_len);
35793 extra_index += @intFromBool(small.has_decls_len);35859 extra_index += @intFromBool(small.has_decls_len);
3579435860
35861 extra_index += captures_len;
35862
35795 const backing_int_body_len = zir.extra[extra_index];35863 const backing_int_body_len = zir.extra[extra_index];
35796 extra_index += 1;35864 extra_index += 1;
3579735865
...@@ -35879,7 +35947,7 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void...@@ -35879,7 +35947,7 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void
35879pub fn resolveUnionAlignment(35947pub fn resolveUnionAlignment(
35880 sema: *Sema,35948 sema: *Sema,
35881 ty: Type,35949 ty: Type,
35882 union_type: InternPool.Key.UnionType,35950 union_type: InternPool.LoadedUnionType,
35883) CompileError!Alignment {35951) CompileError!Alignment {
35884 const mod = sema.mod;35952 const mod = sema.mod;
35885 const ip = &mod.intern_pool;35953 const ip = &mod.intern_pool;
...@@ -35899,13 +35967,12 @@ pub fn resolveUnionAlignment(...@@ -35899,13 +35967,12 @@ pub fn resolveUnionAlignment(
3589935967
35900 try sema.resolveTypeFieldsUnion(ty, union_type);35968 try sema.resolveTypeFieldsUnion(ty, union_type);
3590135969
35902 const union_obj = ip.loadUnionType(union_type);
35903 var max_align: Alignment = .@"1";35970 var max_align: Alignment = .@"1";
35904 for (0..union_obj.field_names.len) |field_index| {35971 for (0..union_type.field_types.len) |field_index| {
35905 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);35972 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
35906 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;35973 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));
35909 const field_align = if (explicit_align != .none)35976 const field_align = if (explicit_align != .none)
35910 explicit_align35977 explicit_align
35911 else35978 else
...@@ -35923,16 +35990,17 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -35923,16 +35990,17 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
35923 const mod = sema.mod;35990 const mod = sema.mod;
35924 const ip = &mod.intern_pool;35991 const ip = &mod.intern_pool;
3592535992
35926 const union_type = ip.indexToKey(ty.ip_index).union_type;35993 try sema.resolveTypeFieldsUnion(ty, ip.loadUnionType(ty.ip_index));
35927 try sema.resolveTypeFieldsUnion(ty, union_type);
3592835994
35929 const union_obj = ip.loadUnionType(union_type);35995 // Load again, since the tag type might have changed due to resolution.
35930 switch (union_obj.flagsPtr(ip).status) {35996 const union_type = ip.loadUnionType(ty.ip_index);
35997
35998 switch (union_type.flagsPtr(ip).status) {
35931 .none, .have_field_types => {},35999 .none, .have_field_types => {},
35932 .field_types_wip, .layout_wip => {36000 .field_types_wip, .layout_wip => {
35933 const msg = try Module.ErrorMsg.create(36001 const msg = try Module.ErrorMsg.create(
35934 sema.gpa,36002 sema.gpa,
35935 mod.declPtr(union_obj.decl).srcLoc(mod),36003 mod.declPtr(union_type.decl).srcLoc(mod),
35936 "union '{}' depends on itself",36004 "union '{}' depends on itself",
35937 .{ty.fmt(mod)},36005 .{ty.fmt(mod)},
35938 );36006 );
...@@ -35941,17 +36009,17 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -35941,17 +36009,17 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
35941 .have_layout, .fully_resolved_wip, .fully_resolved => return,36009 .have_layout, .fully_resolved_wip, .fully_resolved => return,
35942 }36010 }
3594336011
35944 const prev_status = union_obj.flagsPtr(ip).status;36012 const prev_status = union_type.flagsPtr(ip).status;
35945 errdefer if (union_obj.flagsPtr(ip).status == .layout_wip) {36013 errdefer if (union_type.flagsPtr(ip).status == .layout_wip) {
35946 union_obj.flagsPtr(ip).status = prev_status;36014 union_type.flagsPtr(ip).status = prev_status;
35947 };36015 };
3594836016
35949 union_obj.flagsPtr(ip).status = .layout_wip;36017 union_type.flagsPtr(ip).status = .layout_wip;
3595036018
35951 var max_size: u64 = 0;36019 var max_size: u64 = 0;
35952 var max_align: Alignment = .@"1";36020 var max_align: Alignment = .@"1";
35953 for (0..union_obj.field_names.len) |field_index| {36021 for (0..union_type.field_types.len) |field_index| {
35954 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);36022 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
35955 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;36023 if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
3595636024
35957 max_size = @max(max_size, sema.typeAbiSize(field_ty) catch |err| switch (err) {36025 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 {...@@ -35963,7 +36031,7 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
35963 else => return err,36031 else => return err,
35964 });36032 });
3596536033
35966 const explicit_align = union_obj.fieldAlign(ip, @intCast(field_index));36034 const explicit_align = union_type.fieldAlign(ip, @intCast(field_index));
35967 const field_align = if (explicit_align != .none)36035 const field_align = if (explicit_align != .none)
35968 explicit_align36036 explicit_align
35969 else36037 else
...@@ -35972,10 +36040,10 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -35972,10 +36040,10 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
35972 max_align = max_align.max(field_align);36040 max_align = max_align.max(field_align);
35973 }36041 }
3597436042
35975 const flags = union_obj.flagsPtr(ip);36043 const flags = union_type.flagsPtr(ip);
35976 const has_runtime_tag = flags.runtime_tag.hasTag() and try sema.typeHasRuntimeBits(Type.fromInterned(union_obj.enum_tag_ty));36044 const has_runtime_tag = flags.runtime_tag.hasTag() and try sema.typeHasRuntimeBits(Type.fromInterned(union_type.enum_tag_ty));
35977 const size, const alignment, const padding = if (has_runtime_tag) layout: {36045 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);
35979 const tag_align = try sema.typeAbiAlignment(enum_tag_type);36047 const tag_align = try sema.typeAbiAlignment(enum_tag_type);
35980 const tag_size = try sema.typeAbiSize(enum_tag_type);36048 const tag_size = try sema.typeAbiSize(enum_tag_type);
3598136049
...@@ -36009,22 +36077,22 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -36009,22 +36077,22 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
36009 flags.alignment = alignment;36077 flags.alignment = alignment;
36010 flags.status = .have_layout;36078 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))) {
36013 const msg = try Module.ErrorMsg.create(36081 const msg = try Module.ErrorMsg.create(
36014 sema.gpa,36082 sema.gpa,
36015 mod.declPtr(union_obj.decl).srcLoc(mod),36083 mod.declPtr(union_type.decl).srcLoc(mod),
36016 "union layout depends on it having runtime bits",36084 "union layout depends on it having runtime bits",
36017 .{},36085 .{},
36018 );36086 );
36019 return sema.failWithOwnedErrorMsg(null, msg);36087 return sema.failWithOwnedErrorMsg(null, msg);
36020 }36088 }
3602136089
36022 if (union_obj.flagsPtr(ip).assumed_pointer_aligned and36090 if (union_type.flagsPtr(ip).assumed_pointer_aligned and
36023 alignment.compareStrict(.neq, Alignment.fromByteUnits(@divExact(mod.getTarget().ptrBitWidth(), 8))))36091 alignment.compareStrict(.neq, Alignment.fromByteUnits(@divExact(mod.getTarget().ptrBitWidth(), 8))))
36024 {36092 {
36025 const msg = try Module.ErrorMsg.create(36093 const msg = try Module.ErrorMsg.create(
36026 sema.gpa,36094 sema.gpa,
36027 mod.declPtr(union_obj.decl).srcLoc(mod),36095 mod.declPtr(union_type.decl).srcLoc(mod),
36028 "union layout depends on being pointer aligned",36096 "union layout depends on being pointer aligned",
36029 .{},36097 .{},
36030 );36098 );
...@@ -36212,12 +36280,11 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {...@@ -36212,12 +36280,11 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {
3621236280
36213 else => switch (ip.items.items(.tag)[@intFromEnum(ty_ip)]) {36281 else => switch (ip.items.items(.tag)[@intFromEnum(ty_ip)]) {
36214 .type_struct,36282 .type_struct,
36215 .type_struct_ns,
36216 .type_struct_packed,36283 .type_struct_packed,
36217 .type_struct_packed_inits,36284 .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)),
36221 .simple_type => try sema.resolveSimpleType(ip.indexToKey(ty_ip).simple_type),36288 .simple_type => try sema.resolveSimpleType(ip.indexToKey(ty_ip).simple_type),
36222 else => {},36289 else => {},
36223 },36290 },
...@@ -36249,7 +36316,7 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr...@@ -36249,7 +36316,7 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr
36249pub fn resolveTypeFieldsStruct(36316pub fn resolveTypeFieldsStruct(
36250 sema: *Sema,36317 sema: *Sema,
36251 ty: InternPool.Index,36318 ty: InternPool.Index,
36252 struct_type: InternPool.Key.StructType,36319 struct_type: InternPool.LoadedStructType,
36253) CompileError!void {36320) CompileError!void {
36254 const mod = sema.mod;36321 const mod = sema.mod;
36255 const ip = &mod.intern_pool;36322 const ip = &mod.intern_pool;
...@@ -36309,7 +36376,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {...@@ -36309,7 +36376,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {
36309 struct_type.setHaveFieldInits(ip);36376 struct_type.setHaveFieldInits(ip);
36310}36377}
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 {
36313 const mod = sema.mod;36380 const mod = sema.mod;
36314 const ip = &mod.intern_pool;36381 const ip = &mod.intern_pool;
36315 const owner_decl = mod.declPtr(union_type.decl);36382 const owner_decl = mod.declPtr(union_type.decl);
...@@ -36500,6 +36567,12 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {...@@ -36500,6 +36567,12 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
36500 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);36567 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
36501 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;36568 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
36503 const fields_len = if (small.has_fields_len) blk: {36576 const fields_len = if (small.has_fields_len) blk: {
36504 const fields_len = zir.extra[extra_index];36577 const fields_len = zir.extra[extra_index];
36505 extra_index += 1;36578 extra_index += 1;
...@@ -36512,6 +36585,8 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {...@@ -36512,6 +36585,8 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
36512 break :decls_len decls_len;36585 break :decls_len decls_len;
36513 } else 0;36586 } else 0;
3651436587
36588 extra_index += captures_len;
36589
36515 // The backing integer cannot be handled until `resolveStructLayout()`.36590 // The backing integer cannot be handled until `resolveStructLayout()`.
36516 if (small.has_backing_int) {36591 if (small.has_backing_int) {
36517 const backing_int_body_len = zir.extra[extra_index];36592 const backing_int_body_len = zir.extra[extra_index];
...@@ -36532,7 +36607,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {...@@ -36532,7 +36607,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
36532fn semaStructFields(36607fn semaStructFields(
36533 mod: *Module,36608 mod: *Module,
36534 arena: Allocator,36609 arena: Allocator,
36535 struct_type: InternPool.Key.StructType,36610 struct_type: InternPool.LoadedStructType,
36536) CompileError!void {36611) CompileError!void {
36537 const gpa = mod.gpa;36612 const gpa = mod.gpa;
36538 const ip = &mod.intern_pool;36613 const ip = &mod.intern_pool;
...@@ -36584,7 +36659,6 @@ fn semaStructFields(...@@ -36584,7 +36659,6 @@ fn semaStructFields(
36584 .sema = &sema,36659 .sema = &sema,
36585 .src_decl = decl_index,36660 .src_decl = decl_index,
36586 .namespace = namespace_index,36661 .namespace = namespace_index,
36587 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
36588 .instructions = .{},36662 .instructions = .{},
36589 .inlining = null,36663 .inlining = null,
36590 .is_comptime = true,36664 .is_comptime = true,
...@@ -36800,7 +36874,7 @@ fn semaStructFields(...@@ -36800,7 +36874,7 @@ fn semaStructFields(
36800fn semaStructFieldInits(36874fn semaStructFieldInits(
36801 mod: *Module,36875 mod: *Module,
36802 arena: Allocator,36876 arena: Allocator,
36803 struct_type: InternPool.Key.StructType,36877 struct_type: InternPool.LoadedStructType,
36804) CompileError!void {36878) CompileError!void {
36805 const gpa = mod.gpa;36879 const gpa = mod.gpa;
36806 const ip = &mod.intern_pool;36880 const ip = &mod.intern_pool;
...@@ -36842,7 +36916,6 @@ fn semaStructFieldInits(...@@ -36842,7 +36916,6 @@ fn semaStructFieldInits(
36842 .sema = &sema,36916 .sema = &sema,
36843 .src_decl = decl_index,36917 .src_decl = decl_index,
36844 .namespace = namespace_index,36918 .namespace = namespace_index,
36845 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
36846 .instructions = .{},36919 .instructions = .{},
36847 .inlining = null,36920 .inlining = null,
36848 .is_comptime = true,36921 .is_comptime = true,
...@@ -36952,15 +37025,15 @@ fn semaStructFieldInits(...@@ -36952,15 +37025,15 @@ fn semaStructFieldInits(
36952 }37025 }
36953}37026}
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 {
36956 const tracy = trace(@src());37029 const tracy = trace(@src());
36957 defer tracy.end();37030 defer tracy.end();
3695837031
36959 const gpa = mod.gpa;37032 const gpa = mod.gpa;
36960 const ip = &mod.intern_pool;37033 const ip = &mod.intern_pool;
36961 const decl_index = union_type.decl;37034 const decl_index = union_type.decl;
36962 const zir = mod.namespacePtr(union_type.namespace).file_scope.zir;37035 const zir = mod.namespacePtr(union_type.namespace.unwrap().?).file_scope.zir;
36963 const zir_index = union_type.zir_index.unwrap().?.resolve(ip);37036 const zir_index = union_type.zir_index.resolve(ip);
36964 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;37037 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
36965 assert(extended.opcode == .union_decl);37038 assert(extended.opcode == .union_decl);
36966 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);37039 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
...@@ -36974,6 +37047,12 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un...@@ -36974,6 +37047,12 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
36974 break :blk ty_ref;37047 break :blk ty_ref;
36975 } else .none;37048 } 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
36977 const body_len = if (small.has_body_len) blk: {37056 const body_len = if (small.has_body_len) blk: {
36978 const body_len = zir.extra[extra_index];37057 const body_len = zir.extra[extra_index];
36979 extra_index += 1;37058 extra_index += 1;
...@@ -36992,8 +37071,8 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un...@@ -36992,8 +37071,8 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
36992 break :decls_len decls_len;37071 break :decls_len decls_len;
36993 } else 0;37072 } else 0;
3699437073
36995 // Skip over decls.37074 // Skip over captures and decls.
36996 extra_index += decls_len;37075 extra_index += captures_len + decls_len;
3699737076
36998 const body = zir.bodySlice(extra_index, body_len);37077 const body = zir.bodySlice(extra_index, body_len);
36999 extra_index += body.len;37078 extra_index += body.len;
...@@ -37027,8 +37106,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un...@@ -37027,8 +37106,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
37027 .parent = null,37106 .parent = null,
37028 .sema = &sema,37107 .sema = &sema,
37029 .src_decl = decl_index,37108 .src_decl = decl_index,
37030 .namespace = union_type.namespace,37109 .namespace = union_type.namespace.unwrap().?,
37031 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
37032 .instructions = .{},37110 .instructions = .{},
37033 .inlining = null,37111 .inlining = null,
37034 .is_comptime = true,37112 .is_comptime = true,
...@@ -37079,7 +37157,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un...@@ -37079,7 +37157,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
37079 // The provided type is the enum tag type.37157 // The provided type is the enum tag type.
37080 union_type.tagTypePtr(ip).* = provided_ty.toIntern();37158 union_type.tagTypePtr(ip).* = provided_ty.toIntern();
37081 const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) {37159 const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) {
37082 .enum_type => |x| x,37160 .enum_type => ip.loadEnumType(provided_ty.toIntern()),
37083 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{provided_ty.fmt(mod)}),37161 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{provided_ty.fmt(mod)}),
37084 };37162 };
37085 // The fields of the union must match the enum exactly.37163 // 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...@@ -37216,7 +37294,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
37216 }37294 }
3721737295
37218 if (explicit_tags_seen.len > 0) {37296 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).*);
37220 const enum_index = tag_info.nameIndex(ip, field_name) orelse {37298 const enum_index = tag_info.nameIndex(ip, field_name) orelse {
37221 const ty_src = mod.fieldSrcLoc(union_type.decl, .{37299 const ty_src = mod.fieldSrcLoc(union_type.decl, .{
37222 .index = field_i,37300 .index = field_i,
...@@ -37327,7 +37405,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un...@@ -37327,7 +37405,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
37327 union_type.setFieldAligns(ip, field_aligns.items);37405 union_type.setFieldAligns(ip, field_aligns.items);
3732837406
37329 if (explicit_tags_seen.len > 0) {37407 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).*);
37331 if (tag_info.names.len > fields_len) {37409 if (tag_info.names.len > fields_len) {
37332 const msg = msg: {37410 const msg = msg: {
37333 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});37411 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...@@ -37348,7 +37426,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
37348 const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), mod.declPtr(union_type.decl));37426 const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), mod.declPtr(union_type.decl));
37349 union_type.tagTypePtr(ip).* = enum_ty;37427 union_type.tagTypePtr(ip).* = enum_ty;
37350 } else {37428 } 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));
37352 union_type.tagTypePtr(ip).* = enum_ty;37430 union_type.tagTypePtr(ip).* = enum_ty;
37353 }37431 }
37354}37432}
...@@ -37365,16 +37443,16 @@ fn generateUnionTagTypeNumbered(...@@ -37365,16 +37443,16 @@ fn generateUnionTagTypeNumbered(
37365 block: *Block,37443 block: *Block,
37366 enum_field_names: []const InternPool.NullTerminatedString,37444 enum_field_names: []const InternPool.NullTerminatedString,
37367 enum_field_vals: []const InternPool.Index,37445 enum_field_vals: []const InternPool.Index,
37368 decl: *Module.Decl,37446 union_owner_decl: *Module.Decl,
37369) !InternPool.Index {37447) !InternPool.Index {
37370 const mod = sema.mod;37448 const mod = sema.mod;
37371 const gpa = sema.gpa;37449 const gpa = sema.gpa;
37372 const ip = &mod.intern_pool;37450 const ip = &mod.intern_pool;
3737337451
37374 const src_decl = mod.declPtr(block.src_decl);37452 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);
37376 errdefer mod.destroyDecl(new_decl_index);37454 errdefer mod.destroyDecl(new_decl_index);
37377 const fqn = try decl.fullyQualifiedName(mod);37455 const fqn = try union_owner_decl.fullyQualifiedName(mod);
37378 const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});37456 const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
37379 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{37457 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
37380 .ty = Type.noreturn,37458 .ty = Type.noreturn,
...@@ -37386,9 +37464,9 @@ fn generateUnionTagTypeNumbered(...@@ -37386,9 +37464,9 @@ fn generateUnionTagTypeNumbered(
37386 new_decl.owns_tv = true;37464 new_decl.owns_tv = true;
37387 new_decl.name_fully_qualified = true;37465 new_decl.name_fully_qualified = true;
3738837466
37389 const enum_ty = try ip.getEnum(gpa, .{37467 const enum_ty = try ip.getGeneratedTagEnumType(gpa, .{
37390 .decl = new_decl_index,37468 .decl = new_decl_index,
37391 .namespace = .none,37469 .owner_union_ty = union_owner_decl.val.toIntern(),
37392 .tag_ty = if (enum_field_vals.len == 0)37470 .tag_ty = if (enum_field_vals.len == 0)
37393 (try mod.intType(.unsigned, 0)).toIntern()37471 (try mod.intType(.unsigned, 0)).toIntern()
37394 else37472 else
...@@ -37396,7 +37474,6 @@ fn generateUnionTagTypeNumbered(...@@ -37396,7 +37474,6 @@ fn generateUnionTagTypeNumbered(
37396 .names = enum_field_names,37474 .names = enum_field_names,
37397 .values = enum_field_vals,37475 .values = enum_field_vals,
37398 .tag_mode = .explicit,37476 .tag_mode = .explicit,
37399 .zir_index = .none,
37400 });37477 });
3740137478
37402 new_decl.ty = Type.type;37479 new_decl.ty = Type.type;
...@@ -37410,22 +37487,16 @@ fn generateUnionTagTypeSimple(...@@ -37410,22 +37487,16 @@ fn generateUnionTagTypeSimple(
37410 sema: *Sema,37487 sema: *Sema,
37411 block: *Block,37488 block: *Block,
37412 enum_field_names: []const InternPool.NullTerminatedString,37489 enum_field_names: []const InternPool.NullTerminatedString,
37413 maybe_decl_index: InternPool.OptionalDeclIndex,37490 union_owner_decl: *Module.Decl,
37414) !InternPool.Index {37491) !InternPool.Index {
37415 const mod = sema.mod;37492 const mod = sema.mod;
37416 const ip = &mod.intern_pool;37493 const ip = &mod.intern_pool;
37417 const gpa = sema.gpa;37494 const gpa = sema.gpa;
3741837495
37419 const new_decl_index = new_decl_index: {37496 const new_decl_index = new_decl_index: {
37420 const decl_index = maybe_decl_index.unwrap() orelse {37497 const fqn = try union_owner_decl.fullyQualifiedName(mod);
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);
37427 const src_decl = mod.declPtr(block.src_decl);37498 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);
37429 errdefer mod.destroyDecl(new_decl_index);37500 errdefer mod.destroyDecl(new_decl_index);
37430 const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});37501 const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
37431 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{37502 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
...@@ -37437,9 +37508,9 @@ fn generateUnionTagTypeSimple(...@@ -37437,9 +37508,9 @@ fn generateUnionTagTypeSimple(
37437 };37508 };
37438 errdefer mod.abortAnonDecl(new_decl_index);37509 errdefer mod.abortAnonDecl(new_decl_index);
3743937510
37440 const enum_ty = try ip.getEnum(gpa, .{37511 const enum_ty = try ip.getGeneratedTagEnumType(gpa, .{
37441 .decl = new_decl_index,37512 .decl = new_decl_index,
37442 .namespace = .none,37513 .owner_union_ty = union_owner_decl.val.toIntern(),
37443 .tag_ty = if (enum_field_names.len == 0)37514 .tag_ty = if (enum_field_names.len == 0)
37444 (try mod.intType(.unsigned, 0)).toIntern()37515 (try mod.intType(.unsigned, 0)).toIntern()
37445 else37516 else
...@@ -37447,7 +37518,6 @@ fn generateUnionTagTypeSimple(...@@ -37447,7 +37518,6 @@ fn generateUnionTagTypeSimple(
37447 .names = enum_field_names,37518 .names = enum_field_names,
37448 .values = &.{},37519 .values = &.{},
37449 .tag_mode = .auto,37520 .tag_mode = .auto,
37450 .zir_index = .none,
37451 });37521 });
3745237522
37453 const new_decl = mod.declPtr(new_decl_index);37523 const new_decl = mod.declPtr(new_decl_index);
...@@ -37460,7 +37530,6 @@ fn generateUnionTagTypeSimple(...@@ -37460,7 +37530,6 @@ fn generateUnionTagTypeSimple(
37460}37530}
3746137531
37462fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {37532fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
37463 const mod = sema.mod;
37464 const gpa = sema.gpa;37533 const gpa = sema.gpa;
37465 const src = LazySrcLoc.nodeOffset(0);37534 const src = LazySrcLoc.nodeOffset(0);
3746637535
...@@ -37469,7 +37538,6 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {...@@ -37469,7 +37538,6 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
37469 .sema = sema,37538 .sema = sema,
37470 .src_decl = sema.owner_decl_index,37539 .src_decl = sema.owner_decl_index,
37471 .namespace = sema.owner_decl.src_namespace,37540 .namespace = sema.owner_decl.src_namespace,
37472 .wip_capture_scope = try mod.createCaptureScope(sema.owner_decl.src_scope),
37473 .instructions = .{},37541 .instructions = .{},
37474 .inlining = null,37542 .inlining = null,
37475 .is_comptime = true,37543 .is_comptime = true,
...@@ -37510,7 +37578,6 @@ fn getBuiltinDecl(sema: *Sema, block: *Block, name: []const u8) CompileError!Int...@@ -37510,7 +37578,6 @@ fn getBuiltinDecl(sema: *Sema, block: *Block, name: []const u8) CompileError!Int
37510}37578}
3751137579
37512fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {37580fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
37513 const mod = sema.mod;
37514 const ty_inst = try sema.getBuiltin(name);37581 const ty_inst = try sema.getBuiltin(name);
3751537582
37516 var block: Block = .{37583 var block: Block = .{
...@@ -37518,7 +37585,6 @@ fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {...@@ -37518,7 +37585,6 @@ fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
37518 .sema = sema,37585 .sema = sema,
37519 .src_decl = sema.owner_decl_index,37586 .src_decl = sema.owner_decl_index,
37520 .namespace = sema.owner_decl.src_namespace,37587 .namespace = sema.owner_decl.src_namespace,
37521 .wip_capture_scope = try mod.createCaptureScope(sema.owner_decl.src_scope),
37522 .instructions = .{},37588 .instructions = .{},
37523 .inlining = null,37589 .inlining = null,
37524 .is_comptime = true,37590 .is_comptime = true,
...@@ -37636,6 +37702,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -37636,6 +37702,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
37636 => unreachable,37702 => unreachable,
3763737703
37638 _ => switch (ip.items.items(.tag)[@intFromEnum(ty.toIntern())]) {37704 _ => switch (ip.items.items(.tag)[@intFromEnum(ty.toIntern())]) {
37705 .removed => unreachable,
37706
37639 .type_int_signed, // i0 handled above37707 .type_int_signed, // i0 handled above
37640 .type_int_unsigned, // u0 handled above37708 .type_int_unsigned, // u0 handled above
37641 .type_pointer,37709 .type_pointer,
...@@ -37713,7 +37781,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -37713,7 +37781,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
37713 .type_enum_explicit,37781 .type_enum_explicit,
37714 .type_enum_nonexhaustive,37782 .type_enum_nonexhaustive,
37715 .type_struct,37783 .type_struct,
37716 .type_struct_ns,
37717 .type_struct_anon,37784 .type_struct_anon,
37718 .type_struct_packed,37785 .type_struct_packed,
37719 .type_struct_packed_inits,37786 .type_struct_packed_inits,
...@@ -37736,8 +37803,9 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -37736,8 +37803,9 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
37736 return null;37803 return null;
37737 },37804 },
3773837805
37739 .struct_type => |struct_type| {37806 .struct_type => {
37740 try sema.resolveTypeFields(ty);37807 const struct_type = ip.loadStructType(ty.toIntern());
37808 try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type);
3774137809
37742 if (struct_type.field_types.len == 0) {37810 if (struct_type.field_types.len == 0) {
37743 // In this case the struct has no fields at all and37811 // In this case the struct has no fields at all and
...@@ -37795,10 +37863,10 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -37795,10 +37863,10 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
37795 } })));37863 } })));
37796 },37864 },
3779737865
37798 .union_type => |union_type| {37866 .union_type => {
37799 try sema.resolveTypeFields(ty);37867 const union_obj = ip.loadUnionType(ty.toIntern());
37800 const union_obj = ip.loadUnionType(union_type);37868 try sema.resolveTypeFieldsUnion(ty, union_obj);
37801 const tag_val = (try sema.typeHasOnePossibleValue(Type.fromInterned(union_obj.enum_tag_ty))) orelse37869 const tag_val = (try sema.typeHasOnePossibleValue(Type.fromInterned(union_obj.tagTypePtr(ip).*))) orelse
37802 return null;37870 return null;
37803 if (union_obj.field_types.len == 0) {37871 if (union_obj.field_types.len == 0) {
37804 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });37872 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
...@@ -37825,39 +37893,42 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -37825,39 +37893,42 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
37825 return Value.fromInterned(only);37893 return Value.fromInterned(only);
37826 },37894 },
3782737895
37828 .enum_type => |enum_type| switch (enum_type.tag_mode) {37896 .enum_type => {
37829 .nonexhaustive => {37897 const enum_type = ip.loadEnumType(ty.toIntern());
37830 if (enum_type.tag_ty == .comptime_int_type) return null;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| {37902 if (try sema.typeHasOnePossibleValue(Type.fromInterned(enum_type.tag_ty))) |int_opv| {
37833 const only = try mod.intern(.{ .enum_tag = .{37903 const only = try mod.intern(.{ .enum_tag = .{
37834 .ty = ty.toIntern(),37904 .ty = ty.toIntern(),
37835 .int = int_opv.toIntern(),37905 .int = int_opv.toIntern(),
37836 } });37906 } });
37837 return Value.fromInterned(only);37907 return Value.fromInterned(only);
37838 }37908 }
3783937909
37840 return null;37910 return null;
37841 },37911 },
37842 .auto, .explicit => {37912 .auto, .explicit => {
37843 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;37913 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;
3784437914
37845 return Value.fromInterned(switch (enum_type.names.len) {37915 return Value.fromInterned(switch (enum_type.names.len) {
37846 0 => try mod.intern(.{ .empty_enum_value = ty.toIntern() }),37916 0 => try mod.intern(.{ .empty_enum_value = ty.toIntern() }),
37847 1 => try mod.intern(.{ .enum_tag = .{37917 1 => try mod.intern(.{ .enum_tag = .{
37848 .ty = ty.toIntern(),37918 .ty = ty.toIntern(),
37849 .int = if (enum_type.values.len == 0)37919 .int = if (enum_type.values.len == 0)
37850 (try mod.intValue(Type.fromInterned(enum_type.tag_ty), 0)).toIntern()37920 (try mod.intValue(Type.fromInterned(enum_type.tag_ty), 0)).toIntern()
37851 else37921 else
37852 try mod.intern_pool.getCoercedInts(37922 try mod.intern_pool.getCoercedInts(
37853 mod.gpa,37923 mod.gpa,
37854 mod.intern_pool.indexToKey(enum_type.values.get(ip)[0]).int,37924 mod.intern_pool.indexToKey(enum_type.values.get(ip)[0]).int,
37855 enum_type.tag_ty,37925 enum_type.tag_ty,
37856 ),37926 ),
37857 } }),37927 } }),
37858 else => return null,37928 else => return null,
37859 });37929 });
37860 },37930 },
37931 }
37861 },37932 },
3786237933
37863 else => unreachable,37934 else => unreachable,
...@@ -38189,7 +38260,7 @@ fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {...@@ -38189,7 +38260,7 @@ fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {
3818938260
38190/// Not valid to call for packed unions.38261/// Not valid to call for packed unions.
38191/// Keep implementation in sync with `Module.unionFieldNormalAlignment`.38262/// 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 {
38193 const mod = sema.mod;38264 const mod = sema.mod;
38194 const ip = &mod.intern_pool;38265 const ip = &mod.intern_pool;
38195 const field_align = u.fieldAlign(ip, field_index);38266 const field_align = u.fieldAlign(ip, field_index);
...@@ -38237,7 +38308,7 @@ fn unionFieldIndex(...@@ -38237,7 +38308,7 @@ fn unionFieldIndex(
38237 const ip = &mod.intern_pool;38308 const ip = &mod.intern_pool;
38238 try sema.resolveTypeFields(union_ty);38309 try sema.resolveTypeFields(union_ty);
38239 const union_obj = mod.typeToUnion(union_ty).?;38310 const union_obj = mod.typeToUnion(union_ty).?;
38240 const field_index = union_obj.nameIndex(ip, field_name) orelse38311 const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse
38241 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);38312 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
38242 return @intCast(field_index);38313 return @intCast(field_index);
38243}38314}
...@@ -38274,7 +38345,7 @@ fn anonStructFieldIndex(...@@ -38274,7 +38345,7 @@ fn anonStructFieldIndex(
38274 .anon_struct_type => |anon_struct_type| for (anon_struct_type.names.get(ip), 0..) |name, i| {38345 .anon_struct_type => |anon_struct_type| for (anon_struct_type.names.get(ip), 0..) |name, i| {
38275 if (name == field_name) return @intCast(i);38346 if (name == field_name) return @intCast(i);
38276 },38347 },
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,
38278 else => unreachable,38349 else => unreachable,
38279 }38350 }
38280 return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{38351 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 {...@@ -38710,7 +38781,7 @@ fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
38710/// Asserts the type is an enum.38781/// Asserts the type is an enum.
38711fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {38782fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
38712 const mod = sema.mod;38783 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());
38714 assert(enum_type.tag_mode != .nonexhaustive);38785 assert(enum_type.tag_mode != .nonexhaustive);
38715 // The `tagValueIndex` function call below relies on the type being the integer tag type.38786 // The `tagValueIndex` function call below relies on the type being the integer tag type.
38716 // `getCoerced` assumes the value will fit the new type.38787 // `getCoerced` assumes the value will fit the new type.
src/TypedValue.zig+4-8
...@@ -89,7 +89,7 @@ pub fn print(...@@ -89,7 +89,7 @@ pub fn print(
8989
90 if (payload.tag) |tag| {90 if (payload.tag) |tag| {
91 try print(.{91 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),
93 .val = tag,93 .val = tag,
94 }, writer, level - 1, mod);94 }, writer, level - 1, mod);
95 try writer.writeAll(" = ");95 try writer.writeAll(" = ");
...@@ -247,7 +247,7 @@ pub fn print(...@@ -247,7 +247,7 @@ pub fn print(
247 if (level == 0) {247 if (level == 0) {
248 return writer.writeAll("(enum)");248 return writer.writeAll("(enum)");
249 }249 }
250 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;250 const enum_type = ip.loadEnumType(ty.toIntern());
251 if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| {251 if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| {
252 try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)});252 try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)});
253 return;253 return;
...@@ -398,7 +398,7 @@ pub fn print(...@@ -398,7 +398,7 @@ pub fn print(
398 }398 }
399 },399 },
400 .Union => {400 .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)];
402 try writer.print(".{i}", .{field_name.fmt(ip)});402 try writer.print(".{i}", .{field_name.fmt(ip)});
403 },403 },
404 .Pointer => {404 .Pointer => {
...@@ -482,11 +482,7 @@ fn printAggregate(...@@ -482,11 +482,7 @@ fn printAggregate(
482 for (0..max_len) |i| {482 for (0..max_len) |i| {
483 if (i != 0) try writer.writeAll(", ");483 if (i != 0) try writer.writeAll(", ");
484484
485 const field_name = switch (ip.indexToKey(ty.toIntern())) {485 const field_name = ty.structFieldName(@intCast(i), mod);
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 };
490486
491 if (field_name.unwrap()) |name| try writer.print(".{} = ", .{name.fmt(ip)});487 if (field_name.unwrap()) |name| try writer.print(".{} = ", .{name.fmt(ip)});
492 try print(.{488 try print(.{
src/Value.zig+16-10
...@@ -424,22 +424,28 @@ pub fn toType(self: Value) Type {...@@ -424,22 +424,28 @@ pub fn toType(self: Value) Type {
424424
425pub fn intFromEnum(val: Value, ty: Type, mod: *Module) Allocator.Error!Value {425pub fn intFromEnum(val: Value, ty: Type, mod: *Module) Allocator.Error!Value {
426 const ip = &mod.intern_pool;426 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)) {
428 // Assume it is already an integer and return it directly.429 // Assume it is already an integer and return it directly.
429 .simple_type, .int_type => val,430 .simple_type, .int_type => val,
430 .enum_literal => |enum_literal| {431 .enum_literal => |enum_literal| {
431 const field_index = ty.enumFieldIndex(enum_literal, mod).?;432 const field_index = ty.enumFieldIndex(enum_literal, mod).?;
432 return switch (ip.indexToKey(ty.toIntern())) {433 switch (ip.indexToKey(ty.toIntern())) {
433 // Assume it is already an integer and return it directly.434 // Assume it is already an integer and return it directly.
434 .simple_type, .int_type => val,435 .simple_type, .int_type => return val,
435 .enum_type => |enum_type| if (enum_type.values.len != 0)436 .enum_type => {
436 Value.fromInterned(enum_type.values.get(ip)[field_index])437 const enum_type = ip.loadEnumType(ty.toIntern());
437 else // Field index and integer values are the same.438 if (enum_type.values.len != 0) {
438 mod.intValue(Type.fromInterned(enum_type.tag_ty), field_index),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 },
439 else => unreachable,445 else => unreachable,
440 };446 }
441 },447 },
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)),
443 else => unreachable,449 else => unreachable,
444 };450 };
445}451}
...@@ -832,7 +838,7 @@ pub fn writeToPackedMemory(...@@ -832,7 +838,7 @@ pub fn writeToPackedMemory(
832 }838 }
833 },839 },
834 .Struct => {840 .Struct => {
835 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;841 const struct_type = ip.loadStructType(ty.toIntern());
836 // Sema is supposed to have emitted a compile error already in the case of Auto,842 // Sema is supposed to have emitted a compile error already in the case of Auto,
837 // and Extern is handled in non-packed writeToMemory.843 // and Extern is handled in non-packed writeToMemory.
838 assert(struct_type.layout == .Packed);844 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 {...@@ -3354,7 +3354,8 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3354 val.writeToMemory(ty, mod, &buf) catch unreachable;3354 val.writeToMemory(ty, mod, &buf) catch unreachable;
3355 return func.storeSimdImmd(buf);3355 return func.storeSimdImmd(buf);
3356 },3356 },
3357 .struct_type => |struct_type| {3357 .struct_type => {
3358 const struct_type = ip.loadStructType(ty.toIntern());
3358 // non-packed structs are not handled in this function because they3359 // non-packed structs are not handled in this function because they
3359 // are by-ref types.3360 // are by-ref types.
3360 assert(struct_type.layout == .Packed);3361 assert(struct_type.layout == .Packed);
...@@ -5411,7 +5412,7 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5411,7 +5412,7 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5411 const layout = union_ty.unionGetLayout(mod);5412 const layout = union_ty.unionGetLayout(mod);
5412 const union_obj = mod.typeToUnion(union_ty).?;5413 const union_obj = mod.typeToUnion(union_ty).?;
5413 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]);5414 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
5416 const tag_int = blk: {5417 const tag_int = blk: {
5417 const tag_ty = union_ty.unionTagTypeHypothetical(mod);5418 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 {...@@ -76,7 +76,7 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {
76 }76 }
77 const layout = ty.unionGetLayout(mod);77 const layout = ty.unionGetLayout(mod);
78 assert(layout.tag_size == 0);78 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;
80 const first_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[0]);80 const first_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[0]);
81 return classifyType(first_field_ty, mod);81 return classifyType(first_field_ty, mod);
82 },82 },
src/arch/x86_64/CodeGen.zig+1-1
...@@ -18183,7 +18183,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -18183,7 +18183,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
18183 const dst_mcv = try self.allocRegOrMem(inst, false);18183 const dst_mcv = try self.allocRegOrMem(inst, false);
1818418184
18185 const union_obj = mod.typeToUnion(union_ty).?;18185 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];
18187 const tag_ty = Type.fromInterned(union_obj.enum_tag_ty);18187 const tag_ty = Type.fromInterned(union_obj.enum_tag_ty);
18188 const field_index = tag_ty.enumFieldIndex(field_name, mod).?;18188 const field_index = tag_ty.enumFieldIndex(field_name, mod).?;
18189 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);18189 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
src/codegen.zig+73-70
...@@ -510,88 +510,91 @@ pub fn generateSymbol(...@@ -510,88 +510,91 @@ pub fn generateSymbol(
510 }510 }
511 }511 }
512 },512 },
513 .struct_type => |struct_type| switch (struct_type.layout) {513 .struct_type => {
514 .Packed => {514 const struct_type = ip.loadStructType(typed_value.ty.toIntern());
515 const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse515 switch (struct_type.layout) {
516 return error.Overflow;516 .Packed => {
517 const current_pos = code.items.len;517 const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse
518 try code.resize(current_pos + abi_size);518 return error.Overflow;
519 var bits: u16 = 0;519 const current_pos = code.items.len;
520520 try code.resize(current_pos + abi_size);
521 for (struct_type.field_types.get(ip), 0..) |field_ty, index| {521 var bits: u16 = 0;
522 const field_val = switch (aggregate.storage) {522
523 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{523 for (struct_type.field_types.get(ip), 0..) |field_ty, index| {
524 .ty = field_ty,524 const field_val = switch (aggregate.storage) {
525 .storage = .{ .u64 = bytes[index] },525 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
526 } }),526 .ty = field_ty,
527 .elems => |elems| elems[index],527 .storage = .{ .u64 = bytes[index] },
528 .repeated_elem => |elem| elem,528 } }),
529 };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();
538 switch (try generateSymbol(bin_file, src_loc, .{578 switch (try generateSymbol(bin_file, src_loc, .{
539 .ty = Type.fromInterned(field_ty),579 .ty = Type.fromInterned(field_ty),
540 .val = Value.fromInterned(field_val),580 .val = Value.fromInterned(field_val),
541 }, &tmp_list, debug_output, reloc_info)) {581 }, code, debug_output, reloc_info)) {
542 .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items),582 .ok => {},
543 .fail => |em| return Result{ .fail = em },583 .fail => |em| return Result{ .fail = em },
544 }584 }
545 } else {
546 Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), mod, code.items[current_pos..], bits) catch unreachable;
547 }585 }
548 bits += @as(u16, @intCast(Type.fromInterned(field_ty).bitSize(mod)));586
549 }587 const size = struct_type.size(ip).*;
550 },588 const alignment = struct_type.flagsPtr(ip).alignment.toByteUnitsOptional().?;
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 };
569589
570 const padding = math.cast(590 const padding = math.cast(
571 usize,591 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),
573 ) orelse return error.Overflow;594 ) orelse return error.Overflow;
574 if (padding > 0) try code.appendNTimes(0, padding);595 if (padding > 0) try code.appendNTimes(0, padding);
575596 },
576 switch (try generateSymbol(bin_file, src_loc, .{597 }
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 },
595 },598 },
596 else => unreachable,599 else => unreachable,
597 },600 },
src/codegen/c.zig+113-110
...@@ -1376,70 +1376,24 @@ pub const DeclGen = struct {...@@ -1376,70 +1376,24 @@ pub const DeclGen = struct {
1376 }1376 }
1377 try writer.writeByte('}');1377 try writer.writeByte('}');
1378 },1378 },
1379 .struct_type => |struct_type| switch (struct_type.layout) {1379 .struct_type => {
1380 .Auto, .Extern => {1380 const struct_type = ip.loadStructType(ty.toIntern());
1381 if (!location.isInitializer()) {1381 switch (struct_type.layout) {
1382 try writer.writeByte('(');1382 .Auto, .Extern => {
1383 try dg.renderType(writer, ty);1383 if (!location.isInitializer()) {
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);
1434 try writer.writeByte('(');1384 try writer.writeByte('(');
1385 try dg.renderType(writer, ty);
1386 try writer.writeByte(')');
1435 }1387 }
14361388
1437 var eff_index: usize = 0;1389 try writer.writeByte('{');
1438 var needs_closing_paren = false;1390 var empty = true;
1439 for (0..struct_type.field_types.len) |field_index| {1391 for (0..struct_type.field_types.len) |field_index| {
1440 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);1392 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1393 if (struct_type.fieldIsComptime(ip, field_index)) continue;
1441 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;1394 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
14421395
1396 if (!empty) try writer.writeByte(',');
1443 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {1397 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1444 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{1398 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1445 .ty = field_ty.toIntern(),1399 .ty = field_ty.toIntern(),
...@@ -1448,64 +1402,113 @@ pub const DeclGen = struct {...@@ -1448,64 +1402,113 @@ pub const DeclGen = struct {
1448 .elems => |elems| elems[field_index],1402 .elems => |elems| elems[field_index],
1449 .repeated_elem => |elem| elem,1403 .repeated_elem => |elem| elem,
1450 };1404 };
1451 const cast_context = IntCastContext{ .value = .{ .value = Value.fromInterned(field_val) } };1405 try dg.renderValue(writer, field_ty, Value.fromInterned(field_val), initializer_type);
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(", ");
14671406
1468 bit_offset += field_ty.bitSize(mod);1407 empty = false;
1469 needs_closing_paren = true;
1470 eff_index += 1;
1471 }1408 }
1472 } else {1409 try writer.writeByte('}');
1473 try writer.writeByte('(');1410 },
1474 // a << a_off | b << b_off | c << c_off1411 .Packed => {
1475 var empty = true;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
1476 for (0..struct_type.field_types.len) |field_index| {1420 for (0..struct_type.field_types.len) |field_index| {
1477 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);1421 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1478 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;1422 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) {
1481 try writer.writeByte('(');1427 try writer.writeByte('(');
1482 try dg.renderType(writer, ty);1428 try dg.renderValue(writer, ty, Value.undef, initializer_type);
1483 try writer.writeByte(')');1429 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) {1439 var eff_index: usize = 0;
1486 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{1440 var needs_closing_paren = false;
1487 .ty = field_ty.toIntern(),1441 for (0..struct_type.field_types.len) |field_index| {
1488 .storage = .{ .u64 = bytes[field_index] },1442 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1489 } }),1443 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
1490 .elems => |elems| elems[field_index],1444
1491 .repeated_elem => |elem| elem,1445 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1492 };1446 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
14931447 .ty = field_ty.toIntern(),
1494 if (bit_offset != 0) {1448 .storage = .{ .u64 = bytes[field_index] },
1495 try dg.renderValue(writer, field_ty, Value.fromInterned(field_val), .Other);1449 } }),
1496 try writer.writeAll(" << ");1450 .elems => |elems| elems[field_index],
1497 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);1451 .repeated_elem => |elem| elem,
1498 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);1452 };
1499 } else {1453 const cast_context = IntCastContext{ .value = .{ .value = Value.fromInterned(field_val) } };
1500 try dg.renderValue(writer, field_ty, Value.fromInterned(field_val), .Other);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;
1501 }1473 }
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);1482 if (!empty) try writer.writeAll(" | ");
1504 empty = false;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(')');
1505 }1509 }
1506 try writer.writeByte(')');1510 },
1507 }1511 }
1508 },
1509 },1512 },
1510 else => unreachable,1513 else => unreachable,
1511 },1514 },
...@@ -1547,7 +1550,7 @@ pub const DeclGen = struct {...@@ -1547,7 +1550,7 @@ pub const DeclGen = struct {
15471550
1548 const field_index = mod.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;1551 const field_index = mod.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;
1549 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);1552 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];
1551 if (union_obj.getLayout(ip) == .Packed) {1554 if (union_obj.getLayout(ip) == .Packed) {
1552 if (field_ty.hasRuntimeBits(mod)) {1555 if (field_ty.hasRuntimeBits(mod)) {
1553 if (field_ty.isPtrAtRuntime(mod)) {1556 if (field_ty.isPtrAtRuntime(mod)) {
...@@ -5502,7 +5505,7 @@ fn fieldLocation(...@@ -5502,7 +5505,7 @@ fn fieldLocation(
5502 .{ .field = .{ .identifier = "payload" } }5505 .{ .field = .{ .identifier = "payload" } }
5503 else5506 else
5504 .begin;5507 .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];
5506 return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_|5509 return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_|
5507 .{ .payload_identifier = ip.stringToSlice(field_name) }5510 .{ .payload_identifier = ip.stringToSlice(field_name) }
5508 else5511 else
...@@ -5735,8 +5738,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5735,8 +5738,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5735 else5738 else
5736 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, mod)) },5739 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, mod)) },
57375740
5738 .union_type => |union_type| field_name: {5741 .union_type => field_name: {
5739 const union_obj = ip.loadUnionType(union_type);5742 const union_obj = ip.loadUnionType(struct_ty.toIntern());
5740 if (union_obj.flagsPtr(ip).layout == .Packed) {5743 if (union_obj.flagsPtr(ip).layout == .Packed) {
5741 const operand_lval = if (struct_byval == .constant) blk: {5744 const operand_lval = if (struct_byval == .constant) blk: {
5742 const operand_local = try f.allocLocal(inst, struct_ty);5745 const operand_local = try f.allocLocal(inst, struct_ty);
...@@ -5762,8 +5765,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5762,8 +5765,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
57625765
5763 return local;5766 return local;
5764 } else {5767 } else {
5765 const name = union_obj.field_names.get(ip)[extra.field_index];5768 const name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
5766 break :field_name if (union_type.hasTag(ip)) .{5769 break :field_name if (union_obj.hasTag(ip)) .{
5767 .payload_identifier = ip.stringToSlice(name),5770 .payload_identifier = ip.stringToSlice(name),
5768 } else .{5771 } else .{
5769 .identifier = ip.stringToSlice(name),5772 .identifier = ip.stringToSlice(name),
...@@ -7171,7 +7174,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7171,7 +7174,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
71717174
7172 const union_ty = f.typeOfIndex(inst);7175 const union_ty = f.typeOfIndex(inst);
7173 const union_obj = mod.typeToUnion(union_ty).?;7176 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];
7175 const payload_ty = f.typeOf(extra.init);7178 const payload_ty = f.typeOf(extra.init);
7176 const payload = try f.resolveInst(extra.init);7179 const payload = try f.resolveInst(extra.init);
7177 try reap(f, inst, &.{extra.init});7180 try reap(f, inst, &.{extra.init});
src/codegen/c/type.zig+8-8
...@@ -1507,7 +1507,7 @@ pub const CType = extern union {...@@ -1507,7 +1507,7 @@ pub const CType = extern union {
1507 if (lookup.isMutable()) {1507 if (lookup.isMutable()) {
1508 for (0..switch (zig_ty_tag) {1508 for (0..switch (zig_ty_tag) {
1509 .Struct => ty.structFieldCount(mod),1509 .Struct => ty.structFieldCount(mod),
1510 .Union => mod.typeToUnion(ty).?.field_names.len,1510 .Union => mod.typeToUnion(ty).?.field_types.len,
1511 else => unreachable,1511 else => unreachable,
1512 }) |field_i| {1512 }) |field_i| {
1513 const field_ty = ty.structFieldType(field_i, mod);1513 const field_ty = ty.structFieldType(field_i, mod);
...@@ -1589,7 +1589,7 @@ pub const CType = extern union {...@@ -1589,7 +1589,7 @@ pub const CType = extern union {
1589 var is_packed = false;1589 var is_packed = false;
1590 for (0..switch (zig_ty_tag) {1590 for (0..switch (zig_ty_tag) {
1591 .Struct => ty.structFieldCount(mod),1591 .Struct => ty.structFieldCount(mod),
1592 .Union => mod.typeToUnion(ty).?.field_names.len,1592 .Union => mod.typeToUnion(ty).?.field_types.len,
1593 else => unreachable,1593 else => unreachable,
1594 }) |field_i| {1594 }) |field_i| {
1595 const field_ty = ty.structFieldType(field_i, mod);1595 const field_ty = ty.structFieldType(field_i, mod);
...@@ -1940,7 +1940,7 @@ pub const CType = extern union {...@@ -1940,7 +1940,7 @@ pub const CType = extern union {
1940 const zig_ty_tag = ty.zigTypeTag(mod);1940 const zig_ty_tag = ty.zigTypeTag(mod);
1941 const fields_len = switch (zig_ty_tag) {1941 const fields_len = switch (zig_ty_tag) {
1942 .Struct => ty.structFieldCount(mod),1942 .Struct => ty.structFieldCount(mod),
1943 .Union => mod.typeToUnion(ty).?.field_names.len,1943 .Union => mod.typeToUnion(ty).?.field_types.len,
1944 else => unreachable,1944 else => unreachable,
1945 };1945 };
19461946
...@@ -1967,7 +1967,7 @@ pub const CType = extern union {...@@ -1967,7 +1967,7 @@ pub const CType = extern union {
1967 else1967 else
1968 arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {1968 arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {
1969 .Struct => ty.legacyStructFieldName(field_i, mod),1969 .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],
1971 else => unreachable,1971 else => unreachable,
1972 })),1972 })),
1973 .type = store.set.typeToIndex(field_ty, mod, switch (kind) {1973 .type = store.set.typeToIndex(field_ty, mod, switch (kind) {
...@@ -2097,7 +2097,7 @@ pub const CType = extern union {...@@ -2097,7 +2097,7 @@ pub const CType = extern union {
2097 var c_field_i: usize = 0;2097 var c_field_i: usize = 0;
2098 for (0..switch (zig_ty_tag) {2098 for (0..switch (zig_ty_tag) {
2099 .Struct => ty.structFieldCount(mod),2099 .Struct => ty.structFieldCount(mod),
2100 .Union => mod.typeToUnion(ty).?.field_names.len,2100 .Union => mod.typeToUnion(ty).?.field_types.len,
2101 else => unreachable,2101 else => unreachable,
2102 }) |field_i_usize| {2102 }) |field_i_usize| {
2103 const field_i: u32 = @intCast(field_i_usize);2103 const field_i: u32 = @intCast(field_i_usize);
...@@ -2120,7 +2120,7 @@ pub const CType = extern union {...@@ -2120,7 +2120,7 @@ pub const CType = extern union {
2120 else2120 else
2121 ip.stringToSlice(switch (zig_ty_tag) {2121 ip.stringToSlice(switch (zig_ty_tag) {
2122 .Struct => ty.legacyStructFieldName(field_i, mod),2122 .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],
2124 else => unreachable,2124 else => unreachable,
2125 }),2125 }),
2126 mem.span(c_field.name),2126 mem.span(c_field.name),
...@@ -2226,7 +2226,7 @@ pub const CType = extern union {...@@ -2226,7 +2226,7 @@ pub const CType = extern union {
2226 const zig_ty_tag = ty.zigTypeTag(mod);2226 const zig_ty_tag = ty.zigTypeTag(mod);
2227 for (0..switch (ty.zigTypeTag(mod)) {2227 for (0..switch (ty.zigTypeTag(mod)) {
2228 .Struct => ty.structFieldCount(mod),2228 .Struct => ty.structFieldCount(mod),
2229 .Union => mod.typeToUnion(ty).?.field_names.len,2229 .Union => mod.typeToUnion(ty).?.field_types.len,
2230 else => unreachable,2230 else => unreachable,
2231 }) |field_i_usize| {2231 }) |field_i_usize| {
2232 const field_i: u32 = @intCast(field_i_usize);2232 const field_i: u32 = @intCast(field_i_usize);
...@@ -2245,7 +2245,7 @@ pub const CType = extern union {...@@ -2245,7 +2245,7 @@ pub const CType = extern union {
2245 else2245 else
2246 mod.intern_pool.stringToSlice(switch (zig_ty_tag) {2246 mod.intern_pool.stringToSlice(switch (zig_ty_tag) {
2247 .Struct => ty.legacyStructFieldName(field_i, mod),2247 .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],
2249 else => unreachable,2249 else => unreachable,
2250 }));2250 }));
2251 autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align");2251 autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align");
src/codegen/llvm.zig+33-28
...@@ -1997,7 +1997,7 @@ pub const Object = struct {...@@ -1997,7 +1997,7 @@ pub const Object = struct {
1997 return debug_enum_type;1997 return debug_enum_type;
1998 }1998 }
19991999
2000 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;2000 const enum_type = ip.loadEnumType(ty.toIntern());
20012001
2002 const enumerators = try gpa.alloc(Builder.Metadata, enum_type.names.len);2002 const enumerators = try gpa.alloc(Builder.Metadata, enum_type.names.len);
2003 defer gpa.free(enumerators);2003 defer gpa.free(enumerators);
...@@ -2507,8 +2507,8 @@ pub const Object = struct {...@@ -2507,8 +2507,8 @@ pub const Object = struct {
2507 try o.debug_type_map.put(gpa, ty, debug_struct_type);2507 try o.debug_type_map.put(gpa, ty, debug_struct_type);
2508 return debug_struct_type;2508 return debug_struct_type;
2509 },2509 },
2510 .struct_type => |struct_type| {2510 .struct_type => {
2511 if (!struct_type.haveFieldTypes(ip)) {2511 if (!ip.loadStructType(ty.toIntern()).haveFieldTypes(ip)) {
2512 // This can happen if a struct type makes it all the way to2512 // This can happen if a struct type makes it all the way to
2513 // flush() without ever being instantiated or referenced (even2513 // flush() without ever being instantiated or referenced (even
2514 // via pointer). The only reason we are hearing about it now is2514 // via pointer). The only reason we are hearing about it now is
...@@ -2597,15 +2597,14 @@ pub const Object = struct {...@@ -2597,15 +2597,14 @@ pub const Object = struct {
2597 const name = try o.allocTypeName(ty);2597 const name = try o.allocTypeName(ty);
2598 defer gpa.free(name);2598 defer gpa.free(name);
25992599
2600 const union_type = ip.indexToKey(ty.toIntern()).union_type;2600 const union_type = ip.loadUnionType(ty.toIntern());
2601 if (!union_type.haveFieldTypes(ip) or !ty.hasRuntimeBitsIgnoreComptime(mod)) {2601 if (!union_type.haveFieldTypes(ip) or !ty.hasRuntimeBitsIgnoreComptime(mod)) {
2602 const debug_union_type = try o.makeEmptyNamespaceDebugType(owner_decl_index);2602 const debug_union_type = try o.makeEmptyNamespaceDebugType(owner_decl_index);
2603 try o.debug_type_map.put(gpa, ty, debug_union_type);2603 try o.debug_type_map.put(gpa, ty, debug_union_type);
2604 return debug_union_type;2604 return debug_union_type;
2605 }2605 }
26062606
2607 const union_obj = ip.loadUnionType(union_type);2607 const layout = mod.getUnionLayout(union_type);
2608 const layout = mod.getUnionLayout(union_obj);
26092608
2610 const debug_fwd_ref = try o.builder.debugForwardReference();2609 const debug_fwd_ref = try o.builder.debugForwardReference();
26112610
...@@ -2622,7 +2621,7 @@ pub const Object = struct {...@@ -2622,7 +2621,7 @@ pub const Object = struct {
2622 ty.abiSize(mod) * 8,2621 ty.abiSize(mod) * 8,
2623 ty.abiAlignment(mod).toByteUnits(0) * 8,2622 ty.abiAlignment(mod).toByteUnits(0) * 8,
2624 try o.builder.debugTuple(2623 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))},
2626 ),2625 ),
2627 );2626 );
26282627
...@@ -2636,21 +2635,23 @@ pub const Object = struct {...@@ -2636,21 +2635,23 @@ pub const Object = struct {
2636 var fields: std.ArrayListUnmanaged(Builder.Metadata) = .{};2635 var fields: std.ArrayListUnmanaged(Builder.Metadata) = .{};
2637 defer fields.deinit(gpa);2636 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
2641 const debug_union_fwd_ref = if (layout.tag_size == 0)2640 const debug_union_fwd_ref = if (layout.tag_size == 0)
2642 debug_fwd_ref2641 debug_fwd_ref
2643 else2642 else
2644 try o.builder.debugForwardReference();2643 try o.builder.debugForwardReference();
26452644
2646 for (0..union_obj.field_names.len) |field_index| {2645 const tag_type = union_type.loadTagType(ip);
2647 const field_ty = union_obj.field_types.get(ip)[field_index];2646
2647 for (0..tag_type.names.len) |field_index| {
2648 const field_ty = union_type.field_types.get(ip)[field_index];
2648 if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(mod)) continue;2649 if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(mod)) continue;
26492650
2650 const field_size = Type.fromInterned(field_ty).abiSize(mod);2651 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];
2654 fields.appendAssumeCapacity(try o.builder.debugMemberType(2655 fields.appendAssumeCapacity(try o.builder.debugMemberType(
2655 try o.builder.metadataString(ip.stringToSlice(field_name)),2656 try o.builder.metadataString(ip.stringToSlice(field_name)),
2656 .none, // File2657 .none, // File
...@@ -2706,7 +2707,7 @@ pub const Object = struct {...@@ -2706,7 +2707,7 @@ pub const Object = struct {
2706 .none, // File2707 .none, // File
2707 debug_fwd_ref,2708 debug_fwd_ref,
2708 0, // Line2709 0, // Line
2709 try o.lowerDebugType(Type.fromInterned(union_obj.enum_tag_ty)),2710 try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty)),
2710 layout.tag_size * 8,2711 layout.tag_size * 8,
2711 layout.tag_align.toByteUnits(0) * 8,2712 layout.tag_align.toByteUnits(0) * 8,
2712 tag_offset * 8,2713 tag_offset * 8,
...@@ -3321,9 +3322,11 @@ pub const Object = struct {...@@ -3321,9 +3322,11 @@ pub const Object = struct {
3321 return o.builder.structType(.normal, fields[0..fields_len]);3322 return o.builder.structType(.normal, fields[0..fields_len]);
3322 },3323 },
3323 .simple_type => unreachable,3324 .simple_type => unreachable,
3324 .struct_type => |struct_type| {3325 .struct_type => {
3325 if (o.type_map.get(t.toIntern())) |value| return value;3326 if (o.type_map.get(t.toIntern())) |value| return value;
33263327
3328 const struct_type = ip.loadStructType(t.toIntern());
3329
3327 if (struct_type.layout == .Packed) {3330 if (struct_type.layout == .Packed) {
3328 const int_ty = try o.lowerType(Type.fromInterned(struct_type.backingIntType(ip).*));3331 const int_ty = try o.lowerType(Type.fromInterned(struct_type.backingIntType(ip).*));
3329 try o.type_map.put(o.gpa, t.toIntern(), int_ty);3332 try o.type_map.put(o.gpa, t.toIntern(), int_ty);
...@@ -3468,10 +3471,10 @@ pub const Object = struct {...@@ -3468,10 +3471,10 @@ pub const Object = struct {
3468 }3471 }
3469 return o.builder.structType(.normal, llvm_field_types.items);3472 return o.builder.structType(.normal, llvm_field_types.items);
3470 },3473 },
3471 .union_type => |union_type| {3474 .union_type => {
3472 if (o.type_map.get(t.toIntern())) |value| return value;3475 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());
3475 const layout = mod.getUnionLayout(union_obj);3478 const layout = mod.getUnionLayout(union_obj);
34763479
3477 if (union_obj.flagsPtr(ip).layout == .Packed) {3480 if (union_obj.flagsPtr(ip).layout == .Packed) {
...@@ -3545,17 +3548,16 @@ pub const Object = struct {...@@ -3545,17 +3548,16 @@ pub const Object = struct {
3545 );3548 );
3546 return ty;3549 return ty;
3547 },3550 },
3548 .opaque_type => |opaque_type| {3551 .opaque_type => {
3549 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());3552 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
3550 if (!gop.found_existing) {3553 if (!gop.found_existing) {
3551 const name = try o.builder.string(ip.stringToSlice(3554 const decl = mod.declPtr(ip.loadOpaqueType(t.toIntern()).decl);
3552 try mod.opaqueFullyQualifiedName(opaque_type),3555 const name = try o.builder.string(ip.stringToSlice(try decl.fullyQualifiedName(mod)));
3553 ));
3554 gop.value_ptr.* = try o.builder.opaqueType(name);3556 gop.value_ptr.* = try o.builder.opaqueType(name);
3555 }3557 }
3556 return gop.value_ptr.*;3558 return gop.value_ptr.*;
3557 },3559 },
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)),
3559 .func_type => |func_type| try o.lowerTypeFn(func_type),3561 .func_type => |func_type| try o.lowerTypeFn(func_type),
3560 .error_set_type, .inferred_error_set_type => try o.errorIntType(),3562 .error_set_type, .inferred_error_set_type => try o.errorIntType(),
3561 // values, not types3563 // values, not types
...@@ -4032,7 +4034,8 @@ pub const Object = struct {...@@ -4032,7 +4034,8 @@ pub const Object = struct {
4032 else4034 else
4033 struct_ty, vals);4035 struct_ty, vals);
4034 },4036 },
4035 .struct_type => |struct_type| {4037 .struct_type => {
4038 const struct_type = ip.loadStructType(ty.toIntern());
4036 assert(struct_type.haveLayout(ip));4039 assert(struct_type.haveLayout(ip));
4037 const struct_ty = try o.lowerType(ty);4040 const struct_ty = try o.lowerType(ty);
4038 if (struct_type.layout == .Packed) {4041 if (struct_type.layout == .Packed) {
...@@ -4596,7 +4599,7 @@ pub const Object = struct {...@@ -4596,7 +4599,7 @@ pub const Object = struct {
4596 fn getEnumTagNameFunction(o: *Object, enum_ty: Type) !Builder.Function.Index {4599 fn getEnumTagNameFunction(o: *Object, enum_ty: Type) !Builder.Function.Index {
4597 const zcu = o.module;4600 const zcu = o.module;
4598 const ip = &zcu.intern_pool;4601 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
4601 // TODO: detect when the type changes and re-emit this function.4604 // TODO: detect when the type changes and re-emit this function.
4602 const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl);4605 const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl);
...@@ -9620,7 +9623,7 @@ pub const FuncGen = struct {...@@ -9620,7 +9623,7 @@ pub const FuncGen = struct {
9620 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {9623 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
9621 const o = self.dg.object;9624 const o = self.dg.object;
9622 const zcu = o.module;9625 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
9625 // TODO: detect when the type changes and re-emit this function.9628 // TODO: detect when the type changes and re-emit this function.
9626 const gop = try o.named_enum_map.getOrPut(o.gpa, enum_type.decl);9629 const gop = try o.named_enum_map.getOrPut(o.gpa, enum_type.decl);
...@@ -10092,7 +10095,7 @@ pub const FuncGen = struct {...@@ -10092,7 +10095,7 @@ pub const FuncGen = struct {
1009210095
10093 const tag_int = blk: {10096 const tag_int = blk: {
10094 const tag_ty = union_ty.unionTagTypeHypothetical(mod);10097 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];
10096 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;10099 const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;
10097 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);10100 const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
10098 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);10101 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...@@ -11154,7 +11157,8 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E
11154 if (first_non_integer == null or classes[first_non_integer.?] == .none) {11157 if (first_non_integer == null or classes[first_non_integer.?] == .none) {
11155 assert(first_non_integer orelse classes.len == types_index);11158 assert(first_non_integer orelse classes.len == types_index);
11156 switch (ip.indexToKey(return_type.toIntern())) {11159 switch (ip.indexToKey(return_type.toIntern())) {
11157 .struct_type => |struct_type| {11160 .struct_type => {
11161 const struct_type = ip.loadStructType(return_type.toIntern());
11158 assert(struct_type.haveLayout(ip));11162 assert(struct_type.haveLayout(ip));
11159 const size: u64 = struct_type.size(ip).*;11163 const size: u64 = struct_type.size(ip).*;
11160 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);11164 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
...@@ -11446,7 +11450,8 @@ const ParamTypeIterator = struct {...@@ -11446,7 +11450,8 @@ const ParamTypeIterator = struct {
11446 return .byref;11450 return .byref;
11447 }11451 }
11448 switch (ip.indexToKey(ty.toIntern())) {11452 switch (ip.indexToKey(ty.toIntern())) {
11449 .struct_type => |struct_type| {11453 .struct_type => {
11454 const struct_type = ip.loadStructType(ty.toIntern());
11450 assert(struct_type.haveLayout(ip));11455 assert(struct_type.haveLayout(ip));
11451 const size: u64 = struct_type.size(ip).*;11456 const size: u64 = struct_type.size(ip).*;
11452 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);11457 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
...@@ -11562,7 +11567,7 @@ fn isByRef(ty: Type, mod: *Module) bool {...@@ -11562,7 +11567,7 @@ fn isByRef(ty: Type, mod: *Module) bool {
11562 }11567 }
11563 return false;11568 return false;
11564 },11569 },
11565 .struct_type => |s| s,11570 .struct_type => ip.loadStructType(ty.toIntern()),
11566 else => unreachable,11571 else => unreachable,
11567 };11572 };
1156811573
src/codegen/spirv.zig+9-11
...@@ -1528,7 +1528,7 @@ const DeclGen = struct {...@@ -1528,7 +1528,7 @@ const DeclGen = struct {
1528 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });1528 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
1529 return ty_ref;1529 return ty_ref;
1530 },1530 },
1531 .struct_type => |struct_type| struct_type,1531 .struct_type => ip.loadStructType(ty.toIntern()),
1532 else => unreachable,1532 else => unreachable,
1533 };1533 };
15341534
...@@ -3633,7 +3633,8 @@ const DeclGen = struct {...@@ -3633,7 +3633,8 @@ const DeclGen = struct {
3633 index += 1;3633 index += 1;
3634 }3634 }
3635 },3635 },
3636 .struct_type => |struct_type| {3636 .struct_type => {
3637 const struct_type = ip.loadStructType(result_ty.toIntern());
3637 var it = struct_type.iterateRuntimeOrder(ip);3638 var it = struct_type.iterateRuntimeOrder(ip);
3638 for (elements, 0..) |element, i| {3639 for (elements, 0..) |element, i| {
3639 const field_index = it.next().?;3640 const field_index = it.next().?;
...@@ -3901,36 +3902,33 @@ const DeclGen = struct {...@@ -3901,36 +3902,33 @@ const DeclGen = struct {
3901 const mod = self.module;3902 const mod = self.module;
3902 const ip = &mod.intern_pool;3903 const ip = &mod.intern_pool;
3903 const union_ty = mod.typeToUnion(ty).?;3904 const union_ty = mod.typeToUnion(ty).?;
3905 const tag_ty = Type.fromInterned(union_ty.enum_tag_ty);
39043906
3905 if (union_ty.getLayout(ip) == .Packed) {3907 if (union_ty.getLayout(ip) == .Packed) {
3906 unreachable; // TODO3908 unreachable; // TODO
3907 }3909 }
39083910
3909 const maybe_tag_ty = ty.unionTagTypeSafety(mod);
3910 const layout = self.unionLayout(ty);3911 const layout = self.unionLayout(ty);
39113912
3912 const tag_int = if (layout.tag_size != 0) blk: {3913 const tag_int = if (layout.tag_size != 0) blk: {
3913 const tag_ty = maybe_tag_ty.?;3914 const tag_val = try mod.enumValueFieldIndex(tag_ty, active_field);
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);
3917 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);3915 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);
3918 break :blk tag_int_val.toUnsignedInt(mod);3916 break :blk tag_int_val.toUnsignedInt(mod);
3919 } else 0;3917 } else 0;
39203918
3921 if (!layout.has_payload) {3919 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);
3923 return try self.constInt(tag_ty_ref, tag_int);3921 return try self.constInt(tag_ty_ref, tag_int);
3924 }3922 }
39253923
3926 const tmp_id = try self.alloc(ty, .{ .storage_class = .Function });3924 const tmp_id = try self.alloc(ty, .{ .storage_class = .Function });
39273925
3928 if (layout.tag_size != 0) {3926 if (layout.tag_size != 0) {
3929 const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct);3927 const tag_ty_ref = try self.resolveType(tag_ty, .direct);
3930 const tag_ptr_ty_ref = try self.ptrType(maybe_tag_ty.?, .Function);3928 const tag_ptr_ty_ref = try self.ptrType(tag_ty, .Function);
3931 const ptr_id = try self.accessChain(tag_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});3929 const ptr_id = try self.accessChain(tag_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.tag_index))});
3932 const tag_id = try self.constInt(tag_ty_ref, tag_int);3930 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, .{});
3934 }3932 }
39353933
3936 const payload_ty = Type.fromInterned(union_ty.field_types.get(ip)[active_field]);3934 const payload_ty = Type.fromInterned(union_ty.field_types.get(ip)[active_field]);
src/glibc.zig+1
...@@ -1118,6 +1118,7 @@ fn buildSharedLib(...@@ -1118,6 +1118,7 @@ fn buildSharedLib(
1118 .cc_argv = &.{},1118 .cc_argv = &.{},
1119 .parent = null,1119 .parent = null,
1120 .builtin_mod = null,1120 .builtin_mod = null,
1121 .builtin_modules = null, // there is only one module in this compilation
1121 });1122 });
11221123
1123 const c_source_files = [1]Compilation.CSourceFile{1124 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 {...@@ -181,6 +181,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) !void {
181 .cc_argv = &.{},181 .cc_argv = &.{},
182 .parent = null,182 .parent = null,
183 .builtin_mod = null,183 .builtin_mod = null,
184 .builtin_modules = null, // there is only one module in this compilation
184 });185 });
185186
186 var c_source_files = try std.ArrayList(Compilation.CSourceFile).initCapacity(arena, libcxx_files.len);187 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 {...@@ -395,6 +396,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) !void {
395 .cc_argv = &.{},396 .cc_argv = &.{},
396 .parent = null,397 .parent = null,
397 .builtin_mod = null,398 .builtin_mod = null,
399 .builtin_modules = null, // there is only one module in this compilation
398 });400 });
399401
400 var c_source_files = try std.ArrayList(Compilation.CSourceFile).initCapacity(arena, libcxxabi_files.len);402 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...@@ -92,6 +92,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) BuildError!v
92 .cc_argv = &common_flags,92 .cc_argv = &common_flags,
93 .parent = null,93 .parent = null,
94 .builtin_mod = null,94 .builtin_mod = null,
95 .builtin_modules = null, // there is only one module in this compilation
95 }) catch |err| {96 }) catch |err| {
96 comp.setMiscFailure(97 comp.setMiscFailure(
97 .libtsan,98 .libtsan,
src/libunwind.zig+1
...@@ -58,6 +58,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void {...@@ -58,6 +58,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void {
58 .cc_argv = &.{},58 .cc_argv = &.{},
59 .parent = null,59 .parent = null,
60 .builtin_mod = null,60 .builtin_mod = null,
61 .builtin_modules = null, // there is only one module in this compilation
61 });62 });
6263
63 const root_name = "unwind";64 const root_name = "unwind";
src/link/Dwarf.zig+4-3
...@@ -311,7 +311,8 @@ pub const DeclState = struct {...@@ -311,7 +311,8 @@ pub const DeclState = struct {
311 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);311 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
312 }312 }
313 },313 },
314 .struct_type => |struct_type| {314 .struct_type => {
315 const struct_type = ip.loadStructType(ty.toIntern());
315 // DW.AT.name, DW.FORM.string316 // DW.AT.name, DW.FORM.string
316 try ty.print(dbg_info_buffer.writer(), mod);317 try ty.print(dbg_info_buffer.writer(), mod);
317 try dbg_info_buffer.append(0);318 try dbg_info_buffer.append(0);
...@@ -374,7 +375,7 @@ pub const DeclState = struct {...@@ -374,7 +375,7 @@ pub const DeclState = struct {
374 try ty.print(dbg_info_buffer.writer(), mod);375 try ty.print(dbg_info_buffer.writer(), mod);
375 try dbg_info_buffer.append(0);376 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);
378 for (enum_type.names.get(ip), 0..) |field_name_index, field_i| {379 for (enum_type.names.get(ip), 0..) |field_name_index, field_i| {
379 const field_name = ip.stringToSlice(field_name_index);380 const field_name = ip.stringToSlice(field_name_index);
380 // DW.AT.enumerator381 // DW.AT.enumerator
...@@ -442,7 +443,7 @@ pub const DeclState = struct {...@@ -442,7 +443,7 @@ pub const DeclState = struct {
442 try dbg_info_buffer.append(0);443 try dbg_info_buffer.append(0);
443 }444 }
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| {
446 if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;447 if (!Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;
447 // DW.AT.member448 // DW.AT.member
448 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_member));449 try dbg_info_buffer.append(@intFromEnum(AbbrevCode.struct_member));
src/main.zig+15-3
...@@ -2708,7 +2708,9 @@ fn buildOutputType(...@@ -2708,7 +2708,9 @@ fn buildOutputType(
2708 create_module.opts.emit_bin = emit_bin != .no;2708 create_module.opts.emit_bin = emit_bin != .no;
2709 create_module.opts.any_c_source_files = create_module.c_source_files.items.len != 0;2709 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);
2712 for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| {2714 for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| {
2713 if (cli_mod.resolved == null)2715 if (cli_mod.resolved == null)
2714 fatal("module '{s}' declared but not used", .{key});2716 fatal("module '{s}' declared but not used", .{key});
...@@ -2753,6 +2755,7 @@ fn buildOutputType(...@@ -2753,6 +2755,7 @@ fn buildOutputType(
2753 .global = create_module.resolved_options,2755 .global = create_module.resolved_options,
2754 .parent = main_mod,2756 .parent = main_mod,
2755 .builtin_mod = main_mod.getBuiltinDependency(),2757 .builtin_mod = main_mod.getBuiltinDependency(),
2758 .builtin_modules = null, // `builtin_mod` is specified
2756 });2759 });
2757 test_mod.deps = try main_mod.deps.clone(arena);2760 test_mod.deps = try main_mod.deps.clone(arena);
2758 break :test_mod test_mod;2761 break :test_mod test_mod;
...@@ -2771,6 +2774,7 @@ fn buildOutputType(...@@ -2771,6 +2774,7 @@ fn buildOutputType(
2771 .global = create_module.resolved_options,2774 .global = create_module.resolved_options,
2772 .parent = main_mod,2775 .parent = main_mod,
2773 .builtin_mod = main_mod.getBuiltinDependency(),2776 .builtin_mod = main_mod.getBuiltinDependency(),
2777 .builtin_modules = null, // `builtin_mod` is specified
2774 });2778 });
27752779
2776 break :root_mod test_mod;2780 break :root_mod test_mod;
...@@ -3479,6 +3483,7 @@ fn createModule(...@@ -3479,6 +3483,7 @@ fn createModule(
3479 index: usize,3483 index: usize,
3480 parent: ?*Package.Module,3484 parent: ?*Package.Module,
3481 zig_lib_directory: Cache.Directory,3485 zig_lib_directory: Cache.Directory,
3486 builtin_modules: *std.StringHashMapUnmanaged(*Package.Module),
3482) Allocator.Error!*Package.Module {3487) Allocator.Error!*Package.Module {
3483 const cli_mod = &create_module.modules.values()[index];3488 const cli_mod = &create_module.modules.values()[index];
3484 if (cli_mod.resolved) |m| return m;3489 if (cli_mod.resolved) |m| return m;
...@@ -3931,6 +3936,7 @@ fn createModule(...@@ -3931,6 +3936,7 @@ fn createModule(
3931 .global = create_module.resolved_options,3936 .global = create_module.resolved_options,
3932 .parent = parent,3937 .parent = parent,
3933 .builtin_mod = null,3938 .builtin_mod = null,
3939 .builtin_modules = builtin_modules,
3934 }) catch |err| switch (err) {3940 }) catch |err| switch (err) {
3935 error.ValgrindUnsupportedOnTarget => fatal("unable to create module '{s}': valgrind does not support the selected target CPU architecture", .{name}),3941 error.ValgrindUnsupportedOnTarget => fatal("unable to create module '{s}': valgrind does not support the selected target CPU architecture", .{name}),
3936 error.TargetRequiresSingleThreaded => fatal("unable to create module '{s}': the selected target does not support multithreading", .{name}),3942 error.TargetRequiresSingleThreaded => fatal("unable to create module '{s}': the selected target does not support multithreading", .{name}),
...@@ -3953,7 +3959,7 @@ fn createModule(...@@ -3953,7 +3959,7 @@ fn createModule(
3953 for (cli_mod.deps) |dep| {3959 for (cli_mod.deps) |dep| {
3954 const dep_index = create_module.modules.getIndex(dep.value) orelse3960 const dep_index = create_module.modules.getIndex(dep.value) orelse
3955 fatal("module '{s}' depends on non-existent module '{s}'", .{ name, dep.key });3961 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);
3957 try mod.deps.put(arena, dep.key, dep_mod);3963 try mod.deps.put(arena, dep.key, dep_mod);
3958 }3964 }
39593965
...@@ -5249,6 +5255,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -5249,6 +5255,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
5249 .global = config,5255 .global = config,
5250 .parent = null,5256 .parent = null,
5251 .builtin_mod = null,5257 .builtin_mod = null,
5258 .builtin_modules = null, // all modules will inherit this one's builtin
5252 });5259 });
52535260
5254 const builtin_mod = root_mod.getBuiltinDependency();5261 const builtin_mod = root_mod.getBuiltinDependency();
...@@ -5265,6 +5272,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -5265,6 +5272,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
5265 .global = config,5272 .global = config,
5266 .parent = root_mod,5273 .parent = root_mod,
5267 .builtin_mod = builtin_mod,5274 .builtin_mod = builtin_mod,
5275 .builtin_modules = null, // `builtin_mod` is specified
5268 });5276 });
52695277
5270 var cleanup_build_dir: ?fs.Dir = null;5278 var cleanup_build_dir: ?fs.Dir = null;
...@@ -5399,6 +5407,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -5399,6 +5407,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
5399 .global = config,5407 .global = config,
5400 .parent = root_mod,5408 .parent = root_mod,
5401 .builtin_mod = builtin_mod,5409 .builtin_mod = builtin_mod,
5410 .builtin_modules = null, // `builtin_mod` is specified
5402 });5411 });
5403 const hash_cloned = try arena.dupe(u8, &hash);5412 const hash_cloned = try arena.dupe(u8, &hash);
5404 deps_mod.deps.putAssumeCapacityNoClobber(hash_cloned, m);5413 deps_mod.deps.putAssumeCapacityNoClobber(hash_cloned, m);
...@@ -5648,6 +5657,7 @@ fn jitCmd(...@@ -5648,6 +5657,7 @@ fn jitCmd(
5648 .global = config,5657 .global = config,
5649 .parent = null,5658 .parent = null,
5650 .builtin_mod = null,5659 .builtin_mod = null,
5660 .builtin_modules = null, // all modules will inherit this one's builtin
5651 });5661 });
56525662
5653 if (options.depend_on_aro) {5663 if (options.depend_on_aro) {
...@@ -5670,6 +5680,7 @@ fn jitCmd(...@@ -5670,6 +5680,7 @@ fn jitCmd(
5670 .global = config,5680 .global = config,
5671 .parent = null,5681 .parent = null,
5672 .builtin_mod = root_mod.getBuiltinDependency(),5682 .builtin_mod = root_mod.getBuiltinDependency(),
5683 .builtin_modules = null, // `builtin_mod` is specified
5673 });5684 });
5674 try root_mod.deps.put(arena, "aro", aro_mod);5685 try root_mod.deps.put(arena, "aro", aro_mod);
5675 }5686 }
...@@ -7216,10 +7227,11 @@ fn createDependenciesModule(...@@ -7216,10 +7227,11 @@ fn createDependenciesModule(
7216 },7227 },
7217 .fully_qualified_name = "root.@dependencies",7228 .fully_qualified_name = "root.@dependencies",
7218 .parent = main_mod,7229 .parent = main_mod,
7219 .builtin_mod = builtin_mod,
7220 .cc_argv = &.{},7230 .cc_argv = &.{},
7221 .inherited = .{},7231 .inherited = .{},
7222 .global = global_options,7232 .global = global_options,
7233 .builtin_mod = builtin_mod,
7234 .builtin_modules = null, // `builtin_mod` is specified
7223 });7235 });
7224 try main_mod.deps.put(arena, "@dependencies", deps_mod);7236 try main_mod.deps.put(arena, "@dependencies", deps_mod);
7225 return deps_mod;7237 return deps_mod;
src/musl.zig+1
...@@ -250,6 +250,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr...@@ -250,6 +250,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr
250 .cc_argv = cc_argv,250 .cc_argv = cc_argv,
251 .parent = null,251 .parent = null,
252 .builtin_mod = null,252 .builtin_mod = null,
253 .builtin_modules = null, // there is only one module in this compilation
253 });254 });
254255
255 const sub_compilation = try Compilation.create(comp.gpa, arena, .{256 const sub_compilation = try Compilation.create(comp.gpa, arena, .{
src/print_zir.zig+102-5
...@@ -282,7 +282,6 @@ const Writer = struct {...@@ -282,7 +282,6 @@ const Writer = struct {
282282
283 .ref,283 .ref,
284 .ret_implicit,284 .ret_implicit,
285 .closure_capture,
286 .validate_ref_ty,285 .validate_ref_ty,
287 => try self.writeUnTok(stream, inst),286 => try self.writeUnTok(stream, inst),
288287
...@@ -510,8 +509,6 @@ const Writer = struct {...@@ -510,8 +509,6 @@ const Writer = struct {
510509
511 .dbg_stmt => try self.writeDbgStmt(stream, inst),510 .dbg_stmt => try self.writeDbgStmt(stream, inst),
512511
513 .closure_get => try self.writeInstNode(stream, inst),
514
515 .@"defer" => try self.writeDefer(stream, inst),512 .@"defer" => try self.writeDefer(stream, inst),
516 .defer_err_code => try self.writeDeferErrCode(stream, inst),513 .defer_err_code => try self.writeDeferErrCode(stream, inst),
517514
...@@ -611,6 +608,7 @@ const Writer = struct {...@@ -611,6 +608,7 @@ const Writer = struct {
611 .ptr_cast_no_dest => try self.writePtrCastNoDest(stream, extended),608 .ptr_cast_no_dest => try self.writePtrCastNoDest(stream, extended),
612609
613 .restore_err_ret_index => try self.writeRestoreErrRetIndex(stream, extended),610 .restore_err_ret_index => try self.writeRestoreErrRetIndex(stream, extended),
611 .closure_get => try self.writeClosureGet(stream, extended),
614 }612 }
615 }613 }
616614
...@@ -1401,6 +1399,12 @@ const Writer = struct {...@@ -1401,6 +1399,12 @@ const Writer = struct {
14011399
1402 var extra_index: usize = extra.end;1400 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
1404 const fields_len = if (small.has_fields_len) blk: {1408 const fields_len = if (small.has_fields_len) blk: {
1405 const fields_len = self.code.extra[extra_index];1409 const fields_len = self.code.extra[extra_index];
1406 extra_index += 1;1410 extra_index += 1;
...@@ -1419,12 +1423,26 @@ const Writer = struct {...@@ -1419,12 +1423,26 @@ const Writer = struct {
14191423
1420 try stream.print("{s}, ", .{@tagName(small.name_strategy)});1424 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) {
1423 const backing_int_body_len = self.code.extra[extra_index];1441 const backing_int_body_len = self.code.extra[extra_index];
1424 extra_index += 1;1442 extra_index += 1;
1425 try stream.writeAll("Packed(");1443 try stream.writeAll("Packed(");
1426 if (backing_int_body_len == 0) {1444 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]);
1428 extra_index += 1;1446 extra_index += 1;
1429 try self.writeInstRef(stream, backing_int_ref);1447 try self.writeInstRef(stream, backing_int_ref);
1430 } else {1448 } else {
...@@ -1601,6 +1619,12 @@ const Writer = struct {...@@ -1601,6 +1619,12 @@ const Writer = struct {
1601 break :blk tag_type_ref;1619 break :blk tag_type_ref;
1602 } else .none;1620 } 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
1604 const body_len = if (small.has_body_len) blk: {1628 const body_len = if (small.has_body_len) blk: {
1605 const body_len = self.code.extra[extra_index];1629 const body_len = self.code.extra[extra_index];
1606 extra_index += 1;1630 extra_index += 1;
...@@ -1624,6 +1648,20 @@ const Writer = struct {...@@ -1624,6 +1648,20 @@ const Writer = struct {
1624 });1648 });
1625 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);1649 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
1627 if (decls_len == 0) {1665 if (decls_len == 0) {
1628 try stream.writeAll("{}");1666 try stream.writeAll("{}");
1629 } else {1667 } else {
...@@ -1748,6 +1786,12 @@ const Writer = struct {...@@ -1748,6 +1786,12 @@ const Writer = struct {
1748 break :blk tag_type_ref;1786 break :blk tag_type_ref;
1749 } else .none;1787 } 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
1751 const body_len = if (small.has_body_len) blk: {1795 const body_len = if (small.has_body_len) blk: {
1752 const body_len = self.code.extra[extra_index];1796 const body_len = self.code.extra[extra_index];
1753 extra_index += 1;1797 extra_index += 1;
...@@ -1769,6 +1813,20 @@ const Writer = struct {...@@ -1769,6 +1813,20 @@ const Writer = struct {
1769 try stream.print("{s}, ", .{@tagName(small.name_strategy)});1813 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
1770 try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive);1814 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
1772 if (decls_len == 0) {1830 if (decls_len == 0) {
1773 try stream.writeAll("{}, ");1831 try stream.writeAll("{}, ");
1774 } else {1832 } else {
...@@ -1854,6 +1912,12 @@ const Writer = struct {...@@ -1854,6 +1912,12 @@ const Writer = struct {
1854 const extra = self.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);1912 const extra = self.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
1855 var extra_index: usize = extra.end;1913 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
1857 const decls_len = if (small.has_decls_len) blk: {1921 const decls_len = if (small.has_decls_len) blk: {
1858 const decls_len = self.code.extra[extra_index];1922 const decls_len = self.code.extra[extra_index];
1859 extra_index += 1;1923 extra_index += 1;
...@@ -1862,6 +1926,20 @@ const Writer = struct {...@@ -1862,6 +1926,20 @@ const Writer = struct {
18621926
1863 try stream.print("{s}, ", .{@tagName(small.name_strategy)});1927 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
1865 if (decls_len == 0) {1943 if (decls_len == 0) {
1866 try stream.writeAll("{})");1944 try stream.writeAll("{})");
1867 } else {1945 } else {
...@@ -2706,6 +2784,12 @@ const Writer = struct {...@@ -2706,6 +2784,12 @@ const Writer = struct {
2706 try self.writeSrc(stream, inst_data.src());2784 try self.writeSrc(stream, inst_data.src());
2707 }2785 }
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
2709 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {2793 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {
2710 if (ref == .none) {2794 if (ref == .none) {
2711 return stream.writeAll(".none");2795 return stream.writeAll(".none");
...@@ -2722,6 +2806,19 @@ const Writer = struct {...@@ -2722,6 +2806,19 @@ const Writer = struct {
2722 return stream.print("%{d}", .{@intFromEnum(inst)});2806 return stream.print("%{d}", .{@intFromEnum(inst)});
2723 }2807 }
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
2725 fn writeOptionalInstRef(2822 fn writeOptionalInstRef(
2726 self: *Writer,2823 self: *Writer,
2727 stream: anytype,2824 stream: anytype,
src/type.zig+204-178
...@@ -320,11 +320,12 @@ pub const Type = struct {...@@ -320,11 +320,12 @@ pub const Type = struct {
320320
321 .generic_poison => unreachable,321 .generic_poison => unreachable,
322 },322 },
323 .struct_type => |struct_type| {323 .struct_type => {
324 const struct_type = ip.loadStructType(ty.toIntern());
324 if (struct_type.decl.unwrap()) |decl_index| {325 if (struct_type.decl.unwrap()) |decl_index| {
325 const decl = mod.declPtr(decl_index);326 const decl = mod.declPtr(decl_index);
326 try decl.renderFullyQualifiedName(mod, writer);327 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| {
328 const namespace = mod.namespacePtr(namespace_index);329 const namespace = mod.namespacePtr(namespace_index);
329 try namespace.renderFullyQualifiedName(mod, .empty, writer);330 try namespace.renderFullyQualifiedName(mod, .empty, writer);
330 } else {331 } else {
...@@ -354,16 +355,16 @@ pub const Type = struct {...@@ -354,16 +355,16 @@ pub const Type = struct {
354 try writer.writeAll("}");355 try writer.writeAll("}");
355 },356 },
356357
357 .union_type => |union_type| {358 .union_type => {
358 const decl = mod.declPtr(union_type.decl);359 const decl = mod.declPtr(ip.loadUnionType(ty.toIntern()).decl);
359 try decl.renderFullyQualifiedName(mod, writer);360 try decl.renderFullyQualifiedName(mod, writer);
360 },361 },
361 .opaque_type => |opaque_type| {362 .opaque_type => {
362 const decl = mod.declPtr(opaque_type.decl);363 const decl = mod.declPtr(ip.loadOpaqueType(ty.toIntern()).decl);
363 try decl.renderFullyQualifiedName(mod, writer);364 try decl.renderFullyQualifiedName(mod, writer);
364 },365 },
365 .enum_type => |enum_type| {366 .enum_type => {
366 const decl = mod.declPtr(enum_type.decl);367 const decl = mod.declPtr(ip.loadEnumType(ty.toIntern()).decl);
367 try decl.renderFullyQualifiedName(mod, writer);368 try decl.renderFullyQualifiedName(mod, writer);
368 },369 },
369 .func_type => |fn_info| {370 .func_type => |fn_info| {
...@@ -573,7 +574,8 @@ pub const Type = struct {...@@ -573,7 +574,8 @@ pub const Type = struct {
573574
574 .generic_poison => unreachable,575 .generic_poison => unreachable,
575 },576 },
576 .struct_type => |struct_type| {577 .struct_type => {
578 const struct_type = ip.loadStructType(ty.toIntern());
577 if (struct_type.assumeRuntimeBitsIfFieldTypesWip(ip)) {579 if (struct_type.assumeRuntimeBitsIfFieldTypesWip(ip)) {
578 // In this case, we guess that hasRuntimeBits() for this type is true,580 // In this case, we guess that hasRuntimeBits() for this type is true,
579 // and then later if our guess was incorrect, we emit a compile error.581 // and then later if our guess was incorrect, we emit a compile error.
...@@ -601,7 +603,8 @@ pub const Type = struct {...@@ -601,7 +603,8 @@ pub const Type = struct {
601 return false;603 return false;
602 },604 },
603605
604 .union_type => |union_type| {606 .union_type => {
607 const union_type = ip.loadUnionType(ty.toIntern());
605 switch (union_type.flagsPtr(ip).runtime_tag) {608 switch (union_type.flagsPtr(ip).runtime_tag) {
606 .none => {609 .none => {
607 if (union_type.flagsPtr(ip).status == .field_types_wip) {610 if (union_type.flagsPtr(ip).status == .field_types_wip) {
...@@ -628,9 +631,8 @@ pub const Type = struct {...@@ -628,9 +631,8 @@ pub const Type = struct {
628 .lazy => if (!union_type.flagsPtr(ip).status.haveFieldTypes())631 .lazy => if (!union_type.flagsPtr(ip).status.haveFieldTypes())
629 return error.NeedLazy,632 return error.NeedLazy,
630 }633 }
631 const union_obj = ip.loadUnionType(union_type);634 for (0..union_type.field_types.len) |field_index| {
632 for (0..union_obj.field_types.len) |field_index| {635 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
633 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
634 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))636 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
635 return true;637 return true;
636 } else {638 } else {
...@@ -639,7 +641,7 @@ pub const Type = struct {...@@ -639,7 +641,7 @@ pub const Type = struct {
639 },641 },
640642
641 .opaque_type => true,643 .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
644 // values, not types646 // values, not types
645 .undef,647 .undef,
...@@ -736,15 +738,19 @@ pub const Type = struct {...@@ -736,15 +738,19 @@ pub const Type = struct {
736 .generic_poison,738 .generic_poison,
737 => false,739 => false,
738 },740 },
739 .struct_type => |struct_type| {741 .struct_type => {
742 const struct_type = ip.loadStructType(ty.toIntern());
740 // Struct with no fields have a well-defined layout of no bits.743 // Struct with no fields have a well-defined layout of no bits.
741 return struct_type.layout != .Auto or struct_type.field_types.len == 0;744 return struct_type.layout != .Auto or struct_type.field_types.len == 0;
742 },745 },
743 .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) {746 .union_type => {
744 .none, .safety => union_type.flagsPtr(ip).layout != .Auto,747 const union_type = ip.loadUnionType(ty.toIntern());
745 .tagged => false,748 return switch (union_type.flagsPtr(ip).runtime_tag) {
749 .none, .safety => union_type.flagsPtr(ip).layout != .Auto,
750 .tagged => false,
751 };
746 },752 },
747 .enum_type => |enum_type| switch (enum_type.tag_mode) {753 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
748 .auto => false,754 .auto => false,
749 .explicit, .nonexhaustive => true,755 .explicit, .nonexhaustive => true,
750 },756 },
...@@ -1019,7 +1025,8 @@ pub const Type = struct {...@@ -1019,7 +1025,8 @@ pub const Type = struct {
1019 .noreturn => unreachable,1025 .noreturn => unreachable,
1020 .generic_poison => unreachable,1026 .generic_poison => unreachable,
1021 },1027 },
1022 .struct_type => |struct_type| {1028 .struct_type => {
1029 const struct_type = ip.loadStructType(ty.toIntern());
1023 if (struct_type.layout == .Packed) {1030 if (struct_type.layout == .Packed) {
1024 switch (strat) {1031 switch (strat) {
1025 .sema => |sema| try sema.resolveTypeLayout(ty),1032 .sema => |sema| try sema.resolveTypeLayout(ty),
...@@ -1066,7 +1073,8 @@ pub const Type = struct {...@@ -1066,7 +1073,8 @@ pub const Type = struct {
1066 }1073 }
1067 return .{ .scalar = big_align };1074 return .{ .scalar = big_align };
1068 },1075 },
1069 .union_type => |union_type| {1076 .union_type => {
1077 const union_type = ip.loadUnionType(ty.toIntern());
1070 const flags = union_type.flagsPtr(ip).*;1078 const flags = union_type.flagsPtr(ip).*;
1071 if (flags.alignment != .none) return .{ .scalar = flags.alignment };1079 if (flags.alignment != .none) return .{ .scalar = flags.alignment };
10721080
...@@ -1082,8 +1090,8 @@ pub const Type = struct {...@@ -1082,8 +1090,8 @@ pub const Type = struct {
1082 return .{ .scalar = union_type.flagsPtr(ip).alignment };1090 return .{ .scalar = union_type.flagsPtr(ip).alignment };
1083 },1091 },
1084 .opaque_type => return .{ .scalar = .@"1" },1092 .opaque_type => return .{ .scalar = .@"1" },
1085 .enum_type => |enum_type| return .{1093 .enum_type => return .{
1086 .scalar = Type.fromInterned(enum_type.tag_ty).abiAlignment(mod),1094 .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiAlignment(mod),
1087 },1095 },
10881096
1089 // values, not types1097 // values, not types
...@@ -1394,7 +1402,8 @@ pub const Type = struct {...@@ -1394,7 +1402,8 @@ pub const Type = struct {
1394 .noreturn => unreachable,1402 .noreturn => unreachable,
1395 .generic_poison => unreachable,1403 .generic_poison => unreachable,
1396 },1404 },
1397 .struct_type => |struct_type| {1405 .struct_type => {
1406 const struct_type = ip.loadStructType(ty.toIntern());
1398 switch (strat) {1407 switch (strat) {
1399 .sema => |sema| try sema.resolveTypeLayout(ty),1408 .sema => |sema| try sema.resolveTypeLayout(ty),
1400 .lazy => switch (struct_type.layout) {1409 .lazy => switch (struct_type.layout) {
...@@ -1439,7 +1448,8 @@ pub const Type = struct {...@@ -1439,7 +1448,8 @@ pub const Type = struct {
1439 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };1448 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };
1440 },1449 },
14411450
1442 .union_type => |union_type| {1451 .union_type => {
1452 const union_type = ip.loadUnionType(ty.toIntern());
1443 switch (strat) {1453 switch (strat) {
1444 .sema => |sema| try sema.resolveTypeLayout(ty),1454 .sema => |sema| try sema.resolveTypeLayout(ty),
1445 .lazy => if (!union_type.flagsPtr(ip).status.haveLayout()) return .{1455 .lazy => if (!union_type.flagsPtr(ip).status.haveLayout()) return .{
...@@ -1455,7 +1465,7 @@ pub const Type = struct {...@@ -1455,7 +1465,7 @@ pub const Type = struct {
1455 return .{ .scalar = union_type.size(ip).* };1465 return .{ .scalar = union_type.size(ip).* };
1456 },1466 },
1457 .opaque_type => unreachable, // no size available1467 .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
1460 // values, not types1470 // values, not types
1461 .undef,1471 .undef,
...@@ -1644,7 +1654,8 @@ pub const Type = struct {...@@ -1644,7 +1654,8 @@ pub const Type = struct {
1644 .extern_options => unreachable,1654 .extern_options => unreachable,
1645 .type_info => unreachable,1655 .type_info => unreachable,
1646 },1656 },
1647 .struct_type => |struct_type| {1657 .struct_type => {
1658 const struct_type = ip.loadStructType(ty.toIntern());
1648 const is_packed = struct_type.layout == .Packed;1659 const is_packed = struct_type.layout == .Packed;
1649 if (opt_sema) |sema| {1660 if (opt_sema) |sema| {
1650 try sema.resolveTypeFields(ty);1661 try sema.resolveTypeFields(ty);
...@@ -1661,7 +1672,8 @@ pub const Type = struct {...@@ -1661,7 +1672,8 @@ pub const Type = struct {
1661 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;1672 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1662 },1673 },
16631674
1664 .union_type => |union_type| {1675 .union_type => {
1676 const union_type = ip.loadUnionType(ty.toIntern());
1665 const is_packed = ty.containerLayout(mod) == .Packed;1677 const is_packed = ty.containerLayout(mod) == .Packed;
1666 if (opt_sema) |sema| {1678 if (opt_sema) |sema| {
1667 try sema.resolveTypeFields(ty);1679 try sema.resolveTypeFields(ty);
...@@ -1670,19 +1682,18 @@ pub const Type = struct {...@@ -1670,19 +1682,18 @@ pub const Type = struct {
1670 if (!is_packed) {1682 if (!is_packed) {
1671 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;1683 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1672 }1684 }
1673 const union_obj = ip.loadUnionType(union_type);1685 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
1674 assert(union_obj.flagsPtr(ip).status.haveFieldTypes());
16751686
1676 var size: u64 = 0;1687 var size: u64 = 0;
1677 for (0..union_obj.field_types.len) |field_index| {1688 for (0..union_type.field_types.len) |field_index| {
1678 const field_ty = union_obj.field_types.get(ip)[field_index];1689 const field_ty = union_type.field_types.get(ip)[field_index];
1679 size = @max(size, try bitSizeAdvanced(Type.fromInterned(field_ty), mod, opt_sema));1690 size = @max(size, try bitSizeAdvanced(Type.fromInterned(field_ty), mod, opt_sema));
1680 }1691 }
16811692
1682 return size;1693 return size;
1683 },1694 },
1684 .opaque_type => unreachable,1695 .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
1687 // values, not types1698 // values, not types
1688 .undef,1699 .undef,
...@@ -1713,8 +1724,8 @@ pub const Type = struct {...@@ -1713,8 +1724,8 @@ pub const Type = struct {
1713 pub fn layoutIsResolved(ty: Type, mod: *Module) bool {1724 pub fn layoutIsResolved(ty: Type, mod: *Module) bool {
1714 const ip = &mod.intern_pool;1725 const ip = &mod.intern_pool;
1715 return switch (ip.indexToKey(ty.toIntern())) {1726 return switch (ip.indexToKey(ty.toIntern())) {
1716 .struct_type => |struct_type| struct_type.haveLayout(ip),1727 .struct_type => ip.loadStructType(ty.toIntern()).haveLayout(ip),
1717 .union_type => |union_type| union_type.haveLayout(ip),1728 .union_type => ip.loadUnionType(ty.toIntern()).haveLayout(ip),
1718 .array_type => |array_type| {1729 .array_type => |array_type| {
1719 if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true;1730 if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true;
1720 return Type.fromInterned(array_type.child).layoutIsResolved(mod);1731 return Type.fromInterned(array_type.child).layoutIsResolved(mod);
...@@ -1914,16 +1925,18 @@ pub const Type = struct {...@@ -1914,16 +1925,18 @@ pub const Type = struct {
1914 /// Otherwise, returns `null`.1925 /// Otherwise, returns `null`.
1915 pub fn unionTagType(ty: Type, mod: *Module) ?Type {1926 pub fn unionTagType(ty: Type, mod: *Module) ?Type {
1916 const ip = &mod.intern_pool;1927 const ip = &mod.intern_pool;
1917 return switch (ip.indexToKey(ty.toIntern())) {1928 switch (ip.indexToKey(ty.toIntern())) {
1918 .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) {1929 .union_type => {},
1919 .tagged => {1930 else => return null,
1920 assert(union_type.flagsPtr(ip).status.haveFieldTypes());1931 }
1921 return Type.fromInterned(union_type.enum_tag_ty);1932 const union_type = ip.loadUnionType(ty.toIntern());
1922 },1933 switch (union_type.flagsPtr(ip).runtime_tag) {
1923 else => null,1934 .tagged => {
1935 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
1936 return Type.fromInterned(union_type.enum_tag_ty);
1924 },1937 },
1925 else => null,1938 else => return null,
1926 };1939 }
1927 }1940 }
19281941
1929 /// Same as `unionTagType` but includes safety tag.1942 /// Same as `unionTagType` but includes safety tag.
...@@ -1931,7 +1944,8 @@ pub const Type = struct {...@@ -1931,7 +1944,8 @@ pub const Type = struct {
1931 pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type {1944 pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type {
1932 const ip = &mod.intern_pool;1945 const ip = &mod.intern_pool;
1933 return switch (ip.indexToKey(ty.toIntern())) {1946 return switch (ip.indexToKey(ty.toIntern())) {
1934 .union_type => |union_type| {1947 .union_type => {
1948 const union_type = ip.loadUnionType(ty.toIntern());
1935 if (!union_type.hasTag(ip)) return null;1949 if (!union_type.hasTag(ip)) return null;
1936 assert(union_type.haveFieldTypes(ip));1950 assert(union_type.haveFieldTypes(ip));
1937 return Type.fromInterned(union_type.enum_tag_ty);1951 return Type.fromInterned(union_type.enum_tag_ty);
...@@ -1981,17 +1995,16 @@ pub const Type = struct {...@@ -1981,17 +1995,16 @@ pub const Type = struct {
19811995
1982 pub fn unionGetLayout(ty: Type, mod: *Module) Module.UnionLayout {1996 pub fn unionGetLayout(ty: Type, mod: *Module) Module.UnionLayout {
1983 const ip = &mod.intern_pool;1997 const ip = &mod.intern_pool;
1984 const union_type = ip.indexToKey(ty.toIntern()).union_type;1998 const union_obj = ip.loadUnionType(ty.toIntern());
1985 const union_obj = ip.loadUnionType(union_type);
1986 return mod.getUnionLayout(union_obj);1999 return mod.getUnionLayout(union_obj);
1987 }2000 }
19882001
1989 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {2002 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
1990 const ip = &mod.intern_pool;2003 const ip = &mod.intern_pool;
1991 return switch (ip.indexToKey(ty.toIntern())) {2004 return switch (ip.indexToKey(ty.toIntern())) {
1992 .struct_type => |struct_type| struct_type.layout,2005 .struct_type => ip.loadStructType(ty.toIntern()).layout,
1993 .anon_struct_type => .Auto,2006 .anon_struct_type => .Auto,
1994 .union_type => |union_type| union_type.flagsPtr(ip).layout,2007 .union_type => ip.loadUnionType(ty.toIntern()).flagsPtr(ip).layout,
1995 else => unreachable,2008 else => unreachable,
1996 };2009 };
1997 }2010 }
...@@ -2095,22 +2108,15 @@ pub const Type = struct {...@@ -2095,22 +2108,15 @@ pub const Type = struct {
20952108
2096 /// Asserts the type is an array or vector or struct.2109 /// Asserts the type is an array or vector or struct.
2097 pub fn arrayLen(ty: Type, mod: *const Module) u64 {2110 pub fn arrayLen(ty: Type, mod: *const Module) u64 {
2098 return arrayLenIp(ty, &mod.intern_pool);2111 return ty.arrayLenIp(&mod.intern_pool);
2099 }2112 }
21002113
2101 pub fn arrayLenIp(ty: Type, ip: *const InternPool) u64 {2114 pub fn arrayLenIp(ty: Type, ip: *const InternPool) u64 {
2102 return switch (ip.indexToKey(ty.toIntern())) {2115 return ip.aggregateTypeLen(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 };
2110 }2116 }
21112117
2112 pub fn arrayLenIncludingSentinel(ty: Type, mod: *const Module) u64 {2118 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());
2114 }2120 }
21152121
2116 pub fn vectorLen(ty: Type, mod: *const Module) u32 {2122 pub fn vectorLen(ty: Type, mod: *const Module) u32 {
...@@ -2199,8 +2205,8 @@ pub const Type = struct {...@@ -2199,8 +2205,8 @@ pub const Type = struct {
2199 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) },2205 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) },
2200 else => switch (ip.indexToKey(ty.toIntern())) {2206 else => switch (ip.indexToKey(ty.toIntern())) {
2201 .int_type => |int_type| return int_type,2207 .int_type => |int_type| return int_type,
2202 .struct_type => |t| ty = Type.fromInterned(t.backingIntType(ip).*),2208 .struct_type => ty = Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntType(ip).*),
2203 .enum_type => |enum_type| ty = Type.fromInterned(enum_type.tag_ty),2209 .enum_type => ty = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),
2204 .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child),2210 .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child),
22052211
2206 .error_set_type, .inferred_error_set_type => {2212 .error_set_type, .inferred_error_set_type => {
...@@ -2463,7 +2469,8 @@ pub const Type = struct {...@@ -2463,7 +2469,8 @@ pub const Type = struct {
24632469
2464 .generic_poison => unreachable,2470 .generic_poison => unreachable,
2465 },2471 },
2466 .struct_type => |struct_type| {2472 .struct_type => {
2473 const struct_type = ip.loadStructType(ty.toIntern());
2467 assert(struct_type.haveFieldTypes(ip));2474 assert(struct_type.haveFieldTypes(ip));
2468 if (struct_type.knownNonOpv(ip))2475 if (struct_type.knownNonOpv(ip))
2469 return null;2476 return null;
...@@ -2505,11 +2512,11 @@ pub const Type = struct {...@@ -2505,11 +2512,11 @@ pub const Type = struct {
2505 } })));2512 } })));
2506 },2513 },
25072514
2508 .union_type => |union_type| {2515 .union_type => {
2509 const union_obj = ip.loadUnionType(union_type);2516 const union_obj = ip.loadUnionType(ty.toIntern());
2510 const tag_val = (try Type.fromInterned(union_obj.enum_tag_ty).onePossibleValue(mod)) orelse2517 const tag_val = (try Type.fromInterned(union_obj.enum_tag_ty).onePossibleValue(mod)) orelse
2511 return null;2518 return null;
2512 if (union_obj.field_names.len == 0) {2519 if (union_obj.field_types.len == 0) {
2513 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });2520 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
2514 return Value.fromInterned(only);2521 return Value.fromInterned(only);
2515 }2522 }
...@@ -2524,45 +2531,48 @@ pub const Type = struct {...@@ -2524,45 +2531,48 @@ pub const Type = struct {
2524 return Value.fromInterned(only);2531 return Value.fromInterned(only);
2525 },2532 },
2526 .opaque_type => return null,2533 .opaque_type => return null,
2527 .enum_type => |enum_type| switch (enum_type.tag_mode) {2534 .enum_type => {
2528 .nonexhaustive => {2535 const enum_type = ip.loadEnumType(ty.toIntern());
2529 if (enum_type.tag_ty == .comptime_int_type) return null;2536 switch (enum_type.tag_mode) {
25302537 .nonexhaustive => {
2531 if (try Type.fromInterned(enum_type.tag_ty).onePossibleValue(mod)) |int_opv| {2538 if (enum_type.tag_ty == .comptime_int_type) return null;
2532 const only = try mod.intern(.{ .enum_tag = .{2539
2533 .ty = ty.toIntern(),2540 if (try Type.fromInterned(enum_type.tag_ty).onePossibleValue(mod)) |int_opv| {
2534 .int = int_opv.toIntern(),2541 const only = try mod.intern(.{ .enum_tag = .{
2535 } });2542 .ty = ty.toIntern(),
2536 return Value.fromInterned(only);2543 .int = int_opv.toIntern(),
2537 }2544 } });
2545 return Value.fromInterned(only);
2546 }
25382547
2539 return null;2548 return null;
2540 },2549 },
2541 .auto, .explicit => {2550 .auto, .explicit => {
2542 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;2551 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;
25432552
2544 switch (enum_type.names.len) {2553 switch (enum_type.names.len) {
2545 0 => {2554 0 => {
2546 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });2555 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 } });
2558 return Value.fromInterned(only);2556 return Value.fromInterned(only);
2559 } else {2557 },
2560 return Value.fromInterned(enum_type.values.get(ip)[0]);2558 1 => {
2561 }2559 if (enum_type.values.len == 0) {
2562 },2560 const only = try mod.intern(.{ .enum_tag = .{
2563 else => return null,2561 .ty = ty.toIntern(),
2564 }2562 .int = try mod.intern(.{ .int = .{
2565 },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 }
2566 },2576 },
25672577
2568 // values, not types2578 // values, not types
...@@ -2676,7 +2686,8 @@ pub const Type = struct {...@@ -2676,7 +2686,8 @@ pub const Type = struct {
2676 .type_info,2686 .type_info,
2677 => true,2687 => true,
2678 },2688 },
2679 .struct_type => |struct_type| {2689 .struct_type => {
2690 const struct_type = ip.loadStructType(ty.toIntern());
2680 // packed structs cannot be comptime-only because they have a well-defined2691 // packed structs cannot be comptime-only because they have a well-defined
2681 // memory layout and every field has a well-defined bit pattern.2692 // memory layout and every field has a well-defined bit pattern.
2682 if (struct_type.layout == .Packed)2693 if (struct_type.layout == .Packed)
...@@ -2726,38 +2737,40 @@ pub const Type = struct {...@@ -2726,38 +2737,40 @@ pub const Type = struct {
2726 return false;2737 return false;
2727 },2738 },
27282739
2729 .union_type => |union_type| switch (union_type.flagsPtr(ip).requires_comptime) {2740 .union_type => {
2730 .no, .wip => false,2741 const union_type = ip.loadUnionType(ty.toIntern());
2731 .yes => true,2742 switch (union_type.flagsPtr(ip).requires_comptime) {
2732 .unknown => {2743 .no, .wip => return false,
2733 // The type is not resolved; assert that we have a Sema.2744 .yes => return true,
2734 const sema = opt_sema.?;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)2749 if (union_type.flagsPtr(ip).status == .field_types_wip)
2737 return false;2750 return false;
27382751
2739 union_type.flagsPtr(ip).requires_comptime = .wip;2752 union_type.flagsPtr(ip).requires_comptime = .wip;
2740 errdefer union_type.flagsPtr(ip).requires_comptime = .unknown;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);2757 for (0..union_type.field_types.len) |field_idx| {
2745 for (0..union_obj.field_types.len) |field_idx| {2758 const field_ty = union_type.field_types.get(ip)[field_idx];
2746 const field_ty = union_obj.field_types.get(ip)[field_idx];2759 if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) {
2747 if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) {2760 union_type.flagsPtr(ip).requires_comptime = .yes;
2748 union_obj.flagsPtr(ip).requires_comptime = .yes;2761 return true;
2749 return true;2762 }
2750 }2763 }
2751 }
27522764
2753 union_obj.flagsPtr(ip).requires_comptime = .no;2765 union_type.flagsPtr(ip).requires_comptime = .no;
2754 return false;2766 return false;
2755 },2767 },
2768 }
2756 },2769 },
27572770
2758 .opaque_type => false,2771 .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
2762 // values, not types2775 // values, not types
2763 .undef,2776 .undef,
...@@ -2830,11 +2843,12 @@ pub const Type = struct {...@@ -2830,11 +2843,12 @@ pub const Type = struct {
28302843
2831 /// Returns null if the type has no namespace.2844 /// Returns null if the type has no namespace.
2832 pub fn getNamespaceIndex(ty: Type, mod: *Module) InternPool.OptionalNamespaceIndex {2845 pub fn getNamespaceIndex(ty: Type, mod: *Module) InternPool.OptionalNamespaceIndex {
2833 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {2846 const ip = &mod.intern_pool;
2834 .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),2847 return switch (ip.indexToKey(ty.toIntern())) {
2835 .struct_type => |struct_type| struct_type.namespace,2848 .opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace,
2836 .union_type => |union_type| union_type.namespace.toOptional(),2849 .struct_type => ip.loadStructType(ty.toIntern()).namespace,
2837 .enum_type => |enum_type| enum_type.namespace,2850 .union_type => ip.loadUnionType(ty.toIntern()).namespace,
2851 .enum_type => ip.loadEnumType(ty.toIntern()).namespace,
28382852
2839 else => .none,2853 else => .none,
2840 };2854 };
...@@ -2920,16 +2934,18 @@ pub const Type = struct {...@@ -2920,16 +2934,18 @@ pub const Type = struct {
29202934
2921 /// Asserts the type is an enum or a union.2935 /// Asserts the type is an enum or a union.
2922 pub fn intTagType(ty: Type, mod: *Module) Type {2936 pub fn intTagType(ty: Type, mod: *Module) Type {
2923 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {2937 const ip = &mod.intern_pool;
2924 .union_type => |union_type| Type.fromInterned(union_type.enum_tag_ty).intTagType(mod),2938 return switch (ip.indexToKey(ty.toIntern())) {
2925 .enum_type => |enum_type| Type.fromInterned(enum_type.tag_ty),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),
2926 else => unreachable,2941 else => unreachable,
2927 };2942 };
2928 }2943 }
29292944
2930 pub fn isNonexhaustiveEnum(ty: Type, mod: *Module) bool {2945 pub fn isNonexhaustiveEnum(ty: Type, mod: *Module) bool {
2931 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {2946 const ip = &mod.intern_pool;
2932 .enum_type => |enum_type| switch (enum_type.tag_mode) {2947 return switch (ip.indexToKey(ty.toIntern())) {
2948 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
2933 .nonexhaustive => true,2949 .nonexhaustive => true,
2934 .auto, .explicit => false,2950 .auto, .explicit => false,
2935 },2951 },
...@@ -2953,21 +2969,21 @@ pub const Type = struct {...@@ -2953,21 +2969,21 @@ pub const Type = struct {
2953 }2969 }
29542970
2955 pub fn enumFields(ty: Type, mod: *Module) InternPool.NullTerminatedString.Slice {2971 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;
2957 }2973 }
29582974
2959 pub fn enumFieldCount(ty: Type, mod: *Module) usize {2975 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;
2961 }2977 }
29622978
2963 pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString {2979 pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString {
2964 const ip = &mod.intern_pool;2980 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];
2966 }2982 }
29672983
2968 pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, mod: *Module) ?u32 {2984 pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, mod: *Module) ?u32 {
2969 const ip = &mod.intern_pool;2985 const ip = &mod.intern_pool;
2970 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;2986 const enum_type = ip.loadEnumType(ty.toIntern());
2971 return enum_type.nameIndex(ip, field_name);2987 return enum_type.nameIndex(ip, field_name);
2972 }2988 }
29732989
...@@ -2976,7 +2992,7 @@ pub const Type = struct {...@@ -2976,7 +2992,7 @@ pub const Type = struct {
2976 /// declaration order, or `null` if `enum_tag` does not match any field.2992 /// declaration order, or `null` if `enum_tag` does not match any field.
2977 pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {2993 pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
2978 const ip = &mod.intern_pool;2994 const ip = &mod.intern_pool;
2979 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;2995 const enum_type = ip.loadEnumType(ty.toIntern());
2980 const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) {2996 const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) {
2981 .int => enum_tag.toIntern(),2997 .int => enum_tag.toIntern(),
2982 .enum_tag => |info| info.int,2998 .enum_tag => |info| info.int,
...@@ -2990,7 +3006,7 @@ pub const Type = struct {...@@ -2990,7 +3006,7 @@ pub const Type = struct {
2990 pub fn structFieldName(ty: Type, field_index: u32, mod: *Module) InternPool.OptionalNullTerminatedString {3006 pub fn structFieldName(ty: Type, field_index: u32, mod: *Module) InternPool.OptionalNullTerminatedString {
2991 const ip = &mod.intern_pool;3007 const ip = &mod.intern_pool;
2992 return switch (ip.indexToKey(ty.toIntern())) {3008 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),
2994 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, field_index),3010 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, field_index),
2995 else => unreachable,3011 else => unreachable,
2996 };3012 };
...@@ -3010,7 +3026,7 @@ pub const Type = struct {...@@ -3010,7 +3026,7 @@ pub const Type = struct {
3010 pub fn structFieldCount(ty: Type, mod: *Module) u32 {3026 pub fn structFieldCount(ty: Type, mod: *Module) u32 {
3011 const ip = &mod.intern_pool;3027 const ip = &mod.intern_pool;
3012 return switch (ip.indexToKey(ty.toIntern())) {3028 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,
3014 .anon_struct_type => |anon_struct| anon_struct.types.len,3030 .anon_struct_type => |anon_struct| anon_struct.types.len,
3015 else => unreachable,3031 else => unreachable,
3016 };3032 };
...@@ -3020,9 +3036,9 @@ pub const Type = struct {...@@ -3020,9 +3036,9 @@ pub const Type = struct {
3020 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {3036 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
3021 const ip = &mod.intern_pool;3037 const ip = &mod.intern_pool;
3022 return switch (ip.indexToKey(ty.toIntern())) {3038 return switch (ip.indexToKey(ty.toIntern())) {
3023 .struct_type => |struct_type| Type.fromInterned(struct_type.field_types.get(ip)[index]),3039 .struct_type => Type.fromInterned(ip.loadStructType(ty.toIntern()).field_types.get(ip)[index]),
3024 .union_type => |union_type| {3040 .union_type => {
3025 const union_obj = ip.loadUnionType(union_type);3041 const union_obj = ip.loadUnionType(ty.toIntern());
3026 return Type.fromInterned(union_obj.field_types.get(ip)[index]);3042 return Type.fromInterned(union_obj.field_types.get(ip)[index]);
3027 },3043 },
3028 .anon_struct_type => |anon_struct| Type.fromInterned(anon_struct.types.get(ip)[index]),3044 .anon_struct_type => |anon_struct| Type.fromInterned(anon_struct.types.get(ip)[index]),
...@@ -3033,7 +3049,8 @@ pub const Type = struct {...@@ -3033,7 +3049,8 @@ pub const Type = struct {
3033 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) Alignment {3049 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) Alignment {
3034 const ip = &mod.intern_pool;3050 const ip = &mod.intern_pool;
3035 switch (ip.indexToKey(ty.toIntern())) {3051 switch (ip.indexToKey(ty.toIntern())) {
3036 .struct_type => |struct_type| {3052 .struct_type => {
3053 const struct_type = ip.loadStructType(ty.toIntern());
3037 assert(struct_type.layout != .Packed);3054 assert(struct_type.layout != .Packed);
3038 const explicit_align = struct_type.fieldAlign(ip, index);3055 const explicit_align = struct_type.fieldAlign(ip, index);
3039 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);3056 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);
...@@ -3042,8 +3059,8 @@ pub const Type = struct {...@@ -3042,8 +3059,8 @@ pub const Type = struct {
3042 .anon_struct_type => |anon_struct| {3059 .anon_struct_type => |anon_struct| {
3043 return Type.fromInterned(anon_struct.types.get(ip)[index]).abiAlignment(mod);3060 return Type.fromInterned(anon_struct.types.get(ip)[index]).abiAlignment(mod);
3044 },3061 },
3045 .union_type => |union_type| {3062 .union_type => {
3046 const union_obj = ip.loadUnionType(union_type);3063 const union_obj = ip.loadUnionType(ty.toIntern());
3047 return mod.unionFieldNormalAlignment(union_obj, @intCast(index));3064 return mod.unionFieldNormalAlignment(union_obj, @intCast(index));
3048 },3065 },
3049 else => unreachable,3066 else => unreachable,
...@@ -3053,7 +3070,8 @@ pub const Type = struct {...@@ -3053,7 +3070,8 @@ pub const Type = struct {
3053 pub fn structFieldDefaultValue(ty: Type, index: usize, mod: *Module) Value {3070 pub fn structFieldDefaultValue(ty: Type, index: usize, mod: *Module) Value {
3054 const ip = &mod.intern_pool;3071 const ip = &mod.intern_pool;
3055 switch (ip.indexToKey(ty.toIntern())) {3072 switch (ip.indexToKey(ty.toIntern())) {
3056 .struct_type => |struct_type| {3073 .struct_type => {
3074 const struct_type = ip.loadStructType(ty.toIntern());
3057 const val = struct_type.fieldInit(ip, index);3075 const val = struct_type.fieldInit(ip, index);
3058 // TODO: avoid using `unreachable` to indicate this.3076 // TODO: avoid using `unreachable` to indicate this.
3059 if (val == .none) return Value.@"unreachable";3077 if (val == .none) return Value.@"unreachable";
...@@ -3072,7 +3090,8 @@ pub const Type = struct {...@@ -3072,7 +3090,8 @@ pub const Type = struct {
3072 pub fn structFieldValueComptime(ty: Type, mod: *Module, index: usize) !?Value {3090 pub fn structFieldValueComptime(ty: Type, mod: *Module, index: usize) !?Value {
3073 const ip = &mod.intern_pool;3091 const ip = &mod.intern_pool;
3074 switch (ip.indexToKey(ty.toIntern())) {3092 switch (ip.indexToKey(ty.toIntern())) {
3075 .struct_type => |struct_type| {3093 .struct_type => {
3094 const struct_type = ip.loadStructType(ty.toIntern());
3076 if (struct_type.fieldIsComptime(ip, index)) {3095 if (struct_type.fieldIsComptime(ip, index)) {
3077 assert(struct_type.haveFieldInits(ip));3096 assert(struct_type.haveFieldInits(ip));
3078 return Value.fromInterned(struct_type.field_inits.get(ip)[index]);3097 return Value.fromInterned(struct_type.field_inits.get(ip)[index]);
...@@ -3095,7 +3114,7 @@ pub const Type = struct {...@@ -3095,7 +3114,7 @@ pub const Type = struct {
3095 pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool {3114 pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool {
3096 const ip = &mod.intern_pool;3115 const ip = &mod.intern_pool;
3097 return switch (ip.indexToKey(ty.toIntern())) {3116 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),
3099 .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none,3118 .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none,
3100 else => unreachable,3119 else => unreachable,
3101 };3120 };
...@@ -3110,7 +3129,8 @@ pub const Type = struct {...@@ -3110,7 +3129,8 @@ pub const Type = struct {
3110 pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {3129 pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {
3111 const ip = &mod.intern_pool;3130 const ip = &mod.intern_pool;
3112 switch (ip.indexToKey(ty.toIntern())) {3131 switch (ip.indexToKey(ty.toIntern())) {
3113 .struct_type => |struct_type| {3132 .struct_type => {
3133 const struct_type = ip.loadStructType(ty.toIntern());
3114 assert(struct_type.haveLayout(ip));3134 assert(struct_type.haveLayout(ip));
3115 assert(struct_type.layout != .Packed);3135 assert(struct_type.layout != .Packed);
3116 return struct_type.offsets.get(ip)[index];3136 return struct_type.offsets.get(ip)[index];
...@@ -3137,11 +3157,11 @@ pub const Type = struct {...@@ -3137,11 +3157,11 @@ pub const Type = struct {
3137 return offset;3157 return offset;
3138 },3158 },
31393159
3140 .union_type => |union_type| {3160 .union_type => {
3161 const union_type = ip.loadUnionType(ty.toIntern());
3141 if (!union_type.hasTag(ip))3162 if (!union_type.hasTag(ip))
3142 return 0;3163 return 0;
3143 const union_obj = ip.loadUnionType(union_type);3164 const layout = mod.getUnionLayout(union_type);
3144 const layout = mod.getUnionLayout(union_obj);
3145 if (layout.tag_align.compare(.gte, layout.payload_align)) {3165 if (layout.tag_align.compare(.gte, layout.payload_align)) {
3146 // {Tag, Payload}3166 // {Tag, Payload}
3147 return layout.payload_align.forward(layout.tag_size);3167 return layout.payload_align.forward(layout.tag_size);
...@@ -3160,17 +3180,8 @@ pub const Type = struct {...@@ -3160,17 +3180,8 @@ pub const Type = struct {
3160 }3180 }
31613181
3162 pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc {3182 pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc {
3163 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {3183 const decl = ty.getOwnerDeclOrNull(mod) orelse return null;
3164 .struct_type => |struct_type| {3184 return mod.declPtr(decl).srcLoc(mod);
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 };
3174 }3185 }
31753186
3176 pub fn getOwnerDecl(ty: Type, mod: *Module) InternPool.DeclIndex {3187 pub fn getOwnerDecl(ty: Type, mod: *Module) InternPool.DeclIndex {
...@@ -3178,11 +3189,12 @@ pub const Type = struct {...@@ -3178,11 +3189,12 @@ pub const Type = struct {
3178 }3189 }
31793190
3180 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?InternPool.DeclIndex {3191 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?InternPool.DeclIndex {
3181 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {3192 const ip = &mod.intern_pool;
3182 .struct_type => |struct_type| struct_type.decl.unwrap(),3193 return switch (ip.indexToKey(ty.toIntern())) {
3183 .union_type => |union_type| union_type.decl,3194 .struct_type => ip.loadStructType(ty.toIntern()).decl.unwrap(),
3184 .opaque_type => |opaque_type| opaque_type.decl,3195 .union_type => ip.loadUnionType(ty.toIntern()).decl,
3185 .enum_type => |enum_type| enum_type.decl,3196 .opaque_type => ip.loadOpaqueType(ty.toIntern()).decl,
3197 .enum_type => ip.loadEnumType(ty.toIntern()).decl,
3186 else => null,3198 else => null,
3187 };3199 };
3188 }3200 }
...@@ -3194,7 +3206,8 @@ pub const Type = struct {...@@ -3194,7 +3206,8 @@ pub const Type = struct {
3194 pub fn isTuple(ty: Type, mod: *Module) bool {3206 pub fn isTuple(ty: Type, mod: *Module) bool {
3195 const ip = &mod.intern_pool;3207 const ip = &mod.intern_pool;
3196 return switch (ip.indexToKey(ty.toIntern())) {3208 return switch (ip.indexToKey(ty.toIntern())) {
3197 .struct_type => |struct_type| {3209 .struct_type => {
3210 const struct_type = ip.loadStructType(ty.toIntern());
3198 if (struct_type.layout == .Packed) return false;3211 if (struct_type.layout == .Packed) return false;
3199 if (struct_type.decl == .none) return false;3212 if (struct_type.decl == .none) return false;
3200 return struct_type.flagsPtr(ip).is_tuple;3213 return struct_type.flagsPtr(ip).is_tuple;
...@@ -3215,7 +3228,8 @@ pub const Type = struct {...@@ -3215,7 +3228,8 @@ pub const Type = struct {
3215 pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool {3228 pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool {
3216 const ip = &mod.intern_pool;3229 const ip = &mod.intern_pool;
3217 return switch (ip.indexToKey(ty.toIntern())) {3230 return switch (ip.indexToKey(ty.toIntern())) {
3218 .struct_type => |struct_type| {3231 .struct_type => {
3232 const struct_type = ip.loadStructType(ty.toIntern());
3219 if (struct_type.layout == .Packed) return false;3233 if (struct_type.layout == .Packed) return false;
3220 if (struct_type.decl == .none) return false;3234 if (struct_type.decl == .none) return false;
3221 return struct_type.flagsPtr(ip).is_tuple;3235 return struct_type.flagsPtr(ip).is_tuple;
...@@ -3262,16 +3276,28 @@ pub const Type = struct {...@@ -3262,16 +3276,28 @@ pub const Type = struct {
3262 }3276 }
32633277
3264 pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {3278 pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
3265 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {3279 const ip = &zcu.intern_pool;
3266 inline .struct_type,3280 return switch (ip.indexToKey(ty.toIntern())) {
3267 .union_type,3281 .struct_type => ip.loadStructType(ty.toIntern()).zir_index.unwrap(),
3268 .enum_type,3282 .union_type => ip.loadUnionType(ty.toIntern()).zir_index,
3269 .opaque_type,3283 .enum_type => ip.loadEnumType(ty.toIntern()).zir_index.unwrap(),
3270 => |info| info.zir_index.unwrap(),3284 .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
3271 else => null,3285 else => null,
3272 };3286 };
3273 }3287 }
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
3275 pub const @"u1": Type = .{ .ip_index = .u1_type };3301 pub const @"u1": Type = .{ .ip_index = .u1_type };
3276 pub const @"u8": Type = .{ .ip_index = .u8_type };3302 pub const @"u8": Type = .{ .ip_index = .u8_type };
3277 pub const @"u16": Type = .{ .ip_index = .u16_type };3303 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" {...@@ -1242,3 +1242,24 @@ test "Non-exhaustive enum backed by comptime_int" {
1242 e = @as(E, @enumFromInt(378089457309184723749));1242 e = @as(E, @enumFromInt(378089457309184723749));
1243 try expect(@intFromEnum(e) == 378089457309184723749);1243 try expect(@intFromEnum(e) == 378089457309184723749);
1244}1244}
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" {...@@ -371,8 +371,12 @@ test "extern function used as generic parameter" {
371 const S = struct {371 const S = struct {
372 extern fn usedAsGenericParameterFoo() void;372 extern fn usedAsGenericParameterFoo() void;
373 extern fn usedAsGenericParameterBar() void;373 extern fn usedAsGenericParameterBar() void;
374 inline fn usedAsGenericParameterBaz(comptime _: anytype) type {374 inline fn usedAsGenericParameterBaz(comptime token: anytype) type {
375 return struct {};375 return struct {
376 comptime {
377 _ = token;
378 }
379 };
376 }380 }
377 };381 };
378 try expect(S.usedAsGenericParameterBaz(S.usedAsGenericParameterFoo) !=382 try expect(S.usedAsGenericParameterBaz(S.usedAsGenericParameterFoo) !=
test/behavior/src.zig+6-2
...@@ -23,8 +23,12 @@ test "@src" {...@@ -23,8 +23,12 @@ test "@src" {
2323
24test "@src used as a comptime parameter" {24test "@src used as a comptime parameter" {
25 const S = struct {25 const S = struct {
26 fn Foo(comptime _: std.builtin.SourceLocation) type {26 fn Foo(comptime src: std.builtin.SourceLocation) type {
27 return struct {};27 return struct {
28 comptime {
29 _ = src;
30 }
31 };
28 }32 }
29 };33 };
30 const T1 = S.Foo(@src());34 const T1 = S.Foo(@src());
test/behavior/struct.zig+23
...@@ -2127,3 +2127,26 @@ test "struct containing optional pointer to array of @This()" {...@@ -2127,3 +2127,26 @@ test "struct containing optional pointer to array of @This()" {
2127 _ = &s;2127 _ = &s;
2128 try expect(s.x.?[0].x == null);2128 try expect(s.x.?[0].x == null);
2129}2129}
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");...@@ -2,6 +2,7 @@ const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Type = std.builtin.Type;3const Type = std.builtin.Type;
4const testing = std.testing;4const testing = std.testing;
5const assert = std.debug.assert;
56
6fn testTypes(comptime types: []const type) !void {7fn testTypes(comptime types: []const type) !void {
7 inline for (types) |testType| {8 inline for (types) |testType| {
...@@ -734,3 +735,28 @@ test "struct field names sliced at comptime from larger string" {...@@ -734,3 +735,28 @@ test "struct field names sliced at comptime from larger string" {
734 try testing.expectEqualStrings("f3", gen_fields[2].name);735 try testing.expectEqualStrings("f3", gen_fields[2].name);
735 }736 }
736}737}
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" {...@@ -164,21 +164,30 @@ test "fn param" {
164}164}
165165
166fn TypeFromFn(comptime T: type) type {166fn TypeFromFn(comptime T: type) type {
167 _ = T;167 return struct {
168 return struct {};168 comptime {
169 _ = T;
170 }
171 };
169}172}
170173
171fn TypeFromFn2(comptime T1: type, comptime T2: type) type {174fn TypeFromFn2(comptime T1: type, comptime T2: type) type {
172 _ = T1;175 return struct {
173 _ = T2;176 comptime {
174 return struct {};177 _ = T1;
178 _ = T2;
179 }
180 };
175}181}
176182
177fn TypeFromFnB(comptime T1: type, comptime T2: type, comptime T3: type) type {183fn TypeFromFnB(comptime T1: type, comptime T2: type, comptime T3: type) type {
178 _ = T1;184 return struct {
179 _ = T2;185 comptime {
180 _ = T3;186 _ = T1;
181 return struct {};187 _ = T2;
188 _ = T3;
189 }
190 };
182}191}
183192
184/// Replaces integers in `actual` with '0' before doing the test.193/// 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)" {...@@ -2273,3 +2273,30 @@ test "create union(enum) from other union(enum)" {
2273 else => {},2273 else => {},
2274 }2274 }
2275}2275}
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 {...@@ -74,7 +74,7 @@ comptime {
74// target=native74// target=native
75//75//
76// :2:5: error: tuple cannot have non-numeric field 'foo'76// :2:5: error: tuple cannot have non-numeric field 'foo'
77// :16:5: error: tuple field 3 exceeds tuple field count77// :16:5: error: tuple field name '3' does not match field index 0
78// :30:5: error: comptime field without default initialization value78// :30:5: error: comptime field without default initialization value
79// :44:5: error: extern struct fields cannot be marked comptime79// :44:5: error: extern struct fields cannot be marked comptime
80// :58:5: error: alignment in a packed struct field must be set to 080// :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 {...@@ -30,6 +30,6 @@ export fn entry() void {
30// backend=stage230// backend=stage2
31// target=native31// target=native
32//32//
33// :13:16: error: enum field(s) missing in union33// :13:16: error: enum fields missing in union
34// :1:13: note: field 'arst' missing, declared here34// :1:13: note: field 'arst' missing, declared here
35// :1:13: note: enum declared here35// :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 {...@@ -26,7 +26,7 @@ export fn entry() void {
26// backend=stage226// backend=stage2
27// target=native27// target=native
28//28//
29// :12:16: error: enum field(s) missing in union29// :12:16: error: enum fields missing in union
30// :1:13: note: field 'signed' missing, declared here30// :1:13: note: field 'signed' missing, declared here
31// :1:13: note: field 'unsigned' missing, declared here31// :1:13: note: field 'unsigned' missing, declared here
32// :1:13: note: enum declared here32// :1:13: note: enum declared here