authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-10 23:33:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-18 19:02:05-07:00
logb81d1930216122bd3192bff8a47b023d430df6ea
treeeb1100d886846a49e788f18e31c771c49419f2d8
parent8f37b794a5551c7614d8db3e1e8532fc2644d3c2

InternPool: implement getFuncInstanceIes

and fix bug in equality checking for functions with inferred error sets.

1 files changed, 168 insertions(+), 14 deletions(-)

src/InternPool.zig+168-14
......@@ -1136,7 +1136,7 @@ pub const Key = union(enum) {
11361136 var a_ty_info = ip.indexToFuncType(a_info.ty).?;
11371137 a_ty_info.return_type = ip.errorUnionPayload(a_ty_info.return_type);
11381138 var b_ty_info = ip.indexToFuncType(b_info.ty).?;
1139 b_ty_info.return_type = ip.errorUnionPayload(a_ty_info.return_type);
1139 b_ty_info.return_type = ip.errorUnionPayload(b_ty_info.return_type);
11401140 return a_ty_info.eql(b_ty_info, ip);
11411141 },
11421142
......@@ -4657,7 +4657,12 @@ pub fn getErrorSetType(
46574657}
46584658
46594659pub const GetFuncInstanceKey = struct {
4660 /// Has the length of the instance function (may be lesser than
4661 /// comptime_args).
46604662 param_types: []Index,
4663 /// Has the length of generic_owner's parameters (may be greater than
4664 /// param_types).
4665 comptime_args: []const Index,
46614666 noalias_bits: u32,
46624667 bare_return_type: Index,
46634668 cc: std.builtin.CallingConvention,
......@@ -4665,12 +4670,12 @@ pub const GetFuncInstanceKey = struct {
46654670 is_noinline: bool,
46664671 generic_owner: Index,
46674672 inferred_error_set: bool,
4668 comptime_args: []const Index,
46694673 generation: u32,
46704674};
46714675
46724676pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) Allocator.Error!Index {
4673 if (arg.inferred_error_set) @panic("TODO");
4677 if (arg.inferred_error_set)
4678 return getFuncInstanceIes(ip, gpa, arg);
46744679
46754680 const func_ty = try ip.getFuncType(gpa, .{
46764681 .param_types = arg.param_types,
......@@ -4693,7 +4698,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
46934698 const prev_extra_len = ip.extra.items.len;
46944699 errdefer ip.extra.items.len = prev_extra_len;
46954700
4696 const func_instance_extra_index = ip.addExtraAssumeCapacity(Tag.FuncInstance{
4701 const func_extra_index = ip.addExtraAssumeCapacity(Tag.FuncInstance{
46974702 .analysis = .{
46984703 .state = if (arg.cc == .Inline) .inline_only else .none,
46994704 .is_cold = false,
......@@ -4712,7 +4717,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
47124717 ip.extra.appendSliceAssumeCapacity(@ptrCast(arg.comptime_args));
47134718
47144719 const gop = try ip.map.getOrPutAdapted(gpa, Key{
4715 .func = extraFuncInstance(ip, func_instance_extra_index),
4720 .func = extraFuncInstance(ip, func_extra_index),
47164721 }, KeyAdapter{ .intern_pool = ip });
47174722 errdefer _ = ip.map.pop();
47184723
......@@ -4721,10 +4726,164 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
47214726 return @enumFromInt(gop.index);
47224727 }
47234728
4724 try ip.items.ensureUnusedCapacity(gpa, 1);
47254729 const func_index: Index = @enumFromInt(ip.items.len);
47264730
4727 const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(arg.generic_owner));
4731 try ip.items.append(gpa, .{
4732 .tag = .func_instance,
4733 .data = func_extra_index,
4734 });
4735 errdefer ip.items.len -= 1;
4736
4737 return finishFuncInstance(
4738 ip,
4739 gpa,
4740 arg.generic_owner,
4741 func_index,
4742 func_extra_index,
4743 arg.generation,
4744 func_ty,
4745 );
4746}
4747
4748/// This function exists separately than `getFuncInstance` because it needs to
4749/// create 4 new items in the InternPool atomically before it can look for an
4750/// existing item in the map.
4751pub fn getFuncInstanceIes(
4752 ip: *InternPool,
4753 gpa: Allocator,
4754 arg: GetFuncInstanceKey,
4755) Allocator.Error!Index {
4756 // Validate input parameters.
4757 assert(arg.inferred_error_set);
4758 assert(arg.bare_return_type != .none);
4759 for (arg.param_types) |param_type| assert(param_type != .none);
4760
4761 // The strategy here is to add the function decl unconditionally, then to
4762 // ask if it already exists, and if so, revert the lengths of the mutated
4763 // arrays. This is similar to what `getOrPutTrailingString` does.
4764 const prev_extra_len = ip.extra.items.len;
4765 const params_len: u32 = @intCast(arg.param_types.len);
4766
4767 try ip.map.ensureUnusedCapacity(gpa, 4);
4768 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncInstance).Struct.fields.len +
4769 1 + // inferred_error_set
4770 arg.comptime_args.len +
4771 @typeInfo(Tag.ErrorUnionType).Struct.fields.len +
4772 @typeInfo(Tag.TypeFunction).Struct.fields.len +
4773 @intFromBool(arg.noalias_bits != 0) +
4774 params_len);
4775 try ip.items.ensureUnusedCapacity(gpa, 4);
4776
4777 const func_index: Index = @enumFromInt(ip.items.len);
4778 const error_union_type: Index = @enumFromInt(ip.items.len + 1);
4779 const error_set_type: Index = @enumFromInt(ip.items.len + 2);
4780 const func_ty: Index = @enumFromInt(ip.items.len + 3);
4781
4782 const func_extra_index = ip.addExtraAssumeCapacity(Tag.FuncInstance{
4783 .analysis = .{
4784 .state = if (arg.cc == .Inline) .inline_only else .none,
4785 .is_cold = false,
4786 .is_noinline = arg.is_noinline,
4787 .calls_or_awaits_errorable_fn = false,
4788 .stack_alignment = .none,
4789 .inferred_error_set = true,
4790 },
4791 // This is populated after we create the Decl below. It is not read
4792 // by equality or hashing functions.
4793 .owner_decl = undefined,
4794 .ty = func_ty,
4795 .branch_quota = 0,
4796 .generic_owner = arg.generic_owner,
4797 });
4798 ip.extra.appendAssumeCapacity(@intFromEnum(Index.none)); // resolved error set
4799 ip.extra.appendSliceAssumeCapacity(@ptrCast(arg.comptime_args));
4800
4801 const func_type_extra_index = ip.addExtraAssumeCapacity(Tag.TypeFunction{
4802 .params_len = params_len,
4803 .return_type = error_union_type,
4804 .flags = .{
4805 .alignment = arg.alignment,
4806 .cc = arg.cc,
4807 .is_var_args = false,
4808 .has_comptime_bits = false,
4809 .has_noalias_bits = arg.noalias_bits != 0,
4810 .is_generic = false,
4811 .is_noinline = arg.is_noinline,
4812 .align_is_generic = false,
4813 .cc_is_generic = false,
4814 .section_is_generic = false,
4815 .addrspace_is_generic = false,
4816 },
4817 });
4818 // no comptime_bits because has_comptime_bits is false
4819 if (arg.noalias_bits != 0) ip.extra.appendAssumeCapacity(arg.noalias_bits);
4820 ip.extra.appendSliceAssumeCapacity(@ptrCast(arg.param_types));
4821
4822 // TODO: add appendSliceAssumeCapacity to MultiArrayList.
4823 ip.items.appendAssumeCapacity(.{
4824 .tag = .func_instance,
4825 .data = func_extra_index,
4826 });
4827 ip.items.appendAssumeCapacity(.{
4828 .tag = .type_error_union,
4829 .data = ip.addExtraAssumeCapacity(Tag.ErrorUnionType{
4830 .error_set_type = error_set_type,
4831 .payload_type = arg.bare_return_type,
4832 }),
4833 });
4834 ip.items.appendAssumeCapacity(.{
4835 .tag = .type_inferred_error_set,
4836 .data = @intFromEnum(func_index),
4837 });
4838 ip.items.appendAssumeCapacity(.{
4839 .tag = .type_function,
4840 .data = func_type_extra_index,
4841 });
4842
4843 const adapter: KeyAdapter = .{ .intern_pool = ip };
4844 const gop = ip.map.getOrPutAssumeCapacityAdapted(Key{
4845 .func = extraFuncInstance(ip, func_extra_index),
4846 }, adapter);
4847 if (gop.found_existing) {
4848 // Hot path: undo the additions to our two arrays.
4849 ip.items.len -= 4;
4850 ip.extra.items.len = prev_extra_len;
4851 return @enumFromInt(gop.index);
4852 }
4853
4854 // Synchronize the map with items.
4855 assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{ .error_union_type = .{
4856 .error_set_type = error_set_type,
4857 .payload_type = arg.bare_return_type,
4858 } }, adapter).found_existing);
4859 assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{
4860 .inferred_error_set_type = func_index,
4861 }, adapter).found_existing);
4862 assert(!ip.map.getOrPutAssumeCapacityAdapted(Key{
4863 .func_type = extraFuncType(ip, func_type_extra_index),
4864 }, adapter).found_existing);
4865
4866 return finishFuncInstance(
4867 ip,
4868 gpa,
4869 arg.generic_owner,
4870 func_index,
4871 func_extra_index,
4872 arg.generation,
4873 func_ty,
4874 );
4875}
4876
4877fn finishFuncInstance(
4878 ip: *InternPool,
4879 gpa: Allocator,
4880 generic_owner: Index,
4881 func_index: Index,
4882 func_extra_index: u32,
4883 generation: u32,
4884 func_ty: Index,
4885) Allocator.Error!Index {
4886 const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner));
47284887 const decl_index = try ip.createDecl(gpa, .{
47294888 .name = undefined,
47304889 .src_namespace = fn_owner_decl.src_namespace,
......@@ -4741,7 +4900,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
47414900 .deletion_flag = false,
47424901 .zir_decl_index = fn_owner_decl.zir_decl_index,
47434902 .src_scope = fn_owner_decl.src_scope,
4744 .generation = arg.generation,
4903 .generation = generation,
47454904 .is_pub = fn_owner_decl.is_pub,
47464905 .is_exported = fn_owner_decl.is_exported,
47474906 .has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace,
......@@ -4753,7 +4912,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
47534912
47544913 // Populate the owner_decl field which was left undefined until now.
47554914 ip.extra.items[
4756 func_instance_extra_index + std.meta.fieldIndex(Tag.FuncInstance, "owner_decl").?
4915 func_extra_index + std.meta.fieldIndex(Tag.FuncInstance, "owner_decl").?
47574916 ] = @intFromEnum(decl_index);
47584917
47594918 // TODO: improve this name
......@@ -4762,11 +4921,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
47624921 fn_owner_decl.name.fmt(ip), @intFromEnum(decl_index),
47634922 });
47644923
4765 ip.items.appendAssumeCapacity(.{
4766 .tag = .func_instance,
4767 .data = func_instance_extra_index,
4768 });
4769
47704924 return func_index;
47714925}
47724926