authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-10 15:10:51-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-10 15:10:51-05:00
log0b82c02945c69e2e0465b5a4d9de471ea3c76d50
treed587e1fe27e50a8913d3ea33038278d49c9f6579
parent8bab1b405f0b398a7e98e373f9d0cc26cb8496a6
parentf9e4344bb51c70aa9959680f3dfc9d7712858395
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11113 from Vexu/stage2

stage2: if generic function evaluates to another generic function call it inline

5 files changed, 366 insertions(+), 301 deletions(-)

src/Sema.zig+332-285
......@@ -3995,7 +3995,7 @@ pub fn analyzeExport(
39953995 try mod.ensureDeclAnalyzed(exported_decl);
39963996 // TODO run the same checks as we do for C ABI struct fields
39973997 switch (exported_decl.ty.zigTypeTag()) {
3998 .Fn, .Int, .Struct, .Array, .Float => {},
3998 .Fn, .Int, .Enum, .Struct, .Union, .Array, .Float => {},
39993999 else => return sema.fail(block, src, "unable to export type '{}'", .{exported_decl.ty}),
40004000 }
40014001
......@@ -4474,8 +4474,26 @@ fn analyzeCall(
44744474
44754475 const is_comptime_call = block.is_comptime or modifier == .compile_time or
44764476 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
44784478 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
44794497 const result: Air.Inst.Ref = if (is_inline_call) res: {
44804498 const func_val = try sema.resolveConstValue(block, func_src, func);
44814499 const module_fn = switch (func_val.tag()) {
......@@ -4728,278 +4746,8 @@ fn analyzeCall(
47284746 try wip_captures.finalize();
47294747
47304748 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 );
50024749 } else res: {
4750 assert(!func_ty_info.is_generic);
50034751 try sema.requireRuntimeBlock(block, call_src);
50044752
50054753 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
......@@ -5037,16 +4785,274 @@ fn analyzeCall(
50374785 return result;
50384786}
50394787
5040fn finishGenericCall(
4788fn instantiateGenericCall(
50414789 sema: *Sema,
50424790 block: *Block,
5043 call_src: LazySrcLoc,
5044 callee: *Module.Fn,
4791 func: Air.Inst.Ref,
50454792 func_src: LazySrcLoc,
4793 call_src: LazySrcLoc,
4794 func_ty_info: Type.Payload.Function.Data,
4795 ensure_result_used: bool,
50464796 uncasted_args: []const Air.Inst.Ref,
5047 fn_info: Zir.FnInfo,
5048 zir_tags: []const Zir.Inst.Tag,
50494797) 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.*;
50505056 const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
50515057
50525058 // Make a runtime call to the new function, making sure to omit the comptime args.
......@@ -5106,6 +5112,10 @@ fn finishGenericCall(
51065112 } },
51075113 });
51085114 sema.appendRefsAssumeCapacity(runtime_args);
5115
5116 if (ensure_result_used) {
5117 try sema.ensureResultUsed(block, func_inst, call_src);
5118 }
51095119 return func_inst;
51105120}
51115121
......@@ -11664,18 +11674,25 @@ fn zirStructInit(
1166411674 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
1166511675 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
1166611676
11667 if (is_ref) {
11668 return sema.fail(block, src, "TODO: Sema.zirStructInit is_ref=true union", .{});
11669 }
11670
1167111677 const init_inst = sema.resolveInst(item.data.init);
1167211678 if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| {
1167311679 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,
1167511683 resolved_ty,
1167611684 try Value.Tag.@"union".create(sema.arena, .{ .tag = tag_val, .val = val }),
11685 is_ref,
1167711686 );
1167811687 }
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
1167911696 return sema.fail(block, src, "TODO: Sema.zirStructInit for runtime-known union values", .{});
1168011697 }
1168111698 unreachable;
......@@ -16033,7 +16050,6 @@ fn coerce(
1603316050 },
1603416051 .Pointer => p: {
1603516052 const inst_info = inst_ty.ptrInfo().data;
16036 if (inst_info.size == .Slice) break :p;
1603716053 switch (try sema.coerceInMemoryAllowed(
1603816054 block,
1603916055 dest_info.pointee_type,
......@@ -16046,6 +16062,14 @@ fn coerce(
1604616062 .ok => {},
1604716063 .no_match => break :p,
1604816064 }
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 }
1604916073 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
1605016074 },
1605116075 else => {},
......@@ -16089,7 +16113,30 @@ fn coerce(
1608916113 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
1609016114 }
1609116115 },
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 },
1609316140 }
1609416141
1609516142 // This will give an extra hint on top of what the bottom of this func would provide.
src/codegen/llvm.zig+25-7
......@@ -1472,12 +1472,12 @@ pub const DeclGen = struct {
14721472 return llvm_int.constIntToPtr(try dg.llvmType(tv.ty));
14731473 },
14741474 .field_ptr, .opt_payload_ptr, .eu_payload_ptr => {
1475 const parent = try dg.lowerParentPtr(tv.val);
1475 const parent = try dg.lowerParentPtr(tv.val, tv.ty);
14761476 return parent.llvm_ptr.constBitCast(try dg.llvmType(tv.ty));
14771477 },
14781478 .elem_ptr => {
14791479 const elem_ptr = tv.val.castTag(.elem_ptr).?.data;
1480 const parent = try dg.lowerParentPtr(elem_ptr.array_ptr);
1480 const parent = try dg.lowerParentPtr(elem_ptr.array_ptr, tv.ty);
14811481 const llvm_usize = try dg.llvmType(Type.usize);
14821482 if (parent.llvm_ptr.typeOf().getElementType().getTypeKind() == .Array) {
14831483 const indices: [2]*const llvm.Value = .{
......@@ -2683,7 +2683,7 @@ pub const DeclGen = struct {
26832683 };
26842684 }
26852685
2686 fn lowerParentPtr(dg: *DeclGen, ptr_val: Value) Error!ParentPtr {
2686 fn lowerParentPtr(dg: *DeclGen, ptr_val: Value, base_ty: Type) Error!ParentPtr {
26872687 switch (ptr_val.tag()) {
26882688 .decl_ref_mut => {
26892689 const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl;
......@@ -2697,9 +2697,27 @@ pub const DeclGen = struct {
26972697 const decl = ptr_val.castTag(.variable).?.data.owner_decl;
26982698 return dg.lowerParentPtrDecl(ptr_val, decl);
26992699 },
2700 .int_i64 => {
2701 const int = ptr_val.castTag(.int_i64).?.data;
2702 const llvm_usize = try dg.llvmType(Type.usize);
2703 const llvm_int = llvm_usize.constInt(@bitCast(u64, int), .False);
2704 return ParentPtr{
2705 .llvm_ptr = llvm_int.constIntToPtr(try dg.llvmType(base_ty)),
2706 .ty = base_ty,
2707 };
2708 },
2709 .int_u64 => {
2710 const int = ptr_val.castTag(.int_u64).?.data;
2711 const llvm_usize = try dg.llvmType(Type.usize);
2712 const llvm_int = llvm_usize.constInt(int, .False);
2713 return ParentPtr{
2714 .llvm_ptr = llvm_int.constIntToPtr(try dg.llvmType(base_ty)),
2715 .ty = base_ty,
2716 };
2717 },
27002718 .field_ptr => {
27012719 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
2702 const parent = try dg.lowerParentPtr(field_ptr.container_ptr);
2720 const parent = try dg.lowerParentPtr(field_ptr.container_ptr, base_ty);
27032721 const field_index = @intCast(u32, field_ptr.field_index);
27042722 const llvm_u32 = dg.context.intType(32);
27052723 const target = dg.module.getTarget();
......@@ -2753,7 +2771,7 @@ pub const DeclGen = struct {
27532771 },
27542772 .elem_ptr => {
27552773 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
2756 const parent = try dg.lowerParentPtr(elem_ptr.array_ptr);
2774 const parent = try dg.lowerParentPtr(elem_ptr.array_ptr, base_ty);
27572775 const llvm_usize = try dg.llvmType(Type.usize);
27582776 const indices: [2]*const llvm.Value = .{
27592777 llvm_usize.constInt(0, .False),
......@@ -2766,7 +2784,7 @@ pub const DeclGen = struct {
27662784 },
27672785 .opt_payload_ptr => {
27682786 const opt_payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
2769 const parent = try dg.lowerParentPtr(opt_payload_ptr);
2787 const parent = try dg.lowerParentPtr(opt_payload_ptr, base_ty);
27702788 var buf: Type.Payload.ElemType = undefined;
27712789 const payload_ty = parent.ty.optionalChild(&buf);
27722790 if (!payload_ty.hasRuntimeBits() or parent.ty.isPtrLikeOptional()) {
......@@ -2790,7 +2808,7 @@ pub const DeclGen = struct {
27902808 },
27912809 .eu_payload_ptr => {
27922810 const eu_payload_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;
2793 const parent = try dg.lowerParentPtr(eu_payload_ptr);
2811 const parent = try dg.lowerParentPtr(eu_payload_ptr, base_ty);
27942812 const payload_ty = parent.ty.errorUnionPayload();
27952813 if (!payload_ty.hasRuntimeBits()) {
27962814 // In this case, we represent pointer to error union the same as pointer
test/behavior.zig+4-4
......@@ -57,6 +57,7 @@ test {
5757 _ = @import("behavior/bugs/5487.zig");
5858 _ = @import("behavior/bugs/6850.zig");
5959 _ = @import("behavior/bugs/7003.zig");
60 _ = @import("behavior/bugs/7047.zig");
6061 _ = @import("behavior/bugs/7250.zig");
6162 _ = @import("behavior/bugs/11100.zig");
6263 _ = @import("behavior/bugs/10970.zig");
......@@ -142,11 +143,14 @@ test {
142143 if (builtin.zig_backend != .stage2_c) {
143144 // Tests that pass for stage1 and the llvm backend.
144145 _ = @import("behavior/atomics.zig");
146 _ = @import("behavior/export.zig");
145147 _ = @import("behavior/maximum_minimum.zig");
146148 _ = @import("behavior/popcount.zig");
147149 _ = @import("behavior/saturating_arithmetic.zig");
148150 _ = @import("behavior/widening.zig");
149151 _ = @import("behavior/bugs/2114.zig");
152 _ = @import("behavior/bugs/3779.zig");
153 _ = @import("behavior/bugs/10147.zig");
150154 _ = @import("behavior/union_with_members.zig");
151155
152156 if (builtin.zig_backend == .stage1) {
......@@ -160,14 +164,10 @@ test {
160164 _ = @import("behavior/bugs/920.zig");
161165 _ = @import("behavior/bugs/1120.zig");
162166 _ = @import("behavior/bugs/1851.zig");
163 _ = @import("behavior/bugs/3779.zig");
164167 _ = @import("behavior/bugs/6456.zig");
165168 _ = @import("behavior/bugs/6781.zig");
166169 _ = @import("behavior/bugs/7027.zig");
167 _ = @import("behavior/bugs/7047.zig");
168 _ = @import("behavior/bugs/10147.zig");
169170 _ = @import("behavior/const_slice_child.zig");
170 _ = @import("behavior/export.zig");
171171 _ = @import("behavior/select.zig");
172172 _ = @import("behavior/shuffle.zig");
173173 _ = @import("behavior/struct_contains_slice_of_itself.zig");
test/behavior/bugs/3779.zig+5-2
......@@ -1,11 +1,13 @@
11const std = @import("std");
2const builtin = @import("builtin");
23
34const TestEnum = enum { TestEnumValue };
45const tag_name = @tagName(TestEnum.TestEnumValue);
56const ptr_tag_name: [*:0]const u8 = tag_name;
67
78test "@tagName() returns a string literal" {
8 try std.testing.expectEqual([:0]const u8, @TypeOf(tag_name));
9 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
10 try std.testing.expectEqual(*const [13:0]u8, @TypeOf(tag_name));
911 try std.testing.expectEqualStrings("TestEnumValue", tag_name);
1012 try std.testing.expectEqualStrings("TestEnumValue", ptr_tag_name[0..tag_name.len]);
1113}
......@@ -15,7 +17,8 @@ const error_name = @errorName(TestError.TestErrorCode);
1517const ptr_error_name: [*:0]const u8 = error_name;
1618
1719test "@errorName() returns a string literal" {
18 try std.testing.expectEqual([:0]const u8, @TypeOf(error_name));
20 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
21 try std.testing.expectEqual(*const [13:0]u8, @TypeOf(error_name));
1922 try std.testing.expectEqualStrings("TestErrorCode", error_name);
2023 try std.testing.expectEqualStrings("TestErrorCode", ptr_error_name[0..error_name.len]);
2124}
test/behavior/export.zig-3
......@@ -38,9 +38,6 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void {
3838test "exporting enum type and value" {
3939 const S = struct {
4040 const E = enum(c_int) { one, two };
41 comptime {
42 @export(E, .{ .name = "E" });
43 }
4441 const e: E = .two;
4542 comptime {
4643 @export(e, .{ .name = "e" });