authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-06-12 20:30:11-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-12 18:24:01-07:00
log3d48c406c18d6bcc579130d7cac91d47cc119dd8
treed89b8a339c355062fa2b7a86ca397131474161de
parent52e7934a21e29b5a39fa207ef29520f58e311bb0

Sema: redo monomorphed funcs to make more sense

By correctly handling comptime-only types appearing in non-comptime parameters (when the parameter is either anytype or generic), this avoids an index out of bounds later when later filling out `monomorphed_args` using what used to be slightly different logic.

1 files changed, 86 insertions(+), 94 deletions(-)

src/Sema.zig+86-94
...@@ -6748,7 +6748,7 @@ fn analyzeCall(...@@ -6748,7 +6748,7 @@ fn analyzeCall(
6748 func,6748 func,
6749 func_src,6749 func_src,
6750 call_src,6750 call_src,
6751 func_ty_info,6751 func_ty,
6752 ensure_result_used,6752 ensure_result_used,
6753 uncasted_args,6753 uncasted_args,
6754 call_tag,6754 call_tag,
...@@ -7367,8 +7367,16 @@ fn analyzeGenericCallArg(...@@ -7367,8 +7367,16 @@ fn analyzeGenericCallArg(
7367 }7367 }
7368}7368}
73697369
7370fn analyzeGenericCallArgVal(sema: *Sema, block: *Block, arg_src: LazySrcLoc, uncasted_arg: Air.Inst.Ref) !Value {7370fn analyzeGenericCallArgVal(
7371 return sema.resolveLazyValue(try sema.resolveValue(block, arg_src, uncasted_arg, "parameter is comptime"));7371 sema: *Sema,
7372 block: *Block,
7373 arg_src: LazySrcLoc,
7374 arg_ty: Type,
7375 uncasted_arg: Air.Inst.Ref,
7376 reason: []const u8,
7377) !Value {
7378 const casted_arg = try sema.coerce(block, arg_ty, uncasted_arg, arg_src);
7379 return sema.resolveLazyValue(try sema.resolveValue(block, arg_src, casted_arg, reason));
7372}7380}
73737381
7374fn instantiateGenericCall(7382fn instantiateGenericCall(
...@@ -7377,7 +7385,7 @@ fn instantiateGenericCall(...@@ -7377,7 +7385,7 @@ fn instantiateGenericCall(
7377 func: Air.Inst.Ref,7385 func: Air.Inst.Ref,
7378 func_src: LazySrcLoc,7386 func_src: LazySrcLoc,
7379 call_src: LazySrcLoc,7387 call_src: LazySrcLoc,
7380 func_ty_info: InternPool.Key.FuncType,7388 generic_func_ty: Type,
7381 ensure_result_used: bool,7389 ensure_result_used: bool,
7382 uncasted_args: []const Air.Inst.Ref,7390 uncasted_args: []const Air.Inst.Ref,
7383 call_tag: Air.Inst.Tag,7391 call_tag: Air.Inst.Tag,
...@@ -7404,24 +7412,25 @@ fn instantiateGenericCall(...@@ -7404,24 +7412,25 @@ fn instantiateGenericCall(
7404 const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst);7412 const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst);
7405 const zir_tags = fn_zir.instructions.items(.tag);7413 const zir_tags = fn_zir.instructions.items(.tag);
74067414
7407 const generic_args = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len);7415 const monomorphed_args = try sema.arena.alloc(InternPool.Index, mod.typeToFunc(generic_func_ty).?.param_types.len);
7408 const callee_index = callee: {7416 const callee_index = callee: {
7409 var arg_i: usize = 0;7417 var arg_i: usize = 0;
7410 var generic_arg_i: u32 = 0;7418 var monomorphed_arg_i: u32 = 0;
7411 var known_unique = false;7419 var known_unique = false;
7412 for (fn_info.param_body) |inst| {7420 for (fn_info.param_body) |inst| {
7421 const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?;
7413 var is_comptime = false;7422 var is_comptime = false;
7414 var is_anytype = false;7423 var is_anytype = false;
7415 switch (zir_tags[inst]) {7424 switch (zir_tags[inst]) {
7416 .param => {7425 .param => {
7417 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i));7426 is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
7418 },7427 },
7419 .param_comptime => {7428 .param_comptime => {
7420 is_comptime = true;7429 is_comptime = true;
7421 },7430 },
7422 .param_anytype => {7431 .param_anytype => {
7423 is_anytype = true;7432 is_anytype = true;
7424 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i));7433 is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
7425 },7434 },
7426 .param_anytype_comptime => {7435 .param_anytype_comptime => {
7427 is_anytype = true;7436 is_anytype = true;
...@@ -7431,69 +7440,60 @@ fn instantiateGenericCall(...@@ -7431,69 +7440,60 @@ fn instantiateGenericCall(
7431 }7440 }
74327441
7433 defer arg_i += 1;7442 defer arg_i += 1;
7443 const param_ty = generic_func_ty_info.param_types[arg_i];
7444 const is_generic = !is_anytype and param_ty == .generic_poison_type;
7445
7434 if (known_unique) {7446 if (known_unique) {
7435 if (is_comptime or is_anytype) {7447 if (is_comptime or is_anytype or is_generic) {
7436 generic_arg_i += 1;7448 monomorphed_arg_i += 1;
7437 }7449 }
7438 continue;7450 continue;
7439 }7451 }
74407452
7441 const arg_ty = sema.typeOf(uncasted_args[arg_i]);7453 const uncasted_arg = uncasted_args[arg_i];
7454 const arg_ty = if (is_generic) mod.monomorphed_funcs.getAdapted(
7455 Module.MonomorphedFuncAdaptedKey{
7456 .func = module_fn_index,
7457 .args = monomorphed_args[0..monomorphed_arg_i],
7458 },
7459 Module.MonomorphedFuncsAdaptedContext{ .mod = mod },
7460 ) orelse {
7461 known_unique = true;
7462 monomorphed_arg_i += 1;
7463 continue;
7464 } else if (is_anytype) sema.typeOf(uncasted_arg).toIntern() else param_ty;
7465 const was_comptime = is_comptime;
7466 if (!is_comptime and try sema.typeRequiresComptime(arg_ty.toType())) is_comptime = true;
7442 if (is_comptime or is_anytype) {7467 if (is_comptime or is_anytype) {
7443 // Tuple default values are a part of the type and need to be7468 // Tuple default values are a part of the type and need to be
7444 // resolved to hash the type.7469 // resolved to hash the type.
7445 try sema.resolveTupleLazyValues(block, call_src, arg_ty);7470 try sema.resolveTupleLazyValues(block, call_src, arg_ty.toType());
7446 }7471 }
74477472
7448 if (is_comptime) {7473 if (is_comptime) {
7449 const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[arg_i]) catch |err| switch (err) {7474 const casted_arg = sema.analyzeGenericCallArgVal(block, .unneeded, arg_ty.toType(), uncasted_arg, "") catch |err| switch (err) {
7450 error.NeededSourceLocation => {7475 error.NeededSourceLocation => {
7451 const decl = mod.declPtr(block.src_decl);7476 const decl = mod.declPtr(block.src_decl);
7452 const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src);7477 const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src);
7453 _ = try sema.analyzeGenericCallArgVal(block, arg_src, uncasted_args[arg_i]);7478 _ = try sema.analyzeGenericCallArgVal(
7479 block,
7480 arg_src,
7481 arg_ty.toType(),
7482 uncasted_arg,
7483 if (was_comptime)
7484 "parameter is comptime"
7485 else
7486 "argument to parameter with comptime-only type must be comptime-known",
7487 );
7454 unreachable;7488 unreachable;
7455 },7489 },
7456 else => |e| return e,7490 else => |e| return e,
7457 };7491 };
74587492 monomorphed_args[monomorphed_arg_i] = casted_arg.toIntern();
7459 if (is_anytype) {7493 monomorphed_arg_i += 1;
7460 generic_args[generic_arg_i] = arg_val.toIntern();7494 } else if (is_anytype or is_generic) {
7461 } else {7495 monomorphed_args[monomorphed_arg_i] = try mod.intern(.{ .undef = arg_ty });
7462 const final_arg_ty = mod.monomorphed_funcs.getAdapted(7496 monomorphed_arg_i += 1;
7463 Module.MonomorphedFuncAdaptedKey{
7464 .func = module_fn_index,
7465 .args = generic_args[0..generic_arg_i],
7466 },
7467 Module.MonomorphedFuncsAdaptedContext{ .mod = mod },
7468 ) orelse {
7469 known_unique = true;
7470 generic_arg_i += 1;
7471 continue;
7472 };
7473 const casted_arg = sema.coerce(block, final_arg_ty.toType(), uncasted_args[arg_i], .unneeded) catch |err| switch (err) {
7474 error.NeededSourceLocation => {
7475 const decl = mod.declPtr(block.src_decl);
7476 const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src);
7477 _ = try sema.coerce(block, final_arg_ty.toType(), uncasted_args[arg_i], arg_src);
7478 unreachable;
7479 },
7480 else => |e| return e,
7481 };
7482 const casted_arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, casted_arg) catch |err| switch (err) {
7483 error.NeededSourceLocation => {
7484 const decl = mod.declPtr(block.src_decl);
7485 const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src);
7486 _ = try sema.analyzeGenericCallArgVal(block, arg_src, casted_arg);
7487 unreachable;
7488 },
7489 else => |e| return e,
7490 };
7491 generic_args[generic_arg_i] = casted_arg_val.toIntern();
7492 }
7493 generic_arg_i += 1;
7494 } else if (is_anytype) {
7495 generic_args[generic_arg_i] = arg_ty.toIntern();
7496 generic_arg_i += 1;
7497 }7497 }
7498 }7498 }
74997499
...@@ -7501,7 +7501,7 @@ fn instantiateGenericCall(...@@ -7501,7 +7501,7 @@ fn instantiateGenericCall(
7501 if (mod.monomorphed_funcs.getAdapted(7501 if (mod.monomorphed_funcs.getAdapted(
7502 Module.MonomorphedFuncAdaptedKey{7502 Module.MonomorphedFuncAdaptedKey{
7503 .func = module_fn_index,7503 .func = module_fn_index,
7504 .args = generic_args[0..generic_arg_i],7504 .args = monomorphed_args[0..monomorphed_arg_i],
7505 },7505 },
7506 Module.MonomorphedFuncsAdaptedContext{ .mod = mod },7506 Module.MonomorphedFuncsAdaptedContext{ .mod = mod },
7507 )) |callee_func| break :callee mod.intern_pool.indexToKey(callee_func).func.index;7507 )) |callee_func| break :callee mod.intern_pool.indexToKey(callee_func).func.index;
...@@ -7550,11 +7550,11 @@ fn instantiateGenericCall(...@@ -7550,11 +7550,11 @@ fn instantiateGenericCall(
7550 new_decl,7550 new_decl,
7551 new_decl_index,7551 new_decl_index,
7552 uncasted_args,7552 uncasted_args,
7553 generic_arg_i,7553 monomorphed_arg_i,
7554 module_fn_index,7554 module_fn_index,
7555 new_module_func_index,7555 new_module_func_index,
7556 namespace_index,7556 namespace_index,
7557 func_ty_info,7557 generic_func_ty,
7558 call_src,7558 call_src,
7559 bound_arg_src,7559 bound_arg_src,
7560 ) catch |err| switch (err) {7560 ) catch |err| switch (err) {
...@@ -7673,11 +7673,11 @@ fn resolveGenericInstantiationType(...@@ -7673,11 +7673,11 @@ fn resolveGenericInstantiationType(
7673 new_decl: *Decl,7673 new_decl: *Decl,
7674 new_decl_index: Decl.Index,7674 new_decl_index: Decl.Index,
7675 uncasted_args: []const Air.Inst.Ref,7675 uncasted_args: []const Air.Inst.Ref,
7676 generic_args_len: u32,7676 monomorphed_args_len: u32,
7677 module_fn_index: Module.Fn.Index,7677 module_fn_index: Module.Fn.Index,
7678 new_module_func: Module.Fn.Index,7678 new_module_func: Module.Fn.Index,
7679 namespace: Namespace.Index,7679 namespace: Namespace.Index,
7680 func_ty_info: InternPool.Key.FuncType,7680 generic_func_ty: Type,
7681 call_src: LazySrcLoc,7681 call_src: LazySrcLoc,
7682 bound_arg_src: ?LazySrcLoc,7682 bound_arg_src: ?LazySrcLoc,
7683) !Module.Fn.Index {7683) !Module.Fn.Index {
...@@ -7737,18 +7737,19 @@ fn resolveGenericInstantiationType(...@@ -7737,18 +7737,19 @@ fn resolveGenericInstantiationType(
77377737
7738 var arg_i: usize = 0;7738 var arg_i: usize = 0;
7739 for (fn_info.param_body) |inst| {7739 for (fn_info.param_body) |inst| {
7740 const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?;
7740 var is_comptime = false;7741 var is_comptime = false;
7741 var is_anytype = false;7742 var is_anytype = false;
7742 switch (zir_tags[inst]) {7743 switch (zir_tags[inst]) {
7743 .param => {7744 .param => {
7744 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i));7745 is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
7745 },7746 },
7746 .param_comptime => {7747 .param_comptime => {
7747 is_comptime = true;7748 is_comptime = true;
7748 },7749 },
7749 .param_anytype => {7750 .param_anytype => {
7750 is_anytype = true;7751 is_anytype = true;
7751 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i));7752 is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
7752 },7753 },
7753 .param_anytype_comptime => {7754 .param_anytype_comptime => {
7754 is_anytype = true;7755 is_anytype = true;
...@@ -7802,25 +7803,26 @@ fn resolveGenericInstantiationType(...@@ -7802,25 +7803,26 @@ fn resolveGenericInstantiationType(
7802 const new_func = new_func_val.getFunctionIndex(mod).unwrap().?;7803 const new_func = new_func_val.getFunctionIndex(mod).unwrap().?;
7803 assert(new_func == new_module_func);7804 assert(new_func == new_module_func);
78047805
7805 const generic_args_index = @intCast(u32, mod.monomorphed_func_keys.items.len);7806 const monomorphed_args_index = @intCast(u32, mod.monomorphed_func_keys.items.len);
7806 const generic_args = try mod.monomorphed_func_keys.addManyAsSlice(gpa, generic_args_len);7807 const monomorphed_args = try mod.monomorphed_func_keys.addManyAsSlice(gpa, monomorphed_args_len);
7807 var generic_arg_i: u32 = 0;7808 var monomorphed_arg_i: u32 = 0;
7808 try mod.monomorphed_funcs.ensureUnusedCapacityContext(gpa, generic_args_len + 1, .{ .mod = mod });7809 try mod.monomorphed_funcs.ensureUnusedCapacityContext(gpa, monomorphed_args_len + 1, .{ .mod = mod });
78097810
7810 arg_i = 0;7811 arg_i = 0;
7811 for (fn_info.param_body) |inst| {7812 for (fn_info.param_body) |inst| {
7813 const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?;
7812 var is_comptime = false;7814 var is_comptime = false;
7813 var is_anytype = false;7815 var is_anytype = false;
7814 switch (zir_tags[inst]) {7816 switch (zir_tags[inst]) {
7815 .param => {7817 .param => {
7816 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i));7818 is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
7817 },7819 },
7818 .param_comptime => {7820 .param_comptime => {
7819 is_comptime = true;7821 is_comptime = true;
7820 },7822 },
7821 .param_anytype => {7823 .param_anytype => {
7822 is_anytype = true;7824 is_anytype = true;
7823 is_comptime = func_ty_info.paramIsComptime(@intCast(u5, arg_i));7825 is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
7824 },7826 },
7825 .param_anytype_comptime => {7827 .param_anytype_comptime => {
7826 is_anytype = true;7828 is_anytype = true;
...@@ -7829,40 +7831,30 @@ fn resolveGenericInstantiationType(...@@ -7829,40 +7831,30 @@ fn resolveGenericInstantiationType(
7829 else => continue,7831 else => continue,
7830 }7832 }
78317833
7832 // We populate the Type here regardless because it is needed by7834 const param_ty = generic_func_ty_info.param_types[arg_i];
7833 // `GenericCallAdapter.eql` as well as function body analysis.7835 const is_generic = !is_anytype and param_ty == .generic_poison_type;
7834 // Whether it is anytype is communicated by `isAnytypeParam`.7836
7835 const arg = child_sema.inst_map.get(inst).?;7837 const arg = child_sema.inst_map.get(inst).?;
7836 const arg_ty = child_sema.typeOf(arg);7838 const arg_ty = child_sema.typeOf(arg);
78377839
7838 if (try sema.typeRequiresComptime(arg_ty)) {7840 if (is_generic) if (mod.monomorphed_funcs.fetchPutAssumeCapacityContext(.{
7839 is_comptime = true;7841 .func = module_fn_index,
7840 }7842 .args_index = monomorphed_args_index,
7843 .args_len = monomorphed_arg_i,
7844 }, arg_ty.toIntern(), .{ .mod = mod })) |kv| assert(kv.value == arg_ty.toIntern());
7845 if (!is_comptime and try sema.typeRequiresComptime(arg_ty)) is_comptime = true;
78417846
7842 if (is_comptime) {7847 if (is_comptime) {
7843 const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?;7848 const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?;
7844 if (!is_anytype) {7849 monomorphed_args[monomorphed_arg_i] = arg_val.toIntern();
7845 if (mod.monomorphed_funcs.fetchPutAssumeCapacityContext(.{7850 monomorphed_arg_i += 1;
7846 .func = module_fn_index,7851 child_sema.comptime_args[arg_i] = .{ .ty = arg_ty, .val = arg_val };
7847 .args_index = generic_args_index,
7848 .args_len = generic_arg_i,
7849 }, arg_ty.toIntern(), .{ .mod = mod })) |kv| assert(kv.value == arg_ty.toIntern());
7850 }
7851 generic_args[generic_arg_i] = arg_val.toIntern();
7852 generic_arg_i += 1;
7853 child_sema.comptime_args[arg_i] = .{
7854 .ty = arg_ty,
7855 .val = (try arg_val.intern(arg_ty, mod)).toValue(),
7856 };
7857 } else {7852 } else {
7858 if (is_anytype) {7853 if (is_anytype or is_generic) {
7859 generic_args[generic_arg_i] = arg_ty.toIntern();7854 monomorphed_args[monomorphed_arg_i] = try mod.intern(.{ .undef = arg_ty.toIntern() });
7860 generic_arg_i += 1;7855 monomorphed_arg_i += 1;
7861 }7856 }
7862 child_sema.comptime_args[arg_i] = .{7857 child_sema.comptime_args[arg_i] = .{ .ty = arg_ty, .val = Value.generic_poison };
7863 .ty = arg_ty,
7864 .val = Value.generic_poison,
7865 };
7866 }7858 }
78677859
7868 arg_i += 1;7860 arg_i += 1;
...@@ -7895,8 +7887,8 @@ fn resolveGenericInstantiationType(...@@ -7895,8 +7887,8 @@ fn resolveGenericInstantiationType(
78957887
7896 mod.monomorphed_funcs.putAssumeCapacityNoClobberContext(.{7888 mod.monomorphed_funcs.putAssumeCapacityNoClobberContext(.{
7897 .func = module_fn_index,7889 .func = module_fn_index,
7898 .args_index = generic_args_index,7890 .args_index = monomorphed_args_index,
7899 .args_len = generic_arg_i,7891 .args_len = monomorphed_arg_i,
7900 }, new_decl.val.toIntern(), .{ .mod = mod });7892 }, new_decl.val.toIntern(), .{ .mod = mod });
79017893
7902 // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field7894 // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field