Commit 6d72f971af

Andrew Kelley <andrew@ziglang.org>
2023-07-10 01:51:23
InternPool: implement getExternFunc
1 parent 8fd7739
src/Air.zig
@@ -1436,7 +1436,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
 
         .call, .call_always_tail, .call_never_tail, .call_never_inline => {
             const callee_ty = air.typeOf(datas[inst].pl_op.operand, ip);
-            return ip.funcReturnType(callee_ty.toIntern()).toType();
+            return ip.funcTypeReturnType(callee_ty.toIntern()).toType();
         },
 
         .slice_elem_val, .ptr_elem_val, .array_elem_val => {
src/InternPool.zig
@@ -4393,22 +4393,20 @@ pub fn getFuncType(ip: *InternPool, gpa: Allocator, key: GetFuncTypeKey) Allocat
     return @enumFromInt(ip.items.len - 1);
 }
 
-pub const GetExternFuncKey = struct {
-    param_types: []const Index,
-    noalias_bits: u32,
-    return_type: Index,
-    cc: std.builtin.CallingConvention,
-    alignment: Alignment,
-    is_var_args: bool,
-    decl: Module.Decl.Index,
-    lib_name: OptionalNullTerminatedString,
-};
-
-pub fn getExternFunc(ip: *InternPool, gpa: Allocator, key: GetExternFuncKey) Allocator.Error!Index {
-    _ = ip;
-    _ = gpa;
-    _ = key;
-    @panic("TODO");
+pub fn getExternFunc(ip: *InternPool, gpa: Allocator, key: Key.ExternFunc) Allocator.Error!Index {
+    const adapter: KeyAdapter = .{ .intern_pool = ip };
+    const gop = try ip.map.getOrPutAdapted(gpa, Key{ .extern_func = key }, adapter);
+    if (gop.found_existing) return @enumFromInt(gop.index);
+    errdefer _ = ip.map.pop();
+    const prev_extra_len = ip.extra.items.len;
+    const extra_index = try ip.addExtra(gpa, @as(Tag.ExternFunc, key));
+    errdefer ip.extra.items.len = prev_extra_len;
+    try ip.items.append(gpa, .{
+        .tag = .extern_func,
+        .data = extra_index,
+    });
+    errdefer ip.items.len -= 1;
+    return @enumFromInt(ip.items.len - 1);
 }
 
 pub const GetFuncDeclKey = struct {
@@ -6375,7 +6373,7 @@ pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {
     };
 }
 
-pub fn funcReturnType(ip: *const InternPool, ty: Index) Index {
+pub fn funcTypeReturnType(ip: *const InternPool, ty: Index) Index {
     const item = ip.items.get(@intFromEnum(ty));
     const child_item = switch (item.tag) {
         .type_pointer => ip.items.get(ip.extra.items[
src/Sema.zig
@@ -8767,92 +8767,63 @@ fn funcCommon(
 
     const param_types = block.params.items(.ty);
 
-    const opt_func_index: InternPool.Index = i: {
-        if (!is_source_decl) {
-            assert(has_body);
-            assert(!is_generic);
-            assert(comptime_bits == 0);
-            assert(cc != null);
-            assert(section != .generic);
-            assert(address_space != null);
-            assert(!var_args);
-            break :i try ip.getFuncInstance(gpa, .{
-                .param_types = param_types,
-                .noalias_bits = noalias_bits,
-                .bare_return_type = bare_return_type.toIntern(),
-                .cc = cc_resolved,
-                .alignment = alignment.?,
-                .is_noinline = is_noinline,
-                .inferred_error_set = inferred_error_set,
-                .generic_owner = sema.generic_owner,
-            });
-        }
-
-        // extern_func and func_decl functions take ownership of `sema.owner_decl`.
-
-        sema.owner_decl.@"linksection" = switch (section) {
-            .generic => .none,
-            .default => .none,
-            .explicit => |section_name| section_name.toOptional(),
-        };
-        sema.owner_decl.alignment = alignment orelse .none;
-        sema.owner_decl.@"addrspace" = address_space orelse .generic;
-
-        if (is_extern) {
-            assert(comptime_bits == 0);
-            assert(cc != null);
-            assert(section != .generic);
-            assert(address_space != null);
-            assert(!is_generic);
-            break :i try ip.getExternFunc(gpa, .{
-                .param_types = param_types,
-                .noalias_bits = noalias_bits,
-                .return_type = bare_return_type.toIntern(),
-                .cc = cc_resolved,
-                .alignment = alignment.?,
-                .is_var_args = var_args,
-                .decl = sema.owner_decl_index,
-                .lib_name = if (opt_lib_name) |lib_name| (try mod.intern_pool.getOrPutString(
-                    gpa,
-                    try sema.handleExternLibName(block, .{
-                        .node_offset_lib_name = src_node_offset,
-                    }, lib_name),
-                )).toOptional() else .none,
-            });
-        }
-
-        if (!has_body) break :i .none;
-
-        if (inferred_error_set) {
-            try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
-            break :i try ip.getFuncDeclIes(gpa, .{
-                .owner_decl = sema.owner_decl_index,
+    if (!is_source_decl) {
+        assert(has_body);
+        assert(!is_generic);
+        assert(comptime_bits == 0);
+        assert(cc != null);
+        assert(section != .generic);
+        assert(address_space != null);
+        assert(!var_args);
+        const func_index = try ip.getFuncInstance(gpa, .{
+            .param_types = param_types,
+            .noalias_bits = noalias_bits,
+            .bare_return_type = bare_return_type.toIntern(),
+            .cc = cc_resolved,
+            .alignment = alignment.?,
+            .is_noinline = is_noinline,
+            .inferred_error_set = inferred_error_set,
+            .generic_owner = sema.generic_owner,
+        });
+        return finishFunc(
+            sema,
+            block,
+            func_index,
+            .none,
+            ret_poison,
+            bare_return_type,
+            ret_ty_src,
+            cc_resolved,
+            is_source_decl,
+            ret_ty_requires_comptime,
+            func_inst,
+            cc_src,
+            is_noinline,
+            is_generic,
+            final_is_generic,
+        );
+    }
 
-                .param_types = param_types,
-                .noalias_bits = noalias_bits,
-                .comptime_bits = comptime_bits,
-                .bare_return_type = bare_return_type.toIntern(),
-                .cc = cc,
-                .alignment = alignment,
-                .section_is_generic = section == .generic,
-                .addrspace_is_generic = address_space == null,
-                .is_var_args = var_args,
-                .is_generic = final_is_generic,
-                .is_noinline = is_noinline,
-
-                .zir_body_inst = func_inst,
-                .lbrace_line = src_locs.lbrace_line,
-                .rbrace_line = src_locs.rbrace_line,
-                .lbrace_column = @as(u16, @truncate(src_locs.columns)),
-                .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
-            });
-        }
+    // extern_func and func_decl functions take ownership of `sema.owner_decl`.
+    sema.owner_decl.@"linksection" = switch (section) {
+        .generic => .none,
+        .default => .none,
+        .explicit => |section_name| section_name.toOptional(),
+    };
+    sema.owner_decl.alignment = alignment orelse .none;
+    sema.owner_decl.@"addrspace" = address_space orelse .generic;
+
+    if (inferred_error_set) {
+        assert(!is_extern);
+        assert(has_body);
+        try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
+        const func_index = try ip.getFuncDeclIes(gpa, .{
+            .owner_decl = sema.owner_decl_index,
 
-        const func_ty = try ip.getFuncType(gpa, .{
             .param_types = param_types,
             .noalias_bits = noalias_bits,
             .comptime_bits = comptime_bits,
-            .return_type = bare_return_type.toIntern(),
+            .bare_return_type = bare_return_type.toIntern(),
             .cc = cc,
             .alignment = alignment,
             .section_is_generic = section == .generic,
@@ -8860,9 +8831,83 @@ fn funcCommon(
             .is_var_args = var_args,
             .is_generic = final_is_generic,
             .is_noinline = is_noinline,
+
+            .zir_body_inst = func_inst,
+            .lbrace_line = src_locs.lbrace_line,
+            .rbrace_line = src_locs.rbrace_line,
+            .lbrace_column = @as(u16, @truncate(src_locs.columns)),
+            .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
         });
+        return finishFunc(
+            sema,
+            block,
+            func_index,
+            .none,
+            ret_poison,
+            bare_return_type,
+            ret_ty_src,
+            cc_resolved,
+            is_source_decl,
+            ret_ty_requires_comptime,
+            func_inst,
+            cc_src,
+            is_noinline,
+            is_generic,
+            final_is_generic,
+        );
+    }
 
-        break :i try ip.getFuncDecl(gpa, .{
+    const func_ty = try ip.getFuncType(gpa, .{
+        .param_types = param_types,
+        .noalias_bits = noalias_bits,
+        .comptime_bits = comptime_bits,
+        .return_type = bare_return_type.toIntern(),
+        .cc = cc,
+        .alignment = alignment,
+        .section_is_generic = section == .generic,
+        .addrspace_is_generic = address_space == null,
+        .is_var_args = var_args,
+        .is_generic = final_is_generic,
+        .is_noinline = is_noinline,
+    });
+
+    if (is_extern) {
+        assert(comptime_bits == 0);
+        assert(cc != null);
+        assert(section != .generic);
+        assert(address_space != null);
+        assert(!is_generic);
+        const func_index = try ip.getExternFunc(gpa, .{
+            .ty = func_ty,
+            .decl = sema.owner_decl_index,
+            .lib_name = if (opt_lib_name) |lib_name| (try mod.intern_pool.getOrPutString(
+                gpa,
+                try sema.handleExternLibName(block, .{
+                    .node_offset_lib_name = src_node_offset,
+                }, lib_name),
+            )).toOptional() else .none,
+        });
+        return finishFunc(
+            sema,
+            block,
+            func_index,
+            func_ty,
+            ret_poison,
+            bare_return_type,
+            ret_ty_src,
+            cc_resolved,
+            is_source_decl,
+            ret_ty_requires_comptime,
+            func_inst,
+            cc_src,
+            is_noinline,
+            is_generic,
+            final_is_generic,
+        );
+    }
+
+    if (has_body) {
+        const func_index = try ip.getFuncDecl(gpa, .{
             .owner_decl = sema.owner_decl_index,
             .ty = func_ty,
             .cc = cc,
@@ -8873,12 +8918,70 @@ fn funcCommon(
             .lbrace_column = @as(u16, @truncate(src_locs.columns)),
             .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
         });
-    };
+        return finishFunc(
+            sema,
+            block,
+            func_index,
+            func_ty,
+            ret_poison,
+            bare_return_type,
+            ret_ty_src,
+            cc_resolved,
+            is_source_decl,
+            ret_ty_requires_comptime,
+            func_inst,
+            cc_src,
+            is_noinline,
+            is_generic,
+            final_is_generic,
+        );
+    }
+
+    return finishFunc(
+        sema,
+        block,
+        .none,
+        func_ty,
+        ret_poison,
+        bare_return_type,
+        ret_ty_src,
+        cc_resolved,
+        is_source_decl,
+        ret_ty_requires_comptime,
+        func_inst,
+        cc_src,
+        is_noinline,
+        is_generic,
+        final_is_generic,
+    );
+}
+
+fn finishFunc(
+    sema: *Sema,
+    block: *Block,
+    opt_func_index: InternPool.Index,
+    func_ty: InternPool.Index,
+    ret_poison: bool,
+    bare_return_type: Type,
+    ret_ty_src: LazySrcLoc,
+    cc_resolved: std.builtin.CallingConvention,
+    is_source_decl: bool,
+    ret_ty_requires_comptime: bool,
+    func_inst: Zir.Inst.Index,
+    cc_src: LazySrcLoc,
+    is_noinline: bool,
+    is_generic: bool,
+    final_is_generic: bool,
+) CompileError!Air.Inst.Ref {
+    const mod = sema.mod;
+    const ip = &mod.intern_pool;
+    const gpa = sema.gpa;
+    const target = mod.getTarget();
 
     const return_type: Type = if (opt_func_index == .none or ret_poison)
         bare_return_type
     else
-        ip.funcReturnType(ip.typeOf(opt_func_index)).toType();
+        ip.funcTypeReturnType(ip.typeOf(opt_func_index)).toType();
 
     if (!return_type.isValidReturnType(mod)) {
         const opaque_str = if (return_type.zigTypeTag(mod) == .Opaque) "opaque " else "";
@@ -8998,19 +9101,7 @@ fn funcCommon(
         _ = try sema.resolveTypeFields(unresolved_stack_trace_ty);
     }
 
-    return Air.internedToRef(if (opt_func_index == .none) try ip.getFuncType(gpa, .{
-        .param_types = param_types,
-        .noalias_bits = noalias_bits,
-        .comptime_bits = comptime_bits,
-        .return_type = return_type.toIntern(),
-        .cc = cc,
-        .alignment = alignment,
-        .section_is_generic = section == .generic,
-        .addrspace_is_generic = address_space == null,
-        .is_var_args = var_args,
-        .is_generic = final_is_generic,
-        .is_noinline = is_noinline,
-    }) else opt_func_index);
+    return Air.internedToRef(if (opt_func_index != .none) opt_func_index else func_ty);
 }
 
 fn zirParam(
src/type.zig
@@ -2364,7 +2364,7 @@ pub const Type = struct {
 
     /// Asserts the type is a function or a function pointer.
     pub fn fnReturnType(ty: Type, mod: *Module) Type {
-        return mod.intern_pool.funcReturnType(ty.toIntern()).toType();
+        return mod.intern_pool.funcTypeReturnType(ty.toIntern()).toType();
     }
 
     /// Asserts the type is a function.