Commit cbbb5cc2ec

Andrew Kelley <andrew@ziglang.org>
2023-07-10 03:49:16
InternPool: implement getFuncInstance
This handles the case without an inferred error set. Still TODO is the case with one. Also fixes branchQuota returning a pointer to the wrong field.
1 parent 6d72f97
Changed files (2)
src/InternPool.zig
@@ -645,7 +645,7 @@ pub const Key = union(enum) {
 
         /// Returns a pointer that becomes invalid after any additions to the `InternPool`.
         pub fn branchQuota(func: *const Func, ip: *const InternPool) *u32 {
-            return &ip.extra.items[func.zir_body_inst_extra_index];
+            return &ip.extra.items[func.branch_quota_extra_index];
         }
 
         /// Returns a pointer that becomes invalid after any additions to the `InternPool`.
@@ -4649,100 +4649,109 @@ pub const GetFuncInstanceKey = struct {
     is_noinline: bool,
     generic_owner: Index,
     inferred_error_set: bool,
+    comptime_args: []const Index,
+    generation: u32,
 };
 
 pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) Allocator.Error!Index {
-    _ = ip;
-    _ = gpa;
-    _ = arg;
-    @panic("TODO");
-    //const func_ty = try ip.getFuncType(gpa, .{
-    //    .param_types = arg.param_types,
-    //    .bare_return_type = arg.bare_return_type,
-    //    .comptime_bits = arg.comptime_bits,
-    //    .noalias_bits = arg.noalias_bits,
-    //    .alignment = arg.alignment,
-    //    .cc = arg.cc,
-    //    .is_var_args = arg.is_var_args,
-    //    .is_generic = arg.is_generic,
-    //    .is_noinline = arg.is_noinline,
-    //    .section_is_generic = arg.section_is_generic,
-    //    .addrspace_is_generic = arg.addrspace_is_generic,
-    //    .inferred_error_set = arg.inferred_error_set,
-    //});
-
-    //const fn_owner_decl = ip.declPtr(arg.fn_owner_decl);
-    //const decl_index = try ip.createDecl(gpa, .{
-    //    .name = undefined,
-    //    .src_namespace = fn_owner_decl.src_namespace,
-    //    .src_node = fn_owner_decl.src_node,
-    //    .src_line = fn_owner_decl.src_line,
-    //    .has_tv = true,
-    //    .owns_tv = true,
-    //    .ty = func_ty,
-    //    .val = undefined,
-    //    .alignment = .none,
-    //    .@"linksection" = fn_owner_decl.@"linksection",
-    //    .@"addrspace" = fn_owner_decl.@"addrspace",
-    //    .analysis = .complete,
-    //    .deletion_flag = false,
-    //    .zir_decl_index = fn_owner_decl.zir_decl_index,
-    //    .src_scope = fn_owner_decl.src_scope,
-    //    .generation = arg.generation,
-    //    .is_pub = fn_owner_decl.is_pub,
-    //    .is_exported = fn_owner_decl.is_exported,
-    //    .has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace,
-    //    .has_align = fn_owner_decl.has_align,
-    //    .alive = true,
-    //    .kind = .anon,
-    //});
-    //// TODO: improve this name
-    //const decl = ip.declPtr(decl_index);
-    //decl.name = try ip.getOrPutStringFmt(gpa, "{}__anon_{d}", .{
-    //    fn_owner_decl.name.fmt(ip), @intFromEnum(decl_index),
-    //});
-
-    //const gop = try ip.map.getOrPutAdapted(gpa, Key{
-    //    .func = .{
-    //        .ty = func_ty,
-    //        .generic_owner = .none,
-    //        .owner_decl = decl_index,
-    //        // Only the above fields will be read for hashing/equality.
-    //        .analysis_extra_index = undefined,
-    //        .zir_body_inst_extra_index = undefined,
-    //        .branch_quota_extra_index = undefined,
-    //        .resolved_error_set_extra_index = undefined,
-    //        .zir_body_inst = undefined,
-    //        .lbrace_line = undefined,
-    //        .rbrace_line = undefined,
-    //        .lbrace_column = undefined,
-    //        .rbrace_column = undefined,
-    //        .comptime_args = undefined,
-    //    },
-    //}, KeyAdapter{ .intern_pool = ip });
-    //if (gop.found_existing) return @enumFromInt(gop.index);
-    //try ip.items.append(gpa, .{
-    //    .tag = .func_decl,
-    //    .data = try ip.addExtra(gpa, .{
-    //        .analysis = .{
-    //            .state = if (arg.cc == .Inline) .inline_only else .none,
-    //            .is_cold = false,
-    //            .is_noinline = arg.is_noinline,
-    //            .calls_or_awaits_errorable_fn = false,
-    //            .stack_alignment = .none,
-    //        },
-    //        .owner_decl = arg.owner_decl,
-    //        .ty = func_ty,
-    //        .zir_body_inst = arg.zir_body_inst,
-    //        .lbrace_line = arg.lbrace_line,
-    //        .rbrace_line = arg.rbrace_line,
-    //        .lbrace_column = arg.lbrace_column,
-    //        .rbrace_column = arg.rbrace_column,
-    //    }),
-    //});
-    //const func_index: InternPool.Index = @enumFromInt(ip.items.len - 1);
-    //decl.val = func_index.toValue();
-    //return func_index;
+    if (arg.inferred_error_set) @panic("TODO");
+
+    const func_ty = try ip.getFuncType(gpa, .{
+        .param_types = arg.param_types,
+        .return_type = arg.bare_return_type,
+        .comptime_bits = 0,
+        .noalias_bits = arg.noalias_bits,
+        .alignment = arg.alignment,
+        .cc = arg.cc,
+        .is_var_args = false,
+        .is_generic = false,
+        .is_noinline = arg.is_noinline,
+        .section_is_generic = false,
+        .addrspace_is_generic = false,
+    });
+
+    assert(arg.comptime_args.len == ip.funcTypeParamsLen(ip.typeOf(arg.generic_owner)));
+
+    try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.FuncInstance).Struct.fields.len +
+        arg.comptime_args.len);
+    const prev_extra_len = ip.extra.items.len;
+    errdefer ip.extra.items.len = prev_extra_len;
+
+    const func_instance_extra_index = ip.addExtraAssumeCapacity(Tag.FuncInstance{
+        .analysis = .{
+            .state = if (arg.cc == .Inline) .inline_only else .none,
+            .is_cold = false,
+            .is_noinline = arg.is_noinline,
+            .calls_or_awaits_errorable_fn = false,
+            .stack_alignment = .none,
+            .inferred_error_set = false,
+        },
+        // This is populated after we create the Decl below. It is not read
+        // by equality or hashing functions.
+        .owner_decl = undefined,
+        .ty = func_ty,
+        .branch_quota = 0,
+        .generic_owner = arg.generic_owner,
+    });
+    ip.extra.appendSliceAssumeCapacity(@ptrCast(arg.comptime_args));
+
+    const gop = try ip.map.getOrPutAdapted(gpa, Key{
+        .func = extraFuncInstance(ip, func_instance_extra_index),
+    }, KeyAdapter{ .intern_pool = ip });
+    errdefer _ = ip.map.pop();
+
+    if (gop.found_existing) {
+        ip.extra.items.len = prev_extra_len;
+        return @enumFromInt(gop.index);
+    }
+
+    try ip.items.ensureUnusedCapacity(gpa, 1);
+    const func_index: Index = @enumFromInt(ip.items.len);
+
+    const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(arg.generic_owner));
+    const decl_index = try ip.createDecl(gpa, .{
+        .name = undefined,
+        .src_namespace = fn_owner_decl.src_namespace,
+        .src_node = fn_owner_decl.src_node,
+        .src_line = fn_owner_decl.src_line,
+        .has_tv = true,
+        .owns_tv = true,
+        .ty = func_ty.toType(),
+        .val = func_index.toValue(),
+        .alignment = .none,
+        .@"linksection" = fn_owner_decl.@"linksection",
+        .@"addrspace" = fn_owner_decl.@"addrspace",
+        .analysis = .complete,
+        .deletion_flag = false,
+        .zir_decl_index = fn_owner_decl.zir_decl_index,
+        .src_scope = fn_owner_decl.src_scope,
+        .generation = arg.generation,
+        .is_pub = fn_owner_decl.is_pub,
+        .is_exported = fn_owner_decl.is_exported,
+        .has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace,
+        .has_align = fn_owner_decl.has_align,
+        .alive = true,
+        .kind = .anon,
+    });
+    errdefer ip.destroyDecl(gpa, decl_index);
+
+    // Populate the owner_decl field which was left undefined until now.
+    ip.extra.items[
+        func_instance_extra_index + std.meta.fieldIndex(Tag.FuncInstance, "owner_decl").?
+    ] = @intFromEnum(decl_index);
+
+    // TODO: improve this name
+    const decl = ip.declPtr(decl_index);
+    decl.name = try ip.getOrPutStringFmt(gpa, "{}__anon_{d}", .{
+        fn_owner_decl.name.fmt(ip), @intFromEnum(decl_index),
+    });
+
+    ip.items.appendAssumeCapacity(.{
+        .tag = .func_instance,
+        .data = func_instance_extra_index,
+    });
+
+    return func_index;
 }
 
 /// Provides API for completing an enum type after calling `getIncompleteEnum`.
@@ -6754,6 +6763,10 @@ pub fn funcDeclInfo(ip: *const InternPool, i: InternPool.Index) Key.Func {
     return extraFuncDecl(ip, datas[@intFromEnum(i)]);
 }
 
+pub fn funcDeclOwner(ip: *const InternPool, i: InternPool.Index) Module.Decl.Index {
+    return funcDeclInfo(ip, i).owner_decl;
+}
+
 pub fn funcTypeParamsLen(ip: *const InternPool, i: InternPool.Index) u32 {
     const tags = ip.items.items(.tag);
     const datas = ip.items.items(.data);
src/Sema.zig
@@ -7527,8 +7527,6 @@ fn instantiateGenericCall(
     const callee = mod.funcInfo(callee_index);
     callee.branchQuota(ip).* = @max(callee.branchQuota(ip).*, sema.branch_quota);
 
-    const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
-
     // Make a runtime call to the new function, making sure to omit the comptime args.
     const func_ty = callee.ty.toType();
     const func_ty_info = mod.typeToFunc(func_ty).?;
@@ -7573,7 +7571,7 @@ fn instantiateGenericCall(
     const result = try block.addInst(.{
         .tag = call_tag,
         .data = .{ .pl_op = .{
-            .operand = callee_inst,
+            .operand = Air.internedToRef(callee_index),
             .payload = sema.addExtraAssumeCapacity(Air.Call{
                 .args_len = runtime_args_len,
             }),
@@ -8775,6 +8773,9 @@ fn funcCommon(
         assert(section != .generic);
         assert(address_space != null);
         assert(!var_args);
+        if (inferred_error_set) {
+            try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
+        }
         const func_index = try ip.getFuncInstance(gpa, .{
             .param_types = param_types,
             .noalias_bits = noalias_bits,
@@ -8784,6 +8785,8 @@ fn funcCommon(
             .is_noinline = is_noinline,
             .inferred_error_set = inferred_error_set,
             .generic_owner = sema.generic_owner,
+            .comptime_args = sema.comptime_args,
+            .generation = mod.generation,
         });
         return finishFunc(
             sema,