| ... | ... | @@ -3995,7 +3995,7 @@ pub fn analyzeExport( |
| 3995 | 3995 | try mod.ensureDeclAnalyzed(exported_decl); |
| 3996 | 3996 | // TODO run the same checks as we do for C ABI struct fields |
| 3997 | 3997 | switch (exported_decl.ty.zigTypeTag()) { |
| 3998 | | .Fn, .Int, .Struct, .Array, .Float => {}, |
| 3998 | .Fn, .Int, .Enum, .Struct, .Union, .Array, .Float => {}, |
| 3999 | 3999 | else => return sema.fail(block, src, "unable to export type '{}'", .{exported_decl.ty}), |
| 4000 | 4000 | } |
| 4001 | 4001 | |
| ... | ... | @@ -4474,8 +4474,26 @@ fn analyzeCall( |
| 4474 | 4474 | |
| 4475 | 4475 | const is_comptime_call = block.is_comptime or modifier == .compile_time or |
| 4476 | 4476 | try sema.typeRequiresComptime(block, func_src, func_ty_info.return_type); |
| 4477 | | const is_inline_call = is_comptime_call or modifier == .always_inline or |
| 4477 | var is_inline_call = is_comptime_call or modifier == .always_inline or |
| 4478 | 4478 | func_ty_info.cc == .Inline; |
| 4479 | |
| 4480 | if (!is_inline_call and func_ty_info.is_generic) { |
| 4481 | if (sema.instantiateGenericCall( |
| 4482 | block, |
| 4483 | func, |
| 4484 | func_src, |
| 4485 | call_src, |
| 4486 | func_ty_info, |
| 4487 | ensure_result_used, |
| 4488 | uncasted_args, |
| 4489 | )) |some| { |
| 4490 | return some; |
| 4491 | } else |err| switch (err) { |
| 4492 | error.GenericPoison => is_inline_call = true, |
| 4493 | else => |e| return e, |
| 4494 | } |
| 4495 | } |
| 4496 | |
| 4479 | 4497 | const result: Air.Inst.Ref = if (is_inline_call) res: { |
| 4480 | 4498 | const func_val = try sema.resolveConstValue(block, func_src, func); |
| 4481 | 4499 | const module_fn = switch (func_val.tag()) { |
| ... | ... | @@ -4728,278 +4746,8 @@ fn analyzeCall( |
| 4728 | 4746 | try wip_captures.finalize(); |
| 4729 | 4747 | |
| 4730 | 4748 | break :res res2; |
| 4731 | | } else if (func_ty_info.is_generic) res: { |
| 4732 | | const func_val = try sema.resolveConstValue(block, func_src, func); |
| 4733 | | const module_fn = switch (func_val.tag()) { |
| 4734 | | .function => func_val.castTag(.function).?.data, |
| 4735 | | .decl_ref => func_val.castTag(.decl_ref).?.data.val.castTag(.function).?.data, |
| 4736 | | else => unreachable, |
| 4737 | | }; |
| 4738 | | // Check the Module's generic function map with an adapted context, so that we |
| 4739 | | // can match against `uncasted_args` rather than doing the work below to create a |
| 4740 | | // generic Scope only to junk it if it matches an existing instantiation. |
| 4741 | | const namespace = module_fn.owner_decl.src_namespace; |
| 4742 | | const fn_zir = namespace.file_scope.zir; |
| 4743 | | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); |
| 4744 | | const zir_tags = fn_zir.instructions.items(.tag); |
| 4745 | | |
| 4746 | | // This hash must match `Module.MonomorphedFuncsContext.hash`. |
| 4747 | | // For parameters explicitly marked comptime and simple parameter type expressions, |
| 4748 | | // we know whether a parameter is elided from a monomorphed function, and can |
| 4749 | | // use it in the hash here. However, for parameter type expressions that are not |
| 4750 | | // explicitly marked comptime and rely on previous parameter comptime values, we |
| 4751 | | // don't find out until after generating a monomorphed function whether the parameter |
| 4752 | | // type ended up being a "must-be-comptime-known" type. |
| 4753 | | var hasher = std.hash.Wyhash.init(0); |
| 4754 | | std.hash.autoHash(&hasher, @ptrToInt(module_fn)); |
| 4755 | | |
| 4756 | | const comptime_tvs = try sema.arena.alloc(TypedValue, func_ty_info.param_types.len); |
| 4757 | | |
| 4758 | | for (func_ty_info.param_types) |param_ty, i| { |
| 4759 | | const is_comptime = func_ty_info.paramIsComptime(i); |
| 4760 | | if (is_comptime) { |
| 4761 | | const arg_src = call_src; // TODO better source location |
| 4762 | | const casted_arg = try sema.coerce(block, param_ty, uncasted_args[i], arg_src); |
| 4763 | | if (try sema.resolveMaybeUndefVal(block, arg_src, casted_arg)) |arg_val| { |
| 4764 | | if (param_ty.tag() != .generic_poison) { |
| 4765 | | arg_val.hash(param_ty, &hasher); |
| 4766 | | } |
| 4767 | | comptime_tvs[i] = .{ |
| 4768 | | // This will be different than `param_ty` in the case of `generic_poison`. |
| 4769 | | .ty = sema.typeOf(casted_arg), |
| 4770 | | .val = arg_val, |
| 4771 | | }; |
| 4772 | | } else { |
| 4773 | | return sema.failWithNeededComptime(block, arg_src); |
| 4774 | | } |
| 4775 | | } else { |
| 4776 | | comptime_tvs[i] = .{ |
| 4777 | | .ty = sema.typeOf(uncasted_args[i]), |
| 4778 | | .val = Value.initTag(.generic_poison), |
| 4779 | | }; |
| 4780 | | } |
| 4781 | | } |
| 4782 | | |
| 4783 | | const precomputed_hash = hasher.final(); |
| 4784 | | |
| 4785 | | const adapter: GenericCallAdapter = .{ |
| 4786 | | .generic_fn = module_fn, |
| 4787 | | .precomputed_hash = precomputed_hash, |
| 4788 | | .func_ty_info = func_ty_info, |
| 4789 | | .comptime_tvs = comptime_tvs, |
| 4790 | | }; |
| 4791 | | const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter); |
| 4792 | | if (gop.found_existing) { |
| 4793 | | const callee_func = gop.key_ptr.*; |
| 4794 | | break :res try sema.finishGenericCall( |
| 4795 | | block, |
| 4796 | | call_src, |
| 4797 | | callee_func, |
| 4798 | | func_src, |
| 4799 | | uncasted_args, |
| 4800 | | fn_info, |
| 4801 | | zir_tags, |
| 4802 | | ); |
| 4803 | | } |
| 4804 | | const new_module_func = try gpa.create(Module.Fn); |
| 4805 | | gop.key_ptr.* = new_module_func; |
| 4806 | | { |
| 4807 | | errdefer gpa.destroy(new_module_func); |
| 4808 | | const remove_adapter: GenericRemoveAdapter = .{ |
| 4809 | | .precomputed_hash = precomputed_hash, |
| 4810 | | }; |
| 4811 | | errdefer assert(mod.monomorphed_funcs.removeAdapted(new_module_func, remove_adapter)); |
| 4812 | | |
| 4813 | | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); |
| 4814 | | |
| 4815 | | // Create a Decl for the new function. |
| 4816 | | const src_decl = namespace.getDecl(); |
| 4817 | | // TODO better names for generic function instantiations |
| 4818 | | const name_index = mod.getNextAnonNameIndex(); |
| 4819 | | const decl_name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{ |
| 4820 | | module_fn.owner_decl.name, name_index, |
| 4821 | | }); |
| 4822 | | const new_decl = try mod.allocateNewDecl(decl_name, namespace, module_fn.owner_decl.src_node, src_decl.src_scope); |
| 4823 | | new_decl.src_line = module_fn.owner_decl.src_line; |
| 4824 | | new_decl.is_pub = module_fn.owner_decl.is_pub; |
| 4825 | | new_decl.is_exported = module_fn.owner_decl.is_exported; |
| 4826 | | new_decl.has_align = module_fn.owner_decl.has_align; |
| 4827 | | new_decl.has_linksection_or_addrspace = module_fn.owner_decl.has_linksection_or_addrspace; |
| 4828 | | new_decl.@"addrspace" = module_fn.owner_decl.@"addrspace"; |
| 4829 | | new_decl.zir_decl_index = module_fn.owner_decl.zir_decl_index; |
| 4830 | | new_decl.alive = true; // This Decl is called at runtime. |
| 4831 | | new_decl.has_tv = true; |
| 4832 | | new_decl.owns_tv = true; |
| 4833 | | new_decl.analysis = .in_progress; |
| 4834 | | new_decl.generation = mod.generation; |
| 4835 | | |
| 4836 | | namespace.anon_decls.putAssumeCapacityNoClobber(new_decl, {}); |
| 4837 | | |
| 4838 | | // The generic function Decl is guaranteed to be the first dependency |
| 4839 | | // of each of its instantiations. |
| 4840 | | assert(new_decl.dependencies.keys().len == 0); |
| 4841 | | try mod.declareDeclDependency(new_decl, module_fn.owner_decl); |
| 4842 | | |
| 4843 | | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); |
| 4844 | | errdefer new_decl_arena.deinit(); |
| 4845 | | const new_decl_arena_allocator = new_decl_arena.allocator(); |
| 4846 | | |
| 4847 | | // Re-run the block that creates the function, with the comptime parameters |
| 4848 | | // pre-populated inside `inst_map`. This causes `param_comptime` and |
| 4849 | | // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a |
| 4850 | | // new, monomorphized function, with the comptime parameters elided. |
| 4851 | | var child_sema: Sema = .{ |
| 4852 | | .mod = mod, |
| 4853 | | .gpa = gpa, |
| 4854 | | .arena = sema.arena, |
| 4855 | | .perm_arena = new_decl_arena_allocator, |
| 4856 | | .code = fn_zir, |
| 4857 | | .owner_decl = new_decl, |
| 4858 | | .func = null, |
| 4859 | | .fn_ret_ty = Type.void, |
| 4860 | | .owner_func = null, |
| 4861 | | .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len), |
| 4862 | | .comptime_args_fn_inst = module_fn.zir_body_inst, |
| 4863 | | .preallocated_new_func = new_module_func, |
| 4864 | | }; |
| 4865 | | defer child_sema.deinit(); |
| 4866 | | |
| 4867 | | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope); |
| 4868 | | defer wip_captures.deinit(); |
| 4869 | | |
| 4870 | | var child_block: Block = .{ |
| 4871 | | .parent = null, |
| 4872 | | .sema = &child_sema, |
| 4873 | | .src_decl = new_decl, |
| 4874 | | .namespace = namespace, |
| 4875 | | .wip_capture_scope = wip_captures.scope, |
| 4876 | | .instructions = .{}, |
| 4877 | | .inlining = null, |
| 4878 | | .is_comptime = true, |
| 4879 | | }; |
| 4880 | | defer { |
| 4881 | | child_block.instructions.deinit(gpa); |
| 4882 | | child_block.params.deinit(gpa); |
| 4883 | | } |
| 4884 | | |
| 4885 | | try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, uncasted_args.len)); |
| 4886 | | var arg_i: usize = 0; |
| 4887 | | for (fn_info.param_body) |inst| { |
| 4888 | | var is_comptime = false; |
| 4889 | | var is_anytype = false; |
| 4890 | | switch (zir_tags[inst]) { |
| 4891 | | .param => { |
| 4892 | | is_comptime = func_ty_info.paramIsComptime(arg_i); |
| 4893 | | }, |
| 4894 | | .param_comptime => { |
| 4895 | | is_comptime = true; |
| 4896 | | }, |
| 4897 | | .param_anytype => { |
| 4898 | | is_anytype = true; |
| 4899 | | is_comptime = func_ty_info.paramIsComptime(arg_i); |
| 4900 | | }, |
| 4901 | | .param_anytype_comptime => { |
| 4902 | | is_anytype = true; |
| 4903 | | is_comptime = true; |
| 4904 | | }, |
| 4905 | | else => continue, |
| 4906 | | } |
| 4907 | | const arg_src = call_src; // TODO: better source location |
| 4908 | | const arg = uncasted_args[arg_i]; |
| 4909 | | if (is_comptime) { |
| 4910 | | if (try sema.resolveMaybeUndefVal(block, arg_src, arg)) |arg_val| { |
| 4911 | | const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val); |
| 4912 | | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| 4913 | | } else { |
| 4914 | | return sema.failWithNeededComptime(block, arg_src); |
| 4915 | | } |
| 4916 | | } else if (is_anytype) { |
| 4917 | | const arg_ty = sema.typeOf(arg); |
| 4918 | | if (try sema.typeRequiresComptime(block, arg_src, arg_ty)) { |
| 4919 | | const arg_val = try sema.resolveConstValue(block, arg_src, arg); |
| 4920 | | const child_arg = try child_sema.addConstant(arg_ty, arg_val); |
| 4921 | | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| 4922 | | } else { |
| 4923 | | // We insert into the map an instruction which is runtime-known |
| 4924 | | // but has the type of the argument. |
| 4925 | | const child_arg = try child_block.addArg(arg_ty); |
| 4926 | | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| 4927 | | } |
| 4928 | | } |
| 4929 | | arg_i += 1; |
| 4930 | | } |
| 4931 | | const new_func_inst = child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst) catch |err| { |
| 4932 | | // TODO look up the compile error that happened here and attach a note to it |
| 4933 | | // pointing here, at the generic instantiation callsite. |
| 4934 | | if (sema.owner_func) |owner_func| { |
| 4935 | | owner_func.state = .dependency_failure; |
| 4936 | | } else { |
| 4937 | | sema.owner_decl.analysis = .dependency_failure; |
| 4938 | | } |
| 4939 | | return err; |
| 4940 | | }; |
| 4941 | | const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst) catch unreachable; |
| 4942 | | const new_func = new_func_val.castTag(.function).?.data; |
| 4943 | | assert(new_func == new_module_func); |
| 4944 | | |
| 4945 | | arg_i = 0; |
| 4946 | | for (fn_info.param_body) |inst| { |
| 4947 | | switch (zir_tags[inst]) { |
| 4948 | | .param_comptime, .param_anytype_comptime, .param, .param_anytype => {}, |
| 4949 | | else => continue, |
| 4950 | | } |
| 4951 | | const arg = child_sema.inst_map.get(inst).?; |
| 4952 | | const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator); |
| 4953 | | if (child_sema.resolveMaybeUndefValAllowVariables( |
| 4954 | | &child_block, |
| 4955 | | .unneeded, |
| 4956 | | arg, |
| 4957 | | ) catch unreachable) |arg_val| { |
| 4958 | | child_sema.comptime_args[arg_i] = .{ |
| 4959 | | .ty = copied_arg_ty, |
| 4960 | | .val = try arg_val.copy(new_decl_arena_allocator), |
| 4961 | | }; |
| 4962 | | } else { |
| 4963 | | child_sema.comptime_args[arg_i] = .{ |
| 4964 | | .ty = copied_arg_ty, |
| 4965 | | .val = Value.initTag(.generic_poison), |
| 4966 | | }; |
| 4967 | | } |
| 4968 | | |
| 4969 | | arg_i += 1; |
| 4970 | | } |
| 4971 | | |
| 4972 | | try wip_captures.finalize(); |
| 4973 | | |
| 4974 | | // Populate the Decl ty/val with the function and its type. |
| 4975 | | new_decl.ty = try child_sema.typeOf(new_func_inst).copy(new_decl_arena_allocator); |
| 4976 | | new_decl.val = try Value.Tag.function.create(new_decl_arena_allocator, new_func); |
| 4977 | | new_decl.analysis = .complete; |
| 4978 | | |
| 4979 | | log.debug("generic function '{s}' instantiated with type {}", .{ |
| 4980 | | new_decl.name, new_decl.ty, |
| 4981 | | }); |
| 4982 | | assert(!new_decl.ty.fnInfo().is_generic); |
| 4983 | | |
| 4984 | | // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field |
| 4985 | | // will be populated, ensuring it will have `analyzeBody` called with the ZIR |
| 4986 | | // parameters mapped appropriately. |
| 4987 | | try mod.comp.bin_file.allocateDeclIndexes(new_decl); |
| 4988 | | try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func }); |
| 4989 | | |
| 4990 | | try new_decl.finalizeNewArena(&new_decl_arena); |
| 4991 | | } |
| 4992 | | |
| 4993 | | break :res try sema.finishGenericCall( |
| 4994 | | block, |
| 4995 | | call_src, |
| 4996 | | new_module_func, |
| 4997 | | func_src, |
| 4998 | | uncasted_args, |
| 4999 | | fn_info, |
| 5000 | | zir_tags, |
| 5001 | | ); |
| 5002 | 4749 | } else res: { |
| 4750 | assert(!func_ty_info.is_generic); |
| 5003 | 4751 | try sema.requireRuntimeBlock(block, call_src); |
| 5004 | 4752 | |
| 5005 | 4753 | const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len); |
| ... | ... | @@ -5037,16 +4785,274 @@ fn analyzeCall( |
| 5037 | 4785 | return result; |
| 5038 | 4786 | } |
| 5039 | 4787 | |
| 5040 | | fn finishGenericCall( |
| 4788 | fn instantiateGenericCall( |
| 5041 | 4789 | sema: *Sema, |
| 5042 | 4790 | block: *Block, |
| 5043 | | call_src: LazySrcLoc, |
| 5044 | | callee: *Module.Fn, |
| 4791 | func: Air.Inst.Ref, |
| 5045 | 4792 | func_src: LazySrcLoc, |
| 4793 | call_src: LazySrcLoc, |
| 4794 | func_ty_info: Type.Payload.Function.Data, |
| 4795 | ensure_result_used: bool, |
| 5046 | 4796 | uncasted_args: []const Air.Inst.Ref, |
| 5047 | | fn_info: Zir.FnInfo, |
| 5048 | | zir_tags: []const Zir.Inst.Tag, |
| 5049 | 4797 | ) CompileError!Air.Inst.Ref { |
| 4798 | const mod = sema.mod; |
| 4799 | const gpa = sema.gpa; |
| 4800 | |
| 4801 | const func_val = try sema.resolveConstValue(block, func_src, func); |
| 4802 | const module_fn = switch (func_val.tag()) { |
| 4803 | .function => func_val.castTag(.function).?.data, |
| 4804 | .decl_ref => func_val.castTag(.decl_ref).?.data.val.castTag(.function).?.data, |
| 4805 | else => unreachable, |
| 4806 | }; |
| 4807 | // Check the Module's generic function map with an adapted context, so that we |
| 4808 | // can match against `uncasted_args` rather than doing the work below to create a |
| 4809 | // generic Scope only to junk it if it matches an existing instantiation. |
| 4810 | const namespace = module_fn.owner_decl.src_namespace; |
| 4811 | const fn_zir = namespace.file_scope.zir; |
| 4812 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); |
| 4813 | const zir_tags = fn_zir.instructions.items(.tag); |
| 4814 | |
| 4815 | // This hash must match `Module.MonomorphedFuncsContext.hash`. |
| 4816 | // For parameters explicitly marked comptime and simple parameter type expressions, |
| 4817 | // we know whether a parameter is elided from a monomorphed function, and can |
| 4818 | // use it in the hash here. However, for parameter type expressions that are not |
| 4819 | // explicitly marked comptime and rely on previous parameter comptime values, we |
| 4820 | // don't find out until after generating a monomorphed function whether the parameter |
| 4821 | // type ended up being a "must-be-comptime-known" type. |
| 4822 | var hasher = std.hash.Wyhash.init(0); |
| 4823 | std.hash.autoHash(&hasher, @ptrToInt(module_fn)); |
| 4824 | |
| 4825 | const comptime_tvs = try sema.arena.alloc(TypedValue, func_ty_info.param_types.len); |
| 4826 | |
| 4827 | for (func_ty_info.param_types) |param_ty, i| { |
| 4828 | const is_comptime = func_ty_info.paramIsComptime(i); |
| 4829 | if (is_comptime) { |
| 4830 | const arg_src = call_src; // TODO better source location |
| 4831 | const casted_arg = try sema.coerce(block, param_ty, uncasted_args[i], arg_src); |
| 4832 | if (try sema.resolveMaybeUndefVal(block, arg_src, casted_arg)) |arg_val| { |
| 4833 | if (param_ty.tag() != .generic_poison) { |
| 4834 | arg_val.hash(param_ty, &hasher); |
| 4835 | } |
| 4836 | comptime_tvs[i] = .{ |
| 4837 | // This will be different than `param_ty` in the case of `generic_poison`. |
| 4838 | .ty = sema.typeOf(casted_arg), |
| 4839 | .val = arg_val, |
| 4840 | }; |
| 4841 | } else { |
| 4842 | return sema.failWithNeededComptime(block, arg_src); |
| 4843 | } |
| 4844 | } else { |
| 4845 | comptime_tvs[i] = .{ |
| 4846 | .ty = sema.typeOf(uncasted_args[i]), |
| 4847 | .val = Value.initTag(.generic_poison), |
| 4848 | }; |
| 4849 | } |
| 4850 | } |
| 4851 | |
| 4852 | const precomputed_hash = hasher.final(); |
| 4853 | |
| 4854 | const adapter: GenericCallAdapter = .{ |
| 4855 | .generic_fn = module_fn, |
| 4856 | .precomputed_hash = precomputed_hash, |
| 4857 | .func_ty_info = func_ty_info, |
| 4858 | .comptime_tvs = comptime_tvs, |
| 4859 | }; |
| 4860 | const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter); |
| 4861 | if (!gop.found_existing) { |
| 4862 | const new_module_func = try gpa.create(Module.Fn); |
| 4863 | gop.key_ptr.* = new_module_func; |
| 4864 | errdefer gpa.destroy(new_module_func); |
| 4865 | const remove_adapter: GenericRemoveAdapter = .{ |
| 4866 | .precomputed_hash = precomputed_hash, |
| 4867 | }; |
| 4868 | errdefer assert(mod.monomorphed_funcs.removeAdapted(new_module_func, remove_adapter)); |
| 4869 | |
| 4870 | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); |
| 4871 | |
| 4872 | // Create a Decl for the new function. |
| 4873 | const src_decl = namespace.getDecl(); |
| 4874 | // TODO better names for generic function instantiations |
| 4875 | const name_index = mod.getNextAnonNameIndex(); |
| 4876 | const decl_name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{ |
| 4877 | module_fn.owner_decl.name, name_index, |
| 4878 | }); |
| 4879 | const new_decl = try mod.allocateNewDecl(decl_name, namespace, module_fn.owner_decl.src_node, src_decl.src_scope); |
| 4880 | errdefer new_decl.destroy(mod); |
| 4881 | new_decl.src_line = module_fn.owner_decl.src_line; |
| 4882 | new_decl.is_pub = module_fn.owner_decl.is_pub; |
| 4883 | new_decl.is_exported = module_fn.owner_decl.is_exported; |
| 4884 | new_decl.has_align = module_fn.owner_decl.has_align; |
| 4885 | new_decl.has_linksection_or_addrspace = module_fn.owner_decl.has_linksection_or_addrspace; |
| 4886 | new_decl.@"addrspace" = module_fn.owner_decl.@"addrspace"; |
| 4887 | new_decl.zir_decl_index = module_fn.owner_decl.zir_decl_index; |
| 4888 | new_decl.alive = true; // This Decl is called at runtime. |
| 4889 | new_decl.analysis = .in_progress; |
| 4890 | new_decl.generation = mod.generation; |
| 4891 | |
| 4892 | namespace.anon_decls.putAssumeCapacityNoClobber(new_decl, {}); |
| 4893 | errdefer assert(namespace.anon_decls.orderedRemove(new_decl)); |
| 4894 | |
| 4895 | // The generic function Decl is guaranteed to be the first dependency |
| 4896 | // of each of its instantiations. |
| 4897 | assert(new_decl.dependencies.keys().len == 0); |
| 4898 | try mod.declareDeclDependency(new_decl, module_fn.owner_decl); |
| 4899 | errdefer assert(module_fn.owner_decl.dependants.orderedRemove(new_decl)); |
| 4900 | |
| 4901 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); |
| 4902 | errdefer new_decl_arena.deinit(); |
| 4903 | const new_decl_arena_allocator = new_decl_arena.allocator(); |
| 4904 | |
| 4905 | // Re-run the block that creates the function, with the comptime parameters |
| 4906 | // pre-populated inside `inst_map`. This causes `param_comptime` and |
| 4907 | // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a |
| 4908 | // new, monomorphized function, with the comptime parameters elided. |
| 4909 | var child_sema: Sema = .{ |
| 4910 | .mod = mod, |
| 4911 | .gpa = gpa, |
| 4912 | .arena = sema.arena, |
| 4913 | .perm_arena = new_decl_arena_allocator, |
| 4914 | .code = fn_zir, |
| 4915 | .owner_decl = new_decl, |
| 4916 | .func = null, |
| 4917 | .fn_ret_ty = Type.void, |
| 4918 | .owner_func = null, |
| 4919 | .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len), |
| 4920 | .comptime_args_fn_inst = module_fn.zir_body_inst, |
| 4921 | .preallocated_new_func = new_module_func, |
| 4922 | }; |
| 4923 | defer child_sema.deinit(); |
| 4924 | |
| 4925 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope); |
| 4926 | defer wip_captures.deinit(); |
| 4927 | |
| 4928 | var child_block: Block = .{ |
| 4929 | .parent = null, |
| 4930 | .sema = &child_sema, |
| 4931 | .src_decl = new_decl, |
| 4932 | .namespace = namespace, |
| 4933 | .wip_capture_scope = wip_captures.scope, |
| 4934 | .instructions = .{}, |
| 4935 | .inlining = null, |
| 4936 | .is_comptime = true, |
| 4937 | }; |
| 4938 | defer { |
| 4939 | child_block.instructions.deinit(gpa); |
| 4940 | child_block.params.deinit(gpa); |
| 4941 | } |
| 4942 | |
| 4943 | try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, uncasted_args.len)); |
| 4944 | var arg_i: usize = 0; |
| 4945 | for (fn_info.param_body) |inst| { |
| 4946 | var is_comptime = false; |
| 4947 | var is_anytype = false; |
| 4948 | switch (zir_tags[inst]) { |
| 4949 | .param => { |
| 4950 | is_comptime = func_ty_info.paramIsComptime(arg_i); |
| 4951 | }, |
| 4952 | .param_comptime => { |
| 4953 | is_comptime = true; |
| 4954 | }, |
| 4955 | .param_anytype => { |
| 4956 | is_anytype = true; |
| 4957 | is_comptime = func_ty_info.paramIsComptime(arg_i); |
| 4958 | }, |
| 4959 | .param_anytype_comptime => { |
| 4960 | is_anytype = true; |
| 4961 | is_comptime = true; |
| 4962 | }, |
| 4963 | else => continue, |
| 4964 | } |
| 4965 | const arg_src = call_src; // TODO: better source location |
| 4966 | const arg = uncasted_args[arg_i]; |
| 4967 | if (is_comptime) { |
| 4968 | if (try sema.resolveMaybeUndefVal(block, arg_src, arg)) |arg_val| { |
| 4969 | const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val); |
| 4970 | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| 4971 | } else { |
| 4972 | return sema.failWithNeededComptime(block, arg_src); |
| 4973 | } |
| 4974 | } else if (is_anytype) { |
| 4975 | const arg_ty = sema.typeOf(arg); |
| 4976 | if (try sema.typeRequiresComptime(block, arg_src, arg_ty)) { |
| 4977 | const arg_val = try sema.resolveConstValue(block, arg_src, arg); |
| 4978 | const child_arg = try child_sema.addConstant(arg_ty, arg_val); |
| 4979 | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| 4980 | } else { |
| 4981 | // We insert into the map an instruction which is runtime-known |
| 4982 | // but has the type of the argument. |
| 4983 | const child_arg = try child_block.addArg(arg_ty); |
| 4984 | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| 4985 | } |
| 4986 | } |
| 4987 | arg_i += 1; |
| 4988 | } |
| 4989 | const new_func_inst = child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst) catch |err| { |
| 4990 | // TODO look up the compile error that happened here and attach a note to it |
| 4991 | // pointing here, at the generic instantiation callsite. |
| 4992 | if (sema.owner_func) |owner_func| { |
| 4993 | owner_func.state = .dependency_failure; |
| 4994 | } else { |
| 4995 | sema.owner_decl.analysis = .dependency_failure; |
| 4996 | } |
| 4997 | return err; |
| 4998 | }; |
| 4999 | const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst) catch unreachable; |
| 5000 | const new_func = new_func_val.castTag(.function).?.data; |
| 5001 | assert(new_func == new_module_func); |
| 5002 | |
| 5003 | arg_i = 0; |
| 5004 | for (fn_info.param_body) |inst| { |
| 5005 | switch (zir_tags[inst]) { |
| 5006 | .param_comptime, .param_anytype_comptime, .param, .param_anytype => {}, |
| 5007 | else => continue, |
| 5008 | } |
| 5009 | const arg = child_sema.inst_map.get(inst).?; |
| 5010 | const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator); |
| 5011 | if (child_sema.resolveMaybeUndefValAllowVariables( |
| 5012 | &child_block, |
| 5013 | .unneeded, |
| 5014 | arg, |
| 5015 | ) catch unreachable) |arg_val| { |
| 5016 | child_sema.comptime_args[arg_i] = .{ |
| 5017 | .ty = copied_arg_ty, |
| 5018 | .val = try arg_val.copy(new_decl_arena_allocator), |
| 5019 | }; |
| 5020 | } else { |
| 5021 | child_sema.comptime_args[arg_i] = .{ |
| 5022 | .ty = copied_arg_ty, |
| 5023 | .val = Value.initTag(.generic_poison), |
| 5024 | }; |
| 5025 | } |
| 5026 | |
| 5027 | arg_i += 1; |
| 5028 | } |
| 5029 | |
| 5030 | try wip_captures.finalize(); |
| 5031 | |
| 5032 | // Populate the Decl ty/val with the function and its type. |
| 5033 | new_decl.ty = try child_sema.typeOf(new_func_inst).copy(new_decl_arena_allocator); |
| 5034 | // If the call evaluated to a generic type return errror and call inline. |
| 5035 | if (new_decl.ty.fnInfo().is_generic) return error.GenericPoison; |
| 5036 | |
| 5037 | new_decl.val = try Value.Tag.function.create(new_decl_arena_allocator, new_func); |
| 5038 | new_decl.has_tv = true; |
| 5039 | new_decl.owns_tv = true; |
| 5040 | new_decl.analysis = .complete; |
| 5041 | |
| 5042 | log.debug("generic function '{s}' instantiated with type {}", .{ |
| 5043 | new_decl.name, new_decl.ty, |
| 5044 | }); |
| 5045 | |
| 5046 | // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field |
| 5047 | // will be populated, ensuring it will have `analyzeBody` called with the ZIR |
| 5048 | // parameters mapped appropriately. |
| 5049 | try mod.comp.bin_file.allocateDeclIndexes(new_decl); |
| 5050 | try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func }); |
| 5051 | |
| 5052 | try new_decl.finalizeNewArena(&new_decl_arena); |
| 5053 | } |
| 5054 | |
| 5055 | const callee = gop.key_ptr.*; |
| 5050 | 5056 | const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl); |
| 5051 | 5057 | |
| 5052 | 5058 | // Make a runtime call to the new function, making sure to omit the comptime args. |
| ... | ... | @@ -5106,6 +5112,10 @@ fn finishGenericCall( |
| 5106 | 5112 | } }, |
| 5107 | 5113 | }); |
| 5108 | 5114 | sema.appendRefsAssumeCapacity(runtime_args); |
| 5115 | |
| 5116 | if (ensure_result_used) { |
| 5117 | try sema.ensureResultUsed(block, func_inst, call_src); |
| 5118 | } |
| 5109 | 5119 | return func_inst; |
| 5110 | 5120 | } |
| 5111 | 5121 | |
| ... | ... | @@ -11664,18 +11674,25 @@ fn zirStructInit( |
| 11664 | 11674 | const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); |
| 11665 | 11675 | const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src); |
| 11666 | 11676 | |
| 11667 | | if (is_ref) { |
| 11668 | | return sema.fail(block, src, "TODO: Sema.zirStructInit is_ref=true union", .{}); |
| 11669 | | } |
| 11670 | | |
| 11671 | 11677 | const init_inst = sema.resolveInst(item.data.init); |
| 11672 | 11678 | if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| { |
| 11673 | 11679 | const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); |
| 11674 | | return sema.addConstant( |
| 11680 | return sema.addConstantMaybeRef( |
| 11681 | block, |
| 11682 | src, |
| 11675 | 11683 | resolved_ty, |
| 11676 | 11684 | try Value.Tag.@"union".create(sema.arena, .{ .tag = tag_val, .val = val }), |
| 11685 | is_ref, |
| 11677 | 11686 | ); |
| 11678 | 11687 | } |
| 11688 | |
| 11689 | if (is_ref) { |
| 11690 | const alloc = try block.addTy(.alloc, resolved_ty); |
| 11691 | const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty); |
| 11692 | try sema.storePtr(block, src, field_ptr, init_inst); |
| 11693 | return alloc; |
| 11694 | } |
| 11695 | |
| 11679 | 11696 | return sema.fail(block, src, "TODO: Sema.zirStructInit for runtime-known union values", .{}); |
| 11680 | 11697 | } |
| 11681 | 11698 | unreachable; |
| ... | ... | @@ -16033,7 +16050,6 @@ fn coerce( |
| 16033 | 16050 | }, |
| 16034 | 16051 | .Pointer => p: { |
| 16035 | 16052 | const inst_info = inst_ty.ptrInfo().data; |
| 16036 | | if (inst_info.size == .Slice) break :p; |
| 16037 | 16053 | switch (try sema.coerceInMemoryAllowed( |
| 16038 | 16054 | block, |
| 16039 | 16055 | dest_info.pointee_type, |
| ... | ... | @@ -16046,6 +16062,14 @@ fn coerce( |
| 16046 | 16062 | .ok => {}, |
| 16047 | 16063 | .no_match => break :p, |
| 16048 | 16064 | } |
| 16065 | if (inst_info.size == .Slice) { |
| 16066 | if (dest_info.sentinel == null or inst_info.sentinel == null or |
| 16067 | !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type)) |
| 16068 | break :p; |
| 16069 | |
| 16070 | const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); |
| 16071 | return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src); |
| 16072 | } |
| 16049 | 16073 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| 16050 | 16074 | }, |
| 16051 | 16075 | else => {}, |
| ... | ... | @@ -16089,7 +16113,30 @@ fn coerce( |
| 16089 | 16113 | return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src); |
| 16090 | 16114 | } |
| 16091 | 16115 | }, |
| 16092 | | .Many => {}, |
| 16116 | .Many => p: { |
| 16117 | const inst_info = inst_ty.ptrInfo().data; |
| 16118 | if (inst_info.size != .Slice) break :p; |
| 16119 | |
| 16120 | switch (try sema.coerceInMemoryAllowed( |
| 16121 | block, |
| 16122 | dest_info.pointee_type, |
| 16123 | inst_info.pointee_type, |
| 16124 | dest_info.mutable, |
| 16125 | target, |
| 16126 | dest_ty_src, |
| 16127 | inst_src, |
| 16128 | )) { |
| 16129 | .ok => {}, |
| 16130 | .no_match => break :p, |
| 16131 | } |
| 16132 | |
| 16133 | if (dest_info.sentinel == null or inst_info.sentinel == null or |
| 16134 | !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type)) |
| 16135 | break :p; |
| 16136 | |
| 16137 | const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); |
| 16138 | return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src); |
| 16139 | }, |
| 16093 | 16140 | } |
| 16094 | 16141 | |
| 16095 | 16142 | // This will give an extra hint on top of what the bottom of this func would provide. |