authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-08-01 22:42:01+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-08-10 10:00:26+01:00
logf2c8fa769a92eb61c13f2cc0f75c526c8fd729a9
tree37f611ef1bd700533987eec239667815a491df6d
parent93e53d1e00793d769d4ee39b3cbfd0c88257687d
signaturelock-open Commit is signed but in an unrecognized format.

Sema: refactor generic calls to interleave argument analysis and parameter type resolution

AstGen provides all function call arguments with a result location, referenced through the call instruction index. The idea is that this should be the parameter type, but for `anytype` parameters, we use generic poison, which is required to be handled correctly. Previously, generic instantiations and inline calls worked by evaluating all args in advance, before resolving generic parameter types. This means any generic parameter (not just `anytype` ones) had generic poison result types. This caused missing result locations in some cases. Additionally, the generic instantiation logic caused `zirParam` to analyze the argument types a second time before coercion. This meant that for nominal types (struct/enum/etc), a *new* type was created, distinct to the result type which was previously forwarded to the argument expression. This commit fixes both of these issues. Generic parameter type resolution is now interleaved with argument analysis, so that we don't have unnecessary generic poison types, and generic instantiation logic now handles parameters itself rather than falling through to the standard zirParam logic, so avoids duplicating the types. Resolves: #16566 Resolves: #16258 Resolves: #16753

4 files changed, 604 insertions(+), 447 deletions(-)

src/Air.zig+4-2
...@@ -1528,11 +1528,13 @@ pub fn refToInterned(ref: Inst.Ref) ?InternPool.Index {...@@ -1528,11 +1528,13 @@ pub fn refToInterned(ref: Inst.Ref) ?InternPool.Index {
1528}1528}
15291529
1530pub fn internedToRef(ip_index: InternPool.Index) Inst.Ref {1530pub fn internedToRef(ip_index: InternPool.Index) Inst.Ref {
1531 assert(@intFromEnum(ip_index) >> 31 == 0);
1532 return switch (ip_index) {1531 return switch (ip_index) {
1533 .var_args_param_type => .var_args_param_type,1532 .var_args_param_type => .var_args_param_type,
1534 .none => .none,1533 .none => .none,
1535 else => @enumFromInt(@as(u31, @intCast(@intFromEnum(ip_index)))),1534 else => {
1535 assert(@intFromEnum(ip_index) >> 31 == 0);
1536 return @enumFromInt(@as(u31, @intCast(@intFromEnum(ip_index))));
1537 },
1536 };1538 };
1537}1539}
15381540
src/Module.zig-29
...@@ -5938,35 +5938,6 @@ pub fn paramSrc(...@@ -5938,35 +5938,6 @@ pub fn paramSrc(
5938 unreachable;5938 unreachable;
5939}5939}
59405940
5941pub fn argSrc(
5942 mod: *Module,
5943 call_node_offset: i32,
5944 decl: *Decl,
5945 start_arg_i: usize,
5946 bound_arg_src: ?LazySrcLoc,
5947) LazySrcLoc {
5948 @setCold(true);
5949 const gpa = mod.gpa;
5950 if (start_arg_i == 0 and bound_arg_src != null) return bound_arg_src.?;
5951 const arg_i = start_arg_i - @intFromBool(bound_arg_src != null);
5952 const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
5953 // In this case we emit a warning + a less precise source location.
5954 log.warn("unable to load {s}: {s}", .{
5955 decl.getFileScope(mod).sub_file_path, @errorName(err),
5956 });
5957 return LazySrcLoc.nodeOffset(0);
5958 };
5959 const node = decl.relativeToNodeIndex(call_node_offset);
5960 var args: [1]Ast.Node.Index = undefined;
5961 const call_full = tree.fullCall(&args, node) orelse {
5962 assert(tree.nodes.items(.tag)[node] == .builtin_call);
5963 const call_args_node = tree.extra_data[tree.nodes.items(.data)[node].rhs - 1];
5964 const call_args_offset = decl.nodeIndexToRelative(call_args_node);
5965 return mod.initSrc(call_args_offset, decl, arg_i);
5966 };
5967 return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(call_full.ast.params[arg_i]));
5968}
5969
5970pub fn initSrc(5941pub fn initSrc(
5971 mod: *Module,5942 mod: *Module,
5972 init_node_offset: i32,5943 init_node_offset: i32,
src/Sema.zig+539-416
...@@ -70,7 +70,6 @@ generic_owner: InternPool.Index = .none,...@@ -70,7 +70,6 @@ generic_owner: InternPool.Index = .none,
70/// instantiation can point back to the instantiation site in addition to the70/// instantiation can point back to the instantiation site in addition to the
71/// declaration site.71/// declaration site.
72generic_call_src: LazySrcLoc = .unneeded,72generic_call_src: LazySrcLoc = .unneeded,
73generic_bound_arg_src: ?LazySrcLoc = null,
74/// Corresponds to `generic_call_src`.73/// Corresponds to `generic_call_src`.
75generic_call_decl: Decl.OptionalIndex = .none,74generic_call_decl: Decl.OptionalIndex = .none,
76/// The key is types that must be fully resolved prior to machine code75/// The key is types that must be fully resolved prior to machine code
...@@ -1401,22 +1400,22 @@ fn analyzeBodyInner(...@@ -1401,22 +1400,22 @@ fn analyzeBodyInner(
1401 continue;1400 continue;
1402 },1401 },
1403 .param => {1402 .param => {
1404 try sema.zirParam(block, inst, i, false);1403 try sema.zirParam(block, inst, false);
1405 i += 1;1404 i += 1;
1406 continue;1405 continue;
1407 },1406 },
1408 .param_comptime => {1407 .param_comptime => {
1409 try sema.zirParam(block, inst, i, true);1408 try sema.zirParam(block, inst, true);
1410 i += 1;1409 i += 1;
1411 continue;1410 continue;
1412 },1411 },
1413 .param_anytype => {1412 .param_anytype => {
1414 try sema.zirParamAnytype(block, inst, i, false);1413 try sema.zirParamAnytype(block, inst, false);
1415 i += 1;1414 i += 1;
1416 continue;1415 continue;
1417 },1416 },
1418 .param_anytype_comptime => {1417 .param_anytype_comptime => {
1419 try sema.zirParamAnytype(block, inst, i, true);1418 try sema.zirParamAnytype(block, inst, true);
1420 i += 1;1419 i += 1;
1421 continue;1420 continue;
1422 },1421 },
...@@ -6536,7 +6535,6 @@ fn zirCall(...@@ -6536,7 +6535,6 @@ fn zirCall(
6536 defer tracy.end();6535 defer tracy.end();
65376536
6538 const mod = sema.mod;6537 const mod = sema.mod;
6539 const ip = &mod.intern_pool;
6540 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;6538 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
6541 const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };6539 const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
6542 const call_src = inst_data.src();6540 const call_src = inst_data.src();
...@@ -6560,96 +6558,62 @@ fn zirCall(...@@ -6560,96 +6558,62 @@ fn zirCall(
6560 break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);6558 break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);
6561 },6559 },
6562 };6560 };
6563 var resolved_args: []Air.Inst.Ref = undefined;6561 const func: Air.Inst.Ref = switch (callee) {
6564 var bound_arg_src: ?LazySrcLoc = null;6562 .direct => |func_inst| func_inst,
6565 var func: Air.Inst.Ref = undefined;6563 .method => |method| method.func_inst,
6566 var arg_index: u32 = 0;6564 };
6567 switch (callee) {
6568 .direct => |func_inst| {
6569 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
6570 func = func_inst;
6571 },
6572 .method => |method| {
6573 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
6574 func = method.func_inst;
6575 resolved_args[0] = method.arg0_inst;
6576 arg_index += 1;
6577 bound_arg_src = callee_src;
6578 },
6579 }
65806565
6581 const callee_ty = sema.typeOf(func);6566 const callee_ty = sema.typeOf(func);
6582 const total_args = args_len + @intFromBool(bound_arg_src != null);6567 const total_args = args_len + @intFromBool(callee == .method);
6583 const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, bound_arg_src != null);6568 const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, callee == .method);
6584
6585 const args_body = sema.code.extra[extra.end..];
65866569
6587 var input_is_error = false;6570 // The block index before the call, so we can potentially insert an error trace save here later.
6588 const block_index: Air.Inst.Index = @intCast(block.instructions.items.len);6571 const block_index: Air.Inst.Index = @intCast(block.instructions.items.len);
65896572
6590 const func_ty_info = mod.typeToFunc(func_ty).?;6573 // This will be set by `analyzeCall` to indicate whether any parameter was an error (making the
6591 const fn_params_len = func_ty_info.param_types.len;6574 // error trace potentially dirty).
6592 const parent_comptime = block.is_comptime;6575 var input_is_error = false;
6593 // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument.
6594 var extra_index: usize = 0;
6595 var arg_start: u32 = args_len;
6596 while (extra_index < args_len) : ({
6597 extra_index += 1;
6598 arg_index += 1;
6599 }) {
6600 const arg_end = sema.code.extra[extra.end + extra_index];
6601 defer arg_start = arg_end;
6602
6603 // Generate args to comptime params in comptime block.
6604 defer block.is_comptime = parent_comptime;
6605 if (arg_index < @min(fn_params_len, 32) and func_ty_info.paramIsComptime(@intCast(arg_index))) {
6606 block.is_comptime = true;
6607 // TODO set comptime_reason
6608 }
6609
6610 sema.inst_map.putAssumeCapacity(inst, inst: {
6611 if (arg_index >= fn_params_len)
6612 break :inst Air.Inst.Ref.var_args_param_type;
66136576
6614 if (func_ty_info.param_types.get(ip)[arg_index] == .generic_poison_type)6577 const args_info: CallArgsInfo = .{ .zir_call = .{
6615 break :inst Air.Inst.Ref.generic_poison_type;6578 .bound_arg = switch (callee) {
6579 .direct => .none,
6580 .method => |method| method.arg0_inst,
6581 },
6582 .bound_arg_src = callee_src,
6583 .call_inst = inst,
6584 .call_node_offset = inst_data.src_node,
6585 .num_args = args_len,
6586 .args_body = sema.code.extra[extra.end..],
6587 .any_arg_is_error = &input_is_error,
6588 } };
66166589
6617 break :inst try sema.addType(func_ty_info.param_types.get(ip)[arg_index].toType());6590 // AstGen ensures that a call instruction is always preceded by a dbg_stmt instruction.
6618 });6591 const call_dbg_node = inst - 1;
6592 const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call);
66196593
6620 const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst);
6621 const resolved_ty = sema.typeOf(resolved);
6622 if (resolved_ty.zigTypeTag(mod) == .NoReturn) {
6623 return resolved;
6624 }
6625 if (resolved_ty.isError(mod)) {
6626 input_is_error = true;
6627 }
6628 resolved_args[arg_index] = resolved;
6629 }
6630 if (sema.owner_func_index == .none or6594 if (sema.owner_func_index == .none or
6631 !ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn)6595 !mod.intern_pool.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn)
6632 {6596 {
6633 input_is_error = false; // input was an error type, but no errorable fn's were actually called6597 // No errorable fn actually called; we have no error return trace
6598 input_is_error = false;
6634 }6599 }
66356600
6636 // AstGen ensures that a call instruction is always preceded by a dbg_stmt instruction.
6637 const call_dbg_node = inst - 1;
6638
6639 if (mod.backendSupportsFeature(.error_return_trace) and mod.comp.bin_file.options.error_return_tracing and6601 if (mod.backendSupportsFeature(.error_return_trace) and mod.comp.bin_file.options.error_return_tracing and
6640 !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))6602 !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))
6641 {6603 {
6642 const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {
6643 break :b try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node, .call);
6644 };
6645
6646 const return_ty = sema.typeOf(call_inst);6604 const return_ty = sema.typeOf(call_inst);
6647 if (modifier != .always_tail and return_ty.isNoReturn(mod))6605 if (modifier != .always_tail and return_ty.isNoReturn(mod))
6648 return call_inst; // call to "fn(...) noreturn", don't pop6606 return call_inst; // call to "fn(...) noreturn", don't pop
66496607
6608 // TODO: we don't fix up the error trace for always_tail correctly, we should be doing it
6609 // *before* the recursive call. This will be a bit tricky to do and probably requires
6610 // moving this logic into analyzeCall. But that's probably a good idea anyway.
6611 if (modifier == .always_tail)
6612 return call_inst;
6613
6650 // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only6614 // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only
6651 // need to clean-up our own trace if we were passed to a non-error-handling expression.6615 // need to clean-up our own trace if we were passed to a non-error-handling expression.
6652 if (input_is_error or (pop_error_return_trace and modifier != .always_tail and return_ty.isError(mod))) {6616 if (input_is_error or (pop_error_return_trace and return_ty.isError(mod))) {
6653 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");6617 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
6654 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);6618 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
6655 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index");6619 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index");
...@@ -6669,12 +6633,9 @@ fn zirCall(...@@ -6669,12 +6633,9 @@ fn zirCall(
6669 try sema.popErrorReturnTrace(block, call_src, operand, save_inst);6633 try sema.popErrorReturnTrace(block, call_src, operand, save_inst);
6670 }6634 }
66716635
6672 if (modifier == .always_tail) // Perform the call *after* the restore, so that a tail call is possible.
6673 return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node, .call);
6674
6675 return call_inst;6636 return call_inst;
6676 } else {6637 } else {
6677 return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node, .call);6638 return call_inst;
6678 }6639 }
6679}6640}
66806641
...@@ -6781,7 +6742,19 @@ fn callBuiltin(...@@ -6781,7 +6742,19 @@ fn callBuiltin(
6781 if (args.len != fn_params_len or (func_ty_info.is_var_args and args.len < fn_params_len)) {6742 if (args.len != fn_params_len or (func_ty_info.is_var_args and args.len < fn_params_len)) {
6782 std.debug.panic("parameter count mismatch calling builtin fn, expected {d}, found {d}", .{ fn_params_len, args.len });6743 std.debug.panic("parameter count mismatch calling builtin fn, expected {d}, found {d}", .{ fn_params_len, args.len });
6783 }6744 }
6784 _ = try sema.analyzeCall(block, builtin_fn, func_ty, call_src, call_src, modifier, false, args, null, null, operation);6745
6746 _ = try sema.analyzeCall(
6747 block,
6748 builtin_fn,
6749 func_ty,
6750 call_src,
6751 call_src,
6752 modifier,
6753 false,
6754 .{ .resolved = .{ .src = call_src, .args = args } },
6755 null,
6756 operation,
6757 );
6785}6758}
67866759
6787const CallOperation = enum {6760const CallOperation = enum {
...@@ -6792,6 +6765,251 @@ const CallOperation = enum {...@@ -6792,6 +6765,251 @@ const CallOperation = enum {
6792 @"error return",6765 @"error return",
6793};6766};
67946767
6768const CallArgsInfo = union(enum) {
6769 /// The full list of resolved (but uncoerced) arguments is known ahead of time.
6770 resolved: struct {
6771 src: LazySrcLoc,
6772 args: []const Air.Inst.Ref,
6773 },
6774
6775 /// The list of resolved (but uncoerced) arguments is known ahead of time, but
6776 /// originated from a usage of the @call builtin at the given node offset.
6777 call_builtin: struct {
6778 call_node_offset: i32,
6779 args: []const Air.Inst.Ref,
6780 },
6781
6782 /// This call corresponds to a ZIR call instruction. The arguments have not yet been
6783 /// resolved. They must be resolved by `analyzeCall` so that argument resolution and
6784 /// generic instantiation may be interleaved. This is required for RLS to work on
6785 /// generic parameters.
6786 zir_call: struct {
6787 /// This may be `none`, in which case it is ignored. Otherwise, it is the
6788 /// already-resolved value of the first argument, from method call syntax.
6789 bound_arg: Air.Inst.Ref,
6790 /// The source location of `bound_arg` if it is not `null`. Otherwise `undefined`.
6791 bound_arg_src: LazySrcLoc,
6792 /// The ZIR call instruction. The parameter type is placed at this index while
6793 /// analyzing arguments.
6794 call_inst: Zir.Inst.Index,
6795 /// The node offset of `call_inst`.
6796 call_node_offset: i32,
6797 /// The number of arguments to this call, not including `bound_arg`.
6798 num_args: u32,
6799 /// The ZIR corresponding to all function arguments (other than `bound_arg`, if it
6800 /// is not `none`). Format is precisely the same as trailing data of ZIR `call`.
6801 args_body: []const Zir.Inst.Index,
6802 /// This bool will be set to true if any argument evaluated turns out to have an error set or error union type.
6803 /// This is used by the caller to restore the error return trace when necessary.
6804 any_arg_is_error: *bool,
6805 },
6806
6807 fn count(cai: CallArgsInfo) usize {
6808 return switch (cai) {
6809 inline .resolved, .call_builtin => |resolved| resolved.args.len,
6810 .zir_call => |zir_call| zir_call.num_args + @intFromBool(zir_call.bound_arg != .none),
6811 };
6812 }
6813
6814 fn argSrc(cai: CallArgsInfo, block: *Block, arg_index: usize) LazySrcLoc {
6815 return switch (cai) {
6816 .resolved => |resolved| resolved.src,
6817 .call_builtin => |call_builtin| .{ .call_arg = .{
6818 .decl = block.src_decl,
6819 .call_node_offset = call_builtin.call_node_offset,
6820 .arg_index = @intCast(arg_index),
6821 } },
6822 .zir_call => |zir_call| if (arg_index == 0 and zir_call.bound_arg != .none) {
6823 return zir_call.bound_arg_src;
6824 } else .{ .call_arg = .{
6825 .decl = block.src_decl,
6826 .call_node_offset = zir_call.call_node_offset,
6827 .arg_index = @intCast(arg_index - @intFromBool(zir_call.bound_arg != .none)),
6828 } },
6829 };
6830 }
6831
6832 /// Analyzes the arg at `arg_index` and coerces it to `param_ty`.
6833 /// `param_ty` may be `generic_poison` or `var_args_param`.
6834 /// `func_ty_info` may be the type before instantiation, even if a generic
6835 /// instantiation has been partially completed.
6836 fn analyzeArg(
6837 cai: CallArgsInfo,
6838 sema: *Sema,
6839 block: *Block,
6840 arg_index: usize,
6841 param_ty: Type,
6842 func_ty_info: InternPool.Key.FuncType,
6843 func_inst: Air.Inst.Ref,
6844 ) CompileError!Air.Inst.Ref {
6845 const mod = sema.mod;
6846 const param_count = func_ty_info.param_types.len;
6847 switch (param_ty.toIntern()) {
6848 .generic_poison_type, .var_args_param_type => {},
6849 else => try sema.queueFullTypeResolution(param_ty),
6850 }
6851 const uncoerced_arg: Air.Inst.Ref = switch (cai) {
6852 inline .resolved, .call_builtin => |resolved| resolved.args[arg_index],
6853 .zir_call => |zir_call| arg_val: {
6854 const has_bound_arg = zir_call.bound_arg != .none;
6855 if (arg_index == 0 and has_bound_arg) {
6856 break :arg_val zir_call.bound_arg;
6857 }
6858 const real_arg_idx = arg_index - @intFromBool(has_bound_arg);
6859
6860 const arg_body = if (real_arg_idx == 0) blk: {
6861 const start = zir_call.num_args;
6862 const end = zir_call.args_body[0];
6863 break :blk zir_call.args_body[start..end];
6864 } else blk: {
6865 const start = zir_call.args_body[real_arg_idx - 1];
6866 const end = zir_call.args_body[real_arg_idx];
6867 break :blk zir_call.args_body[start..end];
6868 };
6869
6870 // Generate args to comptime params in comptime block
6871 const parent_comptime = block.is_comptime;
6872 defer block.is_comptime = parent_comptime;
6873 // Note that we are indexing into parameters, not arguments, so use `arg_index` instead of `real_arg_idx`
6874 if (arg_index < @min(param_count, 32) and func_ty_info.paramIsComptime(@intCast(arg_index))) {
6875 block.is_comptime = true;
6876 // TODO set comptime_reason
6877 }
6878 // Give the arg its result type
6879 sema.inst_map.putAssumeCapacity(zir_call.call_inst, try sema.addType(param_ty));
6880 // Resolve the arg!
6881 const uncoerced_arg = try sema.resolveBody(block, arg_body, zir_call.call_inst);
6882
6883 if (sema.typeOf(uncoerced_arg).zigTypeTag(mod) == .NoReturn) {
6884 // This terminates resolution of arguments. The caller should
6885 // propagate this.
6886 return uncoerced_arg;
6887 }
6888
6889 if (sema.typeOf(uncoerced_arg).isError(mod)) {
6890 zir_call.any_arg_is_error.* = true;
6891 }
6892
6893 break :arg_val uncoerced_arg;
6894 },
6895 };
6896 switch (param_ty.toIntern()) {
6897 .generic_poison_type => return uncoerced_arg,
6898 .var_args_param_type => return sema.coerceVarArgParam(block, uncoerced_arg, cai.argSrc(block, arg_index)),
6899 else => return sema.coerceExtra(
6900 block,
6901 param_ty,
6902 uncoerced_arg,
6903 cai.argSrc(block, arg_index),
6904 .{ .param_src = .{
6905 .func_inst = func_inst,
6906 .param_i = @intCast(arg_index),
6907 } },
6908 ) catch |err| switch (err) {
6909 error.NotCoercible => unreachable,
6910 else => |e| return e,
6911 },
6912 }
6913 }
6914};
6915
6916/// While performing an inline call, we need to switch between two Sema states a few times: the
6917/// state for the caller (with the callee's `code`, `fn_ret_ty`, etc), and the state for the callee.
6918/// These cannot be two separate Sema instances as they must share AIR.
6919/// Therefore, this struct acts as a helper to switch between the two.
6920/// This switching is required during argument evaluation, where function argument analysis must be
6921/// interleaved with resolving generic parameter types.
6922const InlineCallSema = struct {
6923 sema: *Sema,
6924 cur: enum {
6925 caller,
6926 callee,
6927 },
6928
6929 other_code: Zir,
6930 other_func_index: InternPool.Index,
6931 other_fn_ret_ty: Type,
6932 other_fn_ret_ty_ies: ?*InferredErrorSet,
6933 other_inst_map: InstMap,
6934 other_error_return_trace_index_on_fn_entry: Air.Inst.Ref,
6935 other_generic_owner: InternPool.Index,
6936 other_generic_call_src: LazySrcLoc,
6937 other_generic_call_decl: Decl.OptionalIndex,
6938
6939 /// Sema should currently be set up for the caller (i.e. unchanged yet). This init will not
6940 /// change that. The other parameters contain data for the callee Sema. The other modified
6941 /// Sema fields are all initialized to default values for the callee.
6942 /// Must call deinit on the result.
6943 fn init(
6944 sema: *Sema,
6945 callee_code: Zir,
6946 callee_func_index: InternPool.Index,
6947 callee_error_return_trace_index_on_fn_entry: Air.Inst.Ref,
6948 ) InlineCallSema {
6949 return .{
6950 .sema = sema,
6951 .cur = .caller,
6952 .other_code = callee_code,
6953 .other_func_index = callee_func_index,
6954 .other_fn_ret_ty = Type.void,
6955 .other_fn_ret_ty_ies = null,
6956 .other_inst_map = .{},
6957 .other_error_return_trace_index_on_fn_entry = callee_error_return_trace_index_on_fn_entry,
6958 .other_generic_owner = .none,
6959 .other_generic_call_src = .unneeded,
6960 .other_generic_call_decl = .none,
6961 };
6962 }
6963
6964 /// Switch back to the caller Sema if necessary and free all temporary state of the callee Sema.
6965 fn deinit(ics: *InlineCallSema) void {
6966 switch (ics.cur) {
6967 .caller => {},
6968 .callee => ics.swap(),
6969 }
6970 // Callee Sema owns the inst_map memory
6971 ics.other_inst_map.deinit(ics.sema.gpa);
6972 ics.* = undefined;
6973 }
6974
6975 /// Returns a Sema instance suitable for usage from the caller context.
6976 fn caller(ics: *InlineCallSema) *Sema {
6977 switch (ics.cur) {
6978 .caller => {},
6979 .callee => ics.swap(),
6980 }
6981 return ics.sema;
6982 }
6983
6984 /// Returns a Sema instance suitable for usage from the callee context.
6985 fn callee(ics: *InlineCallSema) *Sema {
6986 switch (ics.cur) {
6987 .caller => ics.swap(),
6988 .callee => {},
6989 }
6990 return ics.sema;
6991 }
6992
6993 /// Internal use only. Swaps to the other Sema state.
6994 fn swap(ics: *InlineCallSema) void {
6995 ics.cur = switch (ics.cur) {
6996 .caller => .callee,
6997 .callee => .caller,
6998 };
6999 // zig fmt: off
7000 std.mem.swap(Zir, &ics.sema.code, &ics.other_code);
7001 std.mem.swap(InternPool.Index, &ics.sema.func_index, &ics.other_func_index);
7002 std.mem.swap(Type, &ics.sema.fn_ret_ty, &ics.other_fn_ret_ty);
7003 std.mem.swap(?*InferredErrorSet, &ics.sema.fn_ret_ty_ies, &ics.other_fn_ret_ty_ies);
7004 std.mem.swap(InstMap, &ics.sema.inst_map, &ics.other_inst_map);
7005 std.mem.swap(InternPool.Index, &ics.sema.generic_owner, &ics.other_generic_owner);
7006 std.mem.swap(LazySrcLoc, &ics.sema.generic_call_src, &ics.other_generic_call_src);
7007 std.mem.swap(Decl.OptionalIndex, &ics.sema.generic_call_decl, &ics.other_generic_call_decl);
7008 std.mem.swap(Air.Inst.Ref, &ics.sema.error_return_trace_index_on_fn_entry, &ics.other_error_return_trace_index_on_fn_entry);
7009 // zig fmt: on
7010 }
7011};
7012
6795fn analyzeCall(7013fn analyzeCall(
6796 sema: *Sema,7014 sema: *Sema,
6797 block: *Block,7015 block: *Block,
...@@ -6801,8 +7019,7 @@ fn analyzeCall(...@@ -6801,8 +7019,7 @@ fn analyzeCall(
6801 call_src: LazySrcLoc,7019 call_src: LazySrcLoc,
6802 modifier: std.builtin.CallModifier,7020 modifier: std.builtin.CallModifier,
6803 ensure_result_used: bool,7021 ensure_result_used: bool,
6804 uncasted_args: []const Air.Inst.Ref,7022 args_info: CallArgsInfo,
6805 bound_arg_src: ?LazySrcLoc,
6806 call_dbg_node: ?Zir.Inst.Index,7023 call_dbg_node: ?Zir.Inst.Index,
6807 operation: CallOperation,7024 operation: CallOperation,
6808) CompileError!Air.Inst.Ref {7025) CompileError!Air.Inst.Ref {
...@@ -6811,7 +7028,6 @@ fn analyzeCall(...@@ -6811,7 +7028,6 @@ fn analyzeCall(
68117028
6812 const callee_ty = sema.typeOf(func);7029 const callee_ty = sema.typeOf(func);
6813 const func_ty_info = mod.typeToFunc(func_ty).?;7030 const func_ty_info = mod.typeToFunc(func_ty).?;
6814 const fn_params_len = func_ty_info.param_types.len;
6815 const cc = func_ty_info.cc;7031 const cc = func_ty_info.cc;
6816 if (cc == .Naked) {7032 if (cc == .Naked) {
6817 const maybe_decl = try sema.funcDeclSrc(func);7033 const maybe_decl = try sema.funcDeclSrc(func);
...@@ -6896,9 +7112,8 @@ fn analyzeCall(...@@ -6896,9 +7112,8 @@ fn analyzeCall(
6896 func_src,7112 func_src,
6897 call_src,7113 call_src,
6898 ensure_result_used,7114 ensure_result_used,
6899 uncasted_args,7115 args_info,
6900 call_tag,7116 call_tag,
6901 bound_arg_src,
6902 call_dbg_node,7117 call_dbg_node,
6903 )) |some| {7118 )) |some| {
6904 return some;7119 return some;
...@@ -6973,31 +7188,23 @@ fn analyzeCall(...@@ -6973,31 +7188,23 @@ fn analyzeCall(
6973 .block_inst = block_inst,7188 .block_inst = block_inst,
6974 },7189 },
6975 };7190 };
6976 // In order to save a bit of stack space, directly modify Sema rather7191
6977 // than create a child one.
6978 const parent_zir = sema.code;
6979 const module_fn = mod.funcInfo(module_fn_index);7192 const module_fn = mod.funcInfo(module_fn_index);
6980 const fn_owner_decl = mod.declPtr(module_fn.owner_decl);7193 const fn_owner_decl = mod.declPtr(module_fn.owner_decl);
6981 sema.code = fn_owner_decl.getFileScope(mod).zir;
6982 defer sema.code = parent_zir;
6983
6984 try mod.declareDeclDependencyType(sema.owner_decl_index, module_fn.owner_decl, .function_body);
6985
6986 const parent_inst_map = sema.inst_map;
6987 sema.inst_map = .{};
6988 defer {
6989 sema.src = call_src;
6990 sema.inst_map.deinit(gpa);
6991 sema.inst_map = parent_inst_map;
6992 }
69937194
6994 const parent_func_index = sema.func_index;7195 // We effectively want a child Sema here, but can't literally do that, because we need AIR
6995 sema.func_index = module_fn_index;7196 // to be shared. InlineCallSema is a wrapper which handles this for us. While `ics` is in
6996 defer sema.func_index = parent_func_index;7197 // scope, we should use its `caller`/`callee` methods rather than using `sema` directly
7198 // whenever performing an operation where the difference matters.
7199 var ics = InlineCallSema.init(
7200 sema,
7201 fn_owner_decl.getFileScope(mod).zir,
7202 module_fn_index,
7203 block.error_return_trace_index,
7204 );
7205 defer ics.deinit();
69977206
6998 const parent_err_ret_index = sema.error_return_trace_index_on_fn_entry;7207 try mod.declareDeclDependencyType(ics.callee().owner_decl_index, module_fn.owner_decl, .function_body);
6999 sema.error_return_trace_index_on_fn_entry = block.error_return_trace_index;
7000 defer sema.error_return_trace_index_on_fn_entry = parent_err_ret_index;
70017208
7002 var wip_captures = try WipCaptureScope.init(gpa, fn_owner_decl.src_scope);7209 var wip_captures = try WipCaptureScope.init(gpa, fn_owner_decl.src_scope);
7003 defer wip_captures.deinit();7210 defer wip_captures.deinit();
...@@ -7053,37 +7260,37 @@ fn analyzeCall(...@@ -7053,37 +7260,37 @@ fn analyzeCall(
7053 // the AIR instructions of the callsite. The callee could be a generic function7260 // the AIR instructions of the callsite. The callee could be a generic function
7054 // which means its parameter type expressions must be resolved in order and used7261 // which means its parameter type expressions must be resolved in order and used
7055 // to successively coerce the arguments.7262 // to successively coerce the arguments.
7056 const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst);7263 const fn_info = ics.callee().code.getFnInfo(module_fn.zir_body_inst);
7057 try sema.inst_map.ensureSpaceForInstructions(sema.gpa, fn_info.param_body);7264 try ics.callee().inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
70587265
7059 var has_comptime_args = false;7266 var has_comptime_args = false;
7060 var arg_i: u32 = 0;7267 var arg_i: u32 = 0;
7061 for (fn_info.param_body) |inst| {7268 for (fn_info.param_body) |inst| {
7062 const arg_src: LazySrcLoc = if (arg_i == 0 and bound_arg_src != null)7269 const opt_noreturn_ref = try analyzeInlineCallArg(
7063 bound_arg_src.?7270 &ics,
7064 else
7065 .{ .call_arg = .{
7066 .decl = block.src_decl,
7067 .call_node_offset = call_src.node_offset.x,
7068 .arg_index = arg_i - @intFromBool(bound_arg_src != null),
7069 } };
7070 try sema.analyzeInlineCallArg(
7071 block,7271 block,
7072 &child_block,7272 &child_block,
7073 arg_src,
7074 inst,7273 inst,
7075 new_fn_info.param_types,7274 new_fn_info.param_types,
7076 &arg_i,7275 &arg_i,
7077 uncasted_args,7276 args_info,
7078 is_comptime_call,7277 is_comptime_call,
7079 &should_memoize,7278 &should_memoize,
7080 memoized_arg_values,7279 memoized_arg_values,
7081 func_ty_info.param_types,7280 func_ty_info,
7082 func,7281 func,
7083 &has_comptime_args,7282 &has_comptime_args,
7084 );7283 );
7284 if (opt_noreturn_ref) |ref| {
7285 // Analyzing this argument gave a ref of a noreturn type. Terminate argument analysis here.
7286 return ref;
7287 }
7085 }7288 }
70867289
7290 // From here, we only really need to use the callee Sema. Make it the active one, then we
7291 // can just use `sema` directly.
7292 _ = ics.callee();
7293
7087 if (!has_comptime_args and module_fn.analysis(ip).state == .sema_failure)7294 if (!has_comptime_args and module_fn.analysis(ip).state == .sema_failure)
7088 return error.AnalysisFail;7295 return error.AnalysisFail;
70897296
...@@ -7107,26 +7314,7 @@ fn analyzeCall(...@@ -7107,26 +7314,7 @@ fn analyzeCall(
7107 else7314 else
7108 try sema.resolveInst(fn_info.ret_ty_ref);7315 try sema.resolveInst(fn_info.ret_ty_ref);
7109 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };7316 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
7110 const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);7317 sema.fn_ret_ty = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
7111 const parent_fn_ret_ty = sema.fn_ret_ty;
7112 const parent_fn_ret_ty_ies = sema.fn_ret_ty_ies;
7113 const parent_generic_owner = sema.generic_owner;
7114 const parent_generic_call_src = sema.generic_call_src;
7115 const parent_generic_bound_arg_src = sema.generic_bound_arg_src;
7116 const parent_generic_call_decl = sema.generic_call_decl;
7117 sema.fn_ret_ty = bare_return_type;
7118 sema.fn_ret_ty_ies = null;
7119 sema.generic_owner = .none;
7120 sema.generic_call_src = .unneeded;
7121 sema.generic_bound_arg_src = null;
7122 sema.generic_call_decl = .none;
7123 defer sema.fn_ret_ty = parent_fn_ret_ty;
7124 defer sema.fn_ret_ty_ies = parent_fn_ret_ty_ies;
7125 defer sema.generic_owner = parent_generic_owner;
7126 defer sema.generic_call_src = parent_generic_call_src;
7127 defer sema.generic_bound_arg_src = parent_generic_bound_arg_src;
7128 defer sema.generic_call_decl = parent_generic_call_decl;
7129
7130 if (module_fn.analysis(ip).inferred_error_set) {7318 if (module_fn.analysis(ip).inferred_error_set) {
7131 // Create a fresh inferred error set type for inline/comptime calls.7319 // Create a fresh inferred error set type for inline/comptime calls.
7132 const ies = try sema.arena.create(InferredErrorSet);7320 const ies = try sema.arena.create(InferredErrorSet);
...@@ -7134,7 +7322,7 @@ fn analyzeCall(...@@ -7134,7 +7322,7 @@ fn analyzeCall(
7134 sema.fn_ret_ty_ies = ies;7322 sema.fn_ret_ty_ies = ies;
7135 sema.fn_ret_ty = (try ip.get(gpa, .{ .error_union_type = .{7323 sema.fn_ret_ty = (try ip.get(gpa, .{ .error_union_type = .{
7136 .error_set_type = .adhoc_inferred_error_set_type,7324 .error_set_type = .adhoc_inferred_error_set_type,
7137 .payload_type = bare_return_type.toIntern(),7325 .payload_type = sema.fn_ret_ty.toIntern(),
7138 } })).toType();7326 } })).toType();
7139 }7327 }
71407328
...@@ -7157,7 +7345,7 @@ fn analyzeCall(...@@ -7157,7 +7345,7 @@ fn analyzeCall(
7157 new_fn_info.return_type = sema.fn_ret_ty.toIntern();7345 new_fn_info.return_type = sema.fn_ret_ty.toIntern();
7158 const new_func_resolved_ty = try mod.funcType(new_fn_info);7346 const new_func_resolved_ty = try mod.funcType(new_fn_info);
7159 if (!is_comptime_call and !block.is_typeof) {7347 if (!is_comptime_call and !block.is_typeof) {
7160 try sema.emitDbgInline(block, parent_func_index, module_fn_index, new_func_resolved_ty, .dbg_inline_begin);7348 try sema.emitDbgInline(block, sema.func_index, module_fn_index, new_func_resolved_ty, .dbg_inline_begin);
71617349
7162 const zir_tags = sema.code.instructions.items(.tag);7350 const zir_tags = sema.code.instructions.items(.tag);
7163 for (fn_info.param_body) |param| switch (zir_tags[param]) {7351 for (fn_info.param_body) |param| switch (zir_tags[param]) {
...@@ -7191,7 +7379,7 @@ fn analyzeCall(...@@ -7191,7 +7379,7 @@ fn analyzeCall(
7191 const err_msg = sema.err orelse return err;7379 const err_msg = sema.err orelse return err;
7192 if (mem.eql(u8, err_msg.msg, recursive_msg)) return err;7380 if (mem.eql(u8, err_msg.msg, recursive_msg)) return err;
7193 try sema.errNote(block, call_src, err_msg, "called from here", .{});7381 try sema.errNote(block, call_src, err_msg, "called from here", .{});
7194 err_msg.clearTrace(sema.gpa);7382 err_msg.clearTrace(gpa);
7195 return err;7383 return err;
7196 },7384 },
7197 else => |e| return e,7385 else => |e| return e,
...@@ -7205,8 +7393,8 @@ fn analyzeCall(...@@ -7205,8 +7393,8 @@ fn analyzeCall(
7205 try sema.emitDbgInline(7393 try sema.emitDbgInline(
7206 block,7394 block,
7207 module_fn_index,7395 module_fn_index,
7208 parent_func_index,7396 sema.func_index,
7209 mod.funcOwnerDeclPtr(parent_func_index).ty,7397 mod.funcOwnerDeclPtr(sema.func_index).ty,
7210 .dbg_inline_end,7398 .dbg_inline_end,
7211 );7399 );
7212 }7400 }
...@@ -7251,47 +7439,16 @@ fn analyzeCall(...@@ -7251,47 +7439,16 @@ fn analyzeCall(
7251 } else res: {7439 } else res: {
7252 assert(!func_ty_info.is_generic);7440 assert(!func_ty_info.is_generic);
72537441
7254 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);7442 const args = try sema.arena.alloc(Air.Inst.Ref, args_info.count());
7255 for (uncasted_args, 0..) |uncasted_arg, i| {7443 for (args, 0..) |*arg_out, arg_idx| {
7256 if (i < fn_params_len) {7444 // Non-generic, so param types are already resolved
7257 const opts: CoerceOpts = .{ .param_src = .{7445 const param_ty = if (arg_idx < func_ty_info.param_types.len) ty: {
7258 .func_inst = func,7446 break :ty func_ty_info.param_types.get(ip)[arg_idx].toType();
7259 .param_i = @intCast(i),7447 } else InternPool.Index.var_args_param_type.toType();
7260 } };7448 assert(!param_ty.isGenericPoison());
7261 const param_ty = func_ty_info.param_types.get(ip)[i].toType();7449 arg_out.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, func);
7262 args[i] = sema.analyzeCallArg(7450 if (sema.typeOf(arg_out.*).zigTypeTag(mod) == .NoReturn) {
7263 block,7451 return arg_out.*;
7264 .unneeded,
7265 param_ty,
7266 uncasted_arg,
7267 opts,
7268 ) catch |err| switch (err) {
7269 error.NeededSourceLocation => {
7270 const decl = mod.declPtr(block.src_decl);
7271 _ = try sema.analyzeCallArg(
7272 block,
7273 mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src),
7274 param_ty,
7275 uncasted_arg,
7276 opts,
7277 );
7278 unreachable;
7279 },
7280 else => |e| return e,
7281 };
7282 } else {
7283 args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) {
7284 error.NeededSourceLocation => {
7285 const decl = mod.declPtr(block.src_decl);
7286 _ = try sema.coerceVarArgParam(
7287 block,
7288 uncasted_arg,
7289 mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src),
7290 );
7291 unreachable;
7292 },
7293 else => |e| return e,
7294 };
7295 }7452 }
7296 }7453 }
72977454
...@@ -7375,25 +7532,25 @@ fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Typ...@@ -7375,25 +7532,25 @@ fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Typ
7375 return Air.Inst.Ref.unreachable_value;7532 return Air.Inst.Ref.unreachable_value;
7376}7533}
73777534
7535/// Usually, returns null. If an argument was noreturn, returns that ref (which should become the call result).
7378fn analyzeInlineCallArg(7536fn analyzeInlineCallArg(
7379 sema: *Sema,7537 ics: *InlineCallSema,
7380 arg_block: *Block,7538 arg_block: *Block,
7381 param_block: *Block,7539 param_block: *Block,
7382 arg_src: LazySrcLoc,
7383 inst: Zir.Inst.Index,7540 inst: Zir.Inst.Index,
7384 new_param_types: []InternPool.Index,7541 new_param_types: []InternPool.Index,
7385 arg_i: *u32,7542 arg_i: *u32,
7386 uncasted_args: []const Air.Inst.Ref,7543 args_info: CallArgsInfo,
7387 is_comptime_call: bool,7544 is_comptime_call: bool,
7388 should_memoize: *bool,7545 should_memoize: *bool,
7389 memoized_arg_values: []InternPool.Index,7546 memoized_arg_values: []InternPool.Index,
7390 raw_param_types: InternPool.Index.Slice,7547 func_ty_info: InternPool.Key.FuncType,
7391 func_inst: Air.Inst.Ref,7548 func_inst: Air.Inst.Ref,
7392 has_comptime_args: *bool,7549 has_comptime_args: *bool,
7393) !void {7550) !?Air.Inst.Ref {
7394 const mod = sema.mod;7551 const mod = ics.sema.mod;
7395 const ip = &mod.intern_pool;7552 const ip = &mod.intern_pool;
7396 const zir_tags = sema.code.instructions.items(.tag);7553 const zir_tags = ics.callee().code.instructions.items(.tag);
7397 switch (zir_tags[inst]) {7554 switch (zir_tags[inst]) {
7398 .param_comptime, .param_anytype_comptime => has_comptime_args.* = true,7555 .param_comptime, .param_anytype_comptime => has_comptime_args.* = true,
7399 else => {},7556 else => {},
...@@ -7402,39 +7559,36 @@ fn analyzeInlineCallArg(...@@ -7402,39 +7559,36 @@ fn analyzeInlineCallArg(
7402 .param, .param_comptime => {7559 .param, .param_comptime => {
7403 // Evaluate the parameter type expression now that previous ones have7560 // Evaluate the parameter type expression now that previous ones have
7404 // been mapped, and coerce the corresponding argument to it.7561 // been mapped, and coerce the corresponding argument to it.
7405 const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok;7562 const pl_tok = ics.callee().code.instructions.items(.data)[inst].pl_tok;
7406 const param_src = pl_tok.src();7563 const param_src = pl_tok.src();
7407 const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index);7564 const extra = ics.callee().code.extraData(Zir.Inst.Param, pl_tok.payload_index);
7408 const param_body = sema.code.extra[extra.end..][0..extra.data.body_len];7565 const param_body = ics.callee().code.extra[extra.end..][0..extra.data.body_len];
7409 const param_ty = param_ty: {7566 const param_ty = param_ty: {
7410 const raw_param_ty = raw_param_types.get(ip)[arg_i.*];7567 const raw_param_ty = func_ty_info.param_types.get(ip)[arg_i.*];
7411 if (raw_param_ty != .generic_poison_type) break :param_ty raw_param_ty;7568 if (raw_param_ty != .generic_poison_type) break :param_ty raw_param_ty;
7412 const param_ty_inst = try sema.resolveBody(param_block, param_body, inst);7569 const param_ty_inst = try ics.callee().resolveBody(param_block, param_body, inst);
7413 const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst);7570 const param_ty = try ics.callee().analyzeAsType(param_block, param_src, param_ty_inst);
7414 break :param_ty param_ty.toIntern();7571 break :param_ty param_ty.toIntern();
7415 };7572 };
7416 new_param_types[arg_i.*] = param_ty;7573 new_param_types[arg_i.*] = param_ty;
7417 const uncasted_arg = uncasted_args[arg_i.*];7574 const casted_arg = try args_info.analyzeArg(ics.caller(), arg_block, arg_i.*, param_ty.toType(), func_ty_info, func_inst);
7418 if (try sema.typeRequiresComptime(param_ty.toType())) {7575 if (ics.caller().typeOf(casted_arg).zigTypeTag(mod) == .NoReturn) {
7419 _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| {7576 return casted_arg;
7420 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);7577 }
7578 const arg_src = args_info.argSrc(arg_block, arg_i.*);
7579 if (try ics.callee().typeRequiresComptime(param_ty.toType())) {
7580 _ = ics.caller().resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| {
7581 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(ics.caller(), ics.caller().err);
7421 return err;7582 return err;
7422 };7583 };
7423 } else if (!is_comptime_call and zir_tags[inst] == .param_comptime) {7584 } else if (!is_comptime_call and zir_tags[inst] == .param_comptime) {
7424 _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");7585 _ = try ics.caller().resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "parameter is comptime");
7425 }7586 }
7426 const casted_arg = sema.coerceExtra(arg_block, param_ty.toType(), uncasted_arg, arg_src, .{ .param_src = .{
7427 .func_inst = func_inst,
7428 .param_i = @intCast(arg_i.*),
7429 } }) catch |err| switch (err) {
7430 error.NotCoercible => unreachable,
7431 else => |e| return e,
7432 };
74337587
7434 if (is_comptime_call) {7588 if (is_comptime_call) {
7435 sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg);7589 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
7436 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {7590 const arg_val = ics.caller().resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
7437 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);7591 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(ics.caller(), ics.caller().err);
7438 return err;7592 return err;
7439 };7593 };
7440 switch (arg_val.toIntern()) {7594 switch (arg_val.toIntern()) {
...@@ -7448,14 +7602,14 @@ fn analyzeInlineCallArg(...@@ -7448,14 +7602,14 @@ fn analyzeInlineCallArg(
7448 // Needed so that lazy values do not trigger7602 // Needed so that lazy values do not trigger
7449 // assertion due to type not being resolved7603 // assertion due to type not being resolved
7450 // when the hash function is called.7604 // when the hash function is called.
7451 const resolved_arg_val = try sema.resolveLazyValue(arg_val);7605 const resolved_arg_val = try ics.caller().resolveLazyValue(arg_val);
7452 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod);7606 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod);
7453 memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(param_ty.toType(), mod);7607 memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(param_ty.toType(), mod);
7454 } else {7608 } else {
7455 sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg);7609 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
7456 }7610 }
74577611
7458 if (try sema.resolveMaybeUndefVal(casted_arg)) |_| {7612 if (try ics.caller().resolveMaybeUndefVal(casted_arg)) |_| {
7459 has_comptime_args.* = true;7613 has_comptime_args.* = true;
7460 }7614 }
74617615
...@@ -7463,13 +7617,17 @@ fn analyzeInlineCallArg(...@@ -7463,13 +7617,17 @@ fn analyzeInlineCallArg(
7463 },7617 },
7464 .param_anytype, .param_anytype_comptime => {7618 .param_anytype, .param_anytype_comptime => {
7465 // No coercion needed.7619 // No coercion needed.
7466 const uncasted_arg = uncasted_args[arg_i.*];7620 const uncasted_arg = try args_info.analyzeArg(ics.caller(), arg_block, arg_i.*, Type.generic_poison, func_ty_info, func_inst);
7467 new_param_types[arg_i.*] = sema.typeOf(uncasted_arg).toIntern();7621 if (ics.caller().typeOf(uncasted_arg).zigTypeTag(mod) == .NoReturn) {
7622 return uncasted_arg;
7623 }
7624 const arg_src = args_info.argSrc(arg_block, arg_i.*);
7625 new_param_types[arg_i.*] = ics.caller().typeOf(uncasted_arg).toIntern();
74687626
7469 if (is_comptime_call) {7627 if (is_comptime_call) {
7470 sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);7628 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
7471 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {7629 const arg_val = ics.caller().resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
7472 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);7630 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(ics.caller(), ics.caller().err);
7473 return err;7631 return err;
7474 };7632 };
7475 switch (arg_val.toIntern()) {7633 switch (arg_val.toIntern()) {
...@@ -7483,17 +7641,17 @@ fn analyzeInlineCallArg(...@@ -7483,17 +7641,17 @@ fn analyzeInlineCallArg(
7483 // Needed so that lazy values do not trigger7641 // Needed so that lazy values do not trigger
7484 // assertion due to type not being resolved7642 // assertion due to type not being resolved
7485 // when the hash function is called.7643 // when the hash function is called.
7486 const resolved_arg_val = try sema.resolveLazyValue(arg_val);7644 const resolved_arg_val = try ics.caller().resolveLazyValue(arg_val);
7487 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod);7645 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod);
7488 memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(sema.typeOf(uncasted_arg), mod);7646 memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(ics.caller().typeOf(uncasted_arg), mod);
7489 } else {7647 } else {
7490 if (zir_tags[inst] == .param_anytype_comptime) {7648 if (zir_tags[inst] == .param_anytype_comptime) {
7491 _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");7649 _ = try ics.caller().resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");
7492 }7650 }
7493 sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);7651 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
7494 }7652 }
74957653
7496 if (try sema.resolveMaybeUndefVal(uncasted_arg)) |_| {7654 if (try ics.caller().resolveMaybeUndefVal(uncasted_arg)) |_| {
7497 has_comptime_args.* = true;7655 has_comptime_args.* = true;
7498 }7656 }
74997657
...@@ -7501,6 +7659,8 @@ fn analyzeInlineCallArg(...@@ -7501,6 +7659,8 @@ fn analyzeInlineCallArg(
7501 },7659 },
7502 else => {},7660 else => {},
7503 }7661 }
7662
7663 return null;
7504}7664}
75057665
7506fn analyzeCallArg(7666fn analyzeCallArg(
...@@ -7525,9 +7685,8 @@ fn instantiateGenericCall(...@@ -7525,9 +7685,8 @@ fn instantiateGenericCall(
7525 func_src: LazySrcLoc,7685 func_src: LazySrcLoc,
7526 call_src: LazySrcLoc,7686 call_src: LazySrcLoc,
7527 ensure_result_used: bool,7687 ensure_result_used: bool,
7528 uncasted_args: []const Air.Inst.Ref,7688 args_info: CallArgsInfo,
7529 call_tag: Air.Inst.Tag,7689 call_tag: Air.Inst.Tag,
7530 bound_arg_src: ?LazySrcLoc,
7531 call_dbg_node: ?Zir.Inst.Index,7690 call_dbg_node: ?Zir.Inst.Index,
7532) CompileError!Air.Inst.Ref {7691) CompileError!Air.Inst.Ref {
7533 const mod = sema.mod;7692 const mod = sema.mod;
...@@ -7541,6 +7700,7 @@ fn instantiateGenericCall(...@@ -7541,6 +7700,7 @@ fn instantiateGenericCall(
7541 else => unreachable,7700 else => unreachable,
7542 };7701 };
7543 const generic_owner_func = mod.intern_pool.indexToKey(generic_owner).func;7702 const generic_owner_func = mod.intern_pool.indexToKey(generic_owner).func;
7703 const generic_owner_ty_info = mod.typeToFunc(generic_owner_func.ty.toType()).?;
75447704
7545 // Even though there may already be a generic instantiation corresponding7705 // Even though there may already be a generic instantiation corresponding
7546 // to this callsite, we must evaluate the expressions of the generic7706 // to this callsite, we must evaluate the expressions of the generic
...@@ -7556,9 +7716,13 @@ fn instantiateGenericCall(...@@ -7556,9 +7716,13 @@ fn instantiateGenericCall(
7556 const fn_zir = namespace.file_scope.zir;7716 const fn_zir = namespace.file_scope.zir;
7557 const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst);7717 const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst);
75587718
7559 const comptime_args = try sema.arena.alloc(InternPool.Index, uncasted_args.len);7719 const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count());
7560 @memset(comptime_args, .none);7720 @memset(comptime_args, .none);
75617721
7722 // We may overestimate the number of runtime args, but this will definitely be sufficient.
7723 const max_runtime_args = args_info.count() - @popCount(generic_owner_ty_info.comptime_bits);
7724 var runtime_args = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(sema.arena, max_runtime_args);
7725
7562 // Re-run the block that creates the function, with the comptime parameters7726 // Re-run the block that creates the function, with the comptime parameters
7563 // pre-populated inside `inst_map`. This causes `param_comptime` and7727 // pre-populated inside `inst_map`. This causes `param_comptime` and
7564 // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a7728 // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a
...@@ -7583,7 +7747,6 @@ fn instantiateGenericCall(...@@ -7583,7 +7747,6 @@ fn instantiateGenericCall(
7583 .comptime_args = comptime_args,7747 .comptime_args = comptime_args,
7584 .generic_owner = generic_owner,7748 .generic_owner = generic_owner,
7585 .generic_call_src = call_src,7749 .generic_call_src = call_src,
7586 .generic_bound_arg_src = bound_arg_src,
7587 .generic_call_decl = block.src_decl.toOptional(),7750 .generic_call_decl = block.src_decl.toOptional(),
7588 .branch_quota = sema.branch_quota,7751 .branch_quota = sema.branch_quota,
7589 .branch_count = sema.branch_count,7752 .branch_count = sema.branch_count,
...@@ -7608,25 +7771,138 @@ fn instantiateGenericCall(...@@ -7608,25 +7771,138 @@ fn instantiateGenericCall(
76087771
7609 try child_sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);7772 try child_sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
76107773
7611 for (fn_info.param_body[0..uncasted_args.len], uncasted_args, 0..) |inst, arg, i| {7774 for (fn_info.param_body[0..args_info.count()], 0..) |param_inst, arg_index| {
7612 // `child_sema` will use a different `inst_map` which means we have to7775 const param_tag = fn_zir.instructions.items(.tag)[param_inst];
7613 // convert from parent-relative `Air.Inst.Ref` to child-relative here.7776
7614 // Constants are simple; runtime-known values need a new instruction.7777 const param_ty = switch (generic_owner_ty_info.param_types.get(ip)[arg_index]) {
7615 child_sema.inst_map.putAssumeCapacityNoClobber(inst, if (try sema.resolveMaybeUndefVal(arg)) |val|7778 else => |ty| ty.toType(), // parameter is not generic, so type is already resolved
7616 Air.internedToRef(val.toIntern())7779 .generic_poison_type => param_ty: {
7617 else7780 // We have every parameter before this one, so can resolve this parameter's type now.
7618 // We insert into the map an instruction which is runtime-known7781 // However, first check the param type, since it may be anytype.
7619 // but has the type of the argument.7782 switch (param_tag) {
7620 try child_block.addInst(.{7783 .param_anytype, .param_anytype_comptime => {
7784 // The parameter doesn't have a type.
7785 break :param_ty Type.generic_poison;
7786 },
7787 .param, .param_comptime => {
7788 // We now know every prior parameter, so can resolve this
7789 // parameter's type. The child sema has these types.
7790 const param_data = fn_zir.instructions.items(.data)[param_inst].pl_tok;
7791 const param_extra = fn_zir.extraData(Zir.Inst.Param, param_data.payload_index);
7792 const param_ty_body = fn_zir.extra[param_extra.end..][0..param_extra.data.body_len];
7793
7794 // Make sure any nested instructions don't clobber our work.
7795 const prev_params = child_block.params;
7796 const prev_no_partial_func_ty = child_sema.no_partial_func_ty;
7797 const prev_generic_owner = child_sema.generic_owner;
7798 const prev_generic_call_src = child_sema.generic_call_src;
7799 const prev_generic_call_decl = child_sema.generic_call_decl;
7800 child_block.params = .{};
7801 child_sema.no_partial_func_ty = true;
7802 child_sema.generic_owner = .none;
7803 child_sema.generic_call_src = .unneeded;
7804 child_sema.generic_call_decl = .none;
7805 defer {
7806 child_block.params = prev_params;
7807 child_sema.no_partial_func_ty = prev_no_partial_func_ty;
7808 child_sema.generic_owner = prev_generic_owner;
7809 child_sema.generic_call_src = prev_generic_call_src;
7810 child_sema.generic_call_decl = prev_generic_call_decl;
7811 }
7812
7813 const param_ty_inst = try child_sema.resolveBody(&child_block, param_ty_body, param_inst);
7814 break :param_ty try child_sema.analyzeAsType(&child_block, param_data.src(), param_ty_inst);
7815 },
7816 else => unreachable,
7817 }
7818 },
7819 };
7820 const arg_ref = try args_info.analyzeArg(sema, block, arg_index, param_ty, generic_owner_ty_info, func);
7821 const arg_ty = sema.typeOf(arg_ref);
7822 if (arg_ty.zigTypeTag(mod) == .NoReturn) {
7823 // This terminates argument analysis.
7824 return arg_ref;
7825 }
7826
7827 const arg_is_comptime = switch (param_tag) {
7828 .param_comptime, .param_anytype_comptime => true,
7829 .param, .param_anytype => try sema.typeRequiresComptime(arg_ty),
7830 else => unreachable,
7831 };
7832
7833 if (arg_is_comptime) {
7834 if (try sema.resolveMaybeUndefVal(arg_ref)) |arg_val| {
7835 comptime_args[arg_index] = arg_val.toIntern();
7836 child_sema.inst_map.putAssumeCapacityNoClobber(
7837 param_inst,
7838 Air.internedToRef(arg_val.toIntern()),
7839 );
7840 } else switch (param_tag) {
7841 .param_comptime,
7842 .param_anytype_comptime,
7843 => return sema.failWithOwnedErrorMsg(msg: {
7844 const arg_src = args_info.argSrc(block, arg_index);
7845 const msg = try sema.errMsg(block, arg_src, "runtime-known argument passed to comptime parameter", .{});
7846 errdefer msg.destroy(sema.gpa);
7847 const param_src = switch (param_tag) {
7848 .param_comptime => fn_zir.instructions.items(.data)[param_inst].pl_tok.src(),
7849 .param_anytype_comptime => fn_zir.instructions.items(.data)[param_inst].str_tok.src(),
7850 else => unreachable,
7851 };
7852 try child_sema.errNote(&child_block, param_src, msg, "declared comptime here", .{});
7853 break :msg msg;
7854 }),
7855
7856 .param,
7857 .param_anytype,
7858 => return sema.failWithOwnedErrorMsg(msg: {
7859 const arg_src = args_info.argSrc(block, arg_index);
7860 const msg = try sema.errMsg(block, arg_src, "runtime-known argument passed to parameter of comptime-only type", .{});
7861 errdefer msg.destroy(sema.gpa);
7862 const param_src = switch (param_tag) {
7863 .param => fn_zir.instructions.items(.data)[param_inst].pl_tok.src(),
7864 .param_anytype => fn_zir.instructions.items(.data)[param_inst].str_tok.src(),
7865 else => unreachable,
7866 };
7867 try child_sema.errNote(&child_block, param_src, msg, "declared here", .{});
7868 const src_decl = mod.declPtr(block.src_decl);
7869 try sema.explainWhyTypeIsComptime(msg, arg_src.toSrcLoc(src_decl, mod), arg_ty);
7870 break :msg msg;
7871 }),
7872
7873 else => unreachable,
7874 }
7875 } else {
7876 // The parameter is runtime-known.
7877 try sema.queueFullTypeResolution(arg_ty);
7878 child_sema.inst_map.putAssumeCapacityNoClobber(param_inst, try child_block.addInst(.{
7621 .tag = .arg,7879 .tag = .arg,
7622 .data = .{ .arg = .{7880 .data = .{ .arg = .{
7623 .ty = Air.internedToRef(sema.typeOf(arg).toIntern()),7881 .ty = Air.internedToRef(arg_ty.toIntern()),
7624 .src_index = @intCast(i),7882 .src_index = @intCast(arg_index),
7625 } },7883 } },
7626 }));7884 }));
7885 const param_name: Zir.NullTerminatedString = switch (param_tag) {
7886 .param_anytype => @enumFromInt(fn_zir.instructions.items(.data)[param_inst].str_tok.start),
7887 .param => name: {
7888 const inst_data = fn_zir.instructions.items(.data)[param_inst].pl_tok;
7889 const extra = fn_zir.extraData(Zir.Inst.Param, inst_data.payload_index);
7890 break :name @enumFromInt(extra.data.name);
7891 },
7892 else => unreachable,
7893 };
7894 try child_block.params.append(sema.arena, .{
7895 .ty = arg_ty.toIntern(), // This is the type after coercion
7896 .is_comptime = false, // We're adding only runtime args to the instantiation
7897 .name = param_name,
7898 });
7899 runtime_args.appendAssumeCapacity(arg_ref);
7900 }
7627 }7901 }
76287902
7629 const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst);7903 // We've already handled parameters, so don't resolve the whole body. Instead, just
7904 // do the instructions after the params (i.e. the func itself).
7905 const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body[args_info.count()..], fn_info.param_body_inst);
7630 const callee_index = (child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable).toIntern();7906 const callee_index = (child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable).toIntern();
76317907
7632 const callee = mod.funcInfo(callee_index);7908 const callee = mod.funcInfo(callee_index);
...@@ -7649,33 +7925,7 @@ fn instantiateGenericCall(...@@ -7649,33 +7925,7 @@ fn instantiateGenericCall(
7649 return error.GenericPoison;7925 return error.GenericPoison;
7650 }7926 }
76517927
7652 const runtime_args_len: u32 = func_ty_info.param_types.len;7928 try sema.queueFullTypeResolution(func_ty_info.return_type.toType());
7653 const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len);
7654 {
7655 var runtime_i: u32 = 0;
7656 for (uncasted_args, 0..) |uncasted_arg, total_i| {
7657 // In the case of a function call generated by the language, the LazySrcLoc
7658 // provided for `call_src` may not point to anything interesting.
7659 const arg_src: LazySrcLoc = if (total_i == 0 and bound_arg_src != null)
7660 bound_arg_src.?
7661 else if (call_src == .node_offset) .{ .call_arg = .{
7662 .decl = block.src_decl,
7663 .call_node_offset = call_src.node_offset.x,
7664 .arg_index = @intCast(total_i - @intFromBool(bound_arg_src != null)),
7665 } } else .unneeded;
7666
7667 const comptime_arg = callee.comptime_args.get(ip)[total_i];
7668 if (comptime_arg == .none) {
7669 const param_ty = func_ty_info.param_types.get(ip)[runtime_i].toType();
7670 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
7671 try sema.queueFullTypeResolution(param_ty);
7672 runtime_args[runtime_i] = casted_arg;
7673 runtime_i += 1;
7674 }
7675 }
7676
7677 try sema.queueFullTypeResolution(func_ty_info.return_type.toType());
7678 }
76797929
7680 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);7930 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
76817931
...@@ -7687,18 +7937,17 @@ fn instantiateGenericCall(...@@ -7687,18 +7937,17 @@ fn instantiateGenericCall(
76877937
7688 try mod.ensureFuncBodyAnalysisQueued(callee_index);7938 try mod.ensureFuncBodyAnalysisQueued(callee_index);
76897939
7690 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +7940 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + runtime_args.items.len);
7691 runtime_args_len);
7692 const result = try block.addInst(.{7941 const result = try block.addInst(.{
7693 .tag = call_tag,7942 .tag = call_tag,
7694 .data = .{ .pl_op = .{7943 .data = .{ .pl_op = .{
7695 .operand = Air.internedToRef(callee_index),7944 .operand = Air.internedToRef(callee_index),
7696 .payload = sema.addExtraAssumeCapacity(Air.Call{7945 .payload = sema.addExtraAssumeCapacity(Air.Call{
7697 .args_len = runtime_args_len,7946 .args_len = @intCast(runtime_args.items.len),
7698 }),7947 }),
7699 } },7948 } },
7700 });7949 });
7701 sema.appendRefsAssumeCapacity(runtime_args);7950 sema.appendRefsAssumeCapacity(runtime_args.items);
77027951
7703 if (ensure_result_used) {7952 if (ensure_result_used) {
7704 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);7953 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
...@@ -8647,20 +8896,17 @@ fn resolveGenericBody(...@@ -8647,20 +8896,17 @@ fn resolveGenericBody(
8647 const prev_no_partial_func_type = sema.no_partial_func_ty;8896 const prev_no_partial_func_type = sema.no_partial_func_ty;
8648 const prev_generic_owner = sema.generic_owner;8897 const prev_generic_owner = sema.generic_owner;
8649 const prev_generic_call_src = sema.generic_call_src;8898 const prev_generic_call_src = sema.generic_call_src;
8650 const prev_generic_bound_arg_src = sema.generic_bound_arg_src;
8651 const prev_generic_call_decl = sema.generic_call_decl;8899 const prev_generic_call_decl = sema.generic_call_decl;
8652 block.params = .{};8900 block.params = .{};
8653 sema.no_partial_func_ty = true;8901 sema.no_partial_func_ty = true;
8654 sema.generic_owner = .none;8902 sema.generic_owner = .none;
8655 sema.generic_call_src = .unneeded;8903 sema.generic_call_src = .unneeded;
8656 sema.generic_bound_arg_src = null;
8657 sema.generic_call_decl = .none;8904 sema.generic_call_decl = .none;
8658 defer {8905 defer {
8659 block.params = prev_params;8906 block.params = prev_params;
8660 sema.no_partial_func_ty = prev_no_partial_func_type;8907 sema.no_partial_func_ty = prev_no_partial_func_type;
8661 sema.generic_owner = prev_generic_owner;8908 sema.generic_owner = prev_generic_owner;
8662 sema.generic_call_src = prev_generic_call_src;8909 sema.generic_call_src = prev_generic_call_src;
8663 sema.generic_bound_arg_src = prev_generic_bound_arg_src;
8664 sema.generic_call_decl = prev_generic_call_decl;8910 sema.generic_call_decl = prev_generic_call_decl;
8665 }8911 }
86668912
...@@ -9278,37 +9524,18 @@ fn finishFunc(...@@ -9278,37 +9524,18 @@ fn finishFunc(
9278 return Air.internedToRef(if (opt_func_index != .none) opt_func_index else func_ty);9524 return Air.internedToRef(if (opt_func_index != .none) opt_func_index else func_ty);
9279}9525}
92809526
9281fn genericArgSrcLoc(sema: *Sema, block: *Block, param_index: u32, param_src: LazySrcLoc) Module.SrcLoc {
9282 const mod = sema.mod;
9283 if (sema.generic_owner == .none) return param_src.toSrcLoc(mod.declPtr(block.src_decl), mod);
9284 const arg_decl = sema.generic_call_decl.unwrap().?;
9285 const arg_src: LazySrcLoc = if (param_index == 0 and sema.generic_bound_arg_src != null)
9286 sema.generic_bound_arg_src.?
9287 else
9288 .{ .call_arg = .{
9289 .decl = arg_decl,
9290 .call_node_offset = sema.generic_call_src.node_offset.x,
9291 .arg_index = param_index - @intFromBool(sema.generic_bound_arg_src != null),
9292 } };
9293 return arg_src.toSrcLoc(mod.declPtr(arg_decl), mod);
9294}
9295
9296fn zirParam(9527fn zirParam(
9297 sema: *Sema,9528 sema: *Sema,
9298 block: *Block,9529 block: *Block,
9299 inst: Zir.Inst.Index,9530 inst: Zir.Inst.Index,
9300 param_index: u32,
9301 comptime_syntax: bool,9531 comptime_syntax: bool,
9302) CompileError!void {9532) CompileError!void {
9303 const gpa = sema.gpa;
9304 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;9533 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
9305 const src = inst_data.src();9534 const src = inst_data.src();
9306 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);9535 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
9307 const param_name: Zir.NullTerminatedString = @enumFromInt(extra.data.name);9536 const param_name: Zir.NullTerminatedString = @enumFromInt(extra.data.name);
9308 const body = sema.code.extra[extra.end..][0..extra.data.body_len];9537 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
93099538
9310 // We could be in a generic function instantiation, or we could be evaluating a generic
9311 // function without any comptime args provided.
9312 const param_ty = param_ty: {9539 const param_ty = param_ty: {
9313 const err = err: {9540 const err = err: {
9314 // Make sure any nested param instructions don't clobber our work.9541 // Make sure any nested param instructions don't clobber our work.
...@@ -9316,20 +9543,17 @@ fn zirParam(...@@ -9316,20 +9543,17 @@ fn zirParam(
9316 const prev_no_partial_func_type = sema.no_partial_func_ty;9543 const prev_no_partial_func_type = sema.no_partial_func_ty;
9317 const prev_generic_owner = sema.generic_owner;9544 const prev_generic_owner = sema.generic_owner;
9318 const prev_generic_call_src = sema.generic_call_src;9545 const prev_generic_call_src = sema.generic_call_src;
9319 const prev_generic_bound_arg_src = sema.generic_bound_arg_src;
9320 const prev_generic_call_decl = sema.generic_call_decl;9546 const prev_generic_call_decl = sema.generic_call_decl;
9321 block.params = .{};9547 block.params = .{};
9322 sema.no_partial_func_ty = true;9548 sema.no_partial_func_ty = true;
9323 sema.generic_owner = .none;9549 sema.generic_owner = .none;
9324 sema.generic_call_src = .unneeded;9550 sema.generic_call_src = .unneeded;
9325 sema.generic_bound_arg_src = null;
9326 sema.generic_call_decl = .none;9551 sema.generic_call_decl = .none;
9327 defer {9552 defer {
9328 block.params = prev_params;9553 block.params = prev_params;
9329 sema.no_partial_func_ty = prev_no_partial_func_type;9554 sema.no_partial_func_ty = prev_no_partial_func_type;
9330 sema.generic_owner = prev_generic_owner;9555 sema.generic_owner = prev_generic_owner;
9331 sema.generic_call_src = prev_generic_call_src;9556 sema.generic_call_src = prev_generic_call_src;
9332 sema.generic_bound_arg_src = prev_generic_bound_arg_src;
9333 sema.generic_call_decl = prev_generic_call_decl;9557 sema.generic_call_decl = prev_generic_call_decl;
9334 }9558 }
93359559
...@@ -9341,11 +9565,6 @@ fn zirParam(...@@ -9341,11 +9565,6 @@ fn zirParam(
9341 };9565 };
9342 switch (err) {9566 switch (err) {
9343 error.GenericPoison => {9567 error.GenericPoison => {
9344 if (sema.inst_map.contains(inst)) {
9345 // A generic function is about to evaluate to another generic function.
9346 // Return an error instead.
9347 return error.GenericPoison;
9348 }
9349 // The type is not available until the generic instantiation.9568 // The type is not available until the generic instantiation.
9350 // We result the param instruction with a poison value and9569 // We result the param instruction with a poison value and
9351 // insert an anytype parameter.9570 // insert an anytype parameter.
...@@ -9363,11 +9582,6 @@ fn zirParam(...@@ -9363,11 +9582,6 @@ fn zirParam(
93639582
9364 const is_comptime = sema.typeRequiresComptime(param_ty) catch |err| switch (err) {9583 const is_comptime = sema.typeRequiresComptime(param_ty) catch |err| switch (err) {
9365 error.GenericPoison => {9584 error.GenericPoison => {
9366 if (sema.inst_map.contains(inst)) {
9367 // A generic function is about to evaluate to another generic function.
9368 // Return an error instead.
9369 return error.GenericPoison;
9370 }
9371 // The type is not available until the generic instantiation.9585 // The type is not available until the generic instantiation.
9372 // We result the param instruction with a poison value and9586 // We result the param instruction with a poison value and
9373 // insert an anytype parameter.9587 // insert an anytype parameter.
...@@ -9382,46 +9596,6 @@ fn zirParam(...@@ -9382,46 +9596,6 @@ fn zirParam(
9382 else => |e| return e,9596 else => |e| return e,
9383 } or comptime_syntax;9597 } or comptime_syntax;
93849598
9385 if (sema.inst_map.get(inst)) |arg| {
9386 if (is_comptime and sema.generic_owner != .none) {
9387 // We have a comptime value for this parameter so it should be elided from the
9388 // function type of the function instruction in this block.
9389 const coerced_arg = sema.coerce(block, param_ty, arg, .unneeded) catch |err| switch (err) {
9390 error.NeededSourceLocation => {
9391 // We are instantiating a generic function and a comptime arg
9392 // cannot be coerced to the param type, but since we don't
9393 // have the callee source location return `GenericPoison`
9394 // so that the instantiation is failed and the coercion
9395 // is handled by comptime call logic instead.
9396 assert(sema.generic_owner != .none);
9397 return error.GenericPoison;
9398 },
9399 else => |e| return e,
9400 };
9401 sema.inst_map.putAssumeCapacity(inst, coerced_arg);
9402 if (try sema.resolveMaybeUndefVal(coerced_arg)) |val| {
9403 sema.comptime_args[param_index] = val.toIntern();
9404 return;
9405 }
9406 const msg = msg: {
9407 const src_loc = sema.genericArgSrcLoc(block, param_index, src);
9408 const msg = try Module.ErrorMsg.create(gpa, src_loc, "{s}", .{
9409 @as([]const u8, "runtime-known argument passed to comptime parameter"),
9410 });
9411 errdefer msg.destroy(gpa);
9412
9413 if (sema.generic_call_decl != .none) {
9414 try sema.errNote(block, src, msg, "{s}", .{@as([]const u8, "declared comptime here")});
9415 }
9416 break :msg msg;
9417 };
9418 return sema.failWithOwnedErrorMsg(msg);
9419 }
9420 // Even though a comptime argument is provided, the generic function wants to treat
9421 // this as a runtime parameter.
9422 assert(sema.inst_map.remove(inst));
9423 }
9424
9425 try block.params.append(sema.arena, .{9599 try block.params.append(sema.arena, .{
9426 .ty = param_ty.toIntern(),9600 .ty = param_ty.toIntern(),
9427 .is_comptime = comptime_syntax,9601 .is_comptime = comptime_syntax,
...@@ -9447,75 +9621,10 @@ fn zirParamAnytype(...@@ -9447,75 +9621,10 @@ fn zirParamAnytype(
9447 sema: *Sema,9621 sema: *Sema,
9448 block: *Block,9622 block: *Block,
9449 inst: Zir.Inst.Index,9623 inst: Zir.Inst.Index,
9450 param_index: u32,
9451 comptime_syntax: bool,9624 comptime_syntax: bool,
9452) CompileError!void {9625) CompileError!void {
9453 const gpa = sema.gpa;
9454 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;9626 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
9455 const param_name: Zir.NullTerminatedString = @enumFromInt(inst_data.start);9627 const param_name: Zir.NullTerminatedString = @enumFromInt(inst_data.start);
9456 const src = inst_data.src();
9457
9458 if (sema.inst_map.get(inst)) |air_ref| {
9459 const param_ty = sema.typeOf(air_ref);
9460 // If we have a comptime value for this parameter, it should be elided
9461 // from the function type of the function instruction in this block.
9462 if (try sema.typeHasOnePossibleValue(param_ty)) |opv| {
9463 sema.comptime_args[param_index] = opv.toIntern();
9464 return;
9465 }
9466
9467 if (comptime_syntax) {
9468 if (try sema.resolveMaybeUndefVal(air_ref)) |val| {
9469 sema.comptime_args[param_index] = val.toIntern();
9470 return;
9471 }
9472 const msg = msg: {
9473 const src_loc = sema.genericArgSrcLoc(block, param_index, src);
9474 const msg = try Module.ErrorMsg.create(gpa, src_loc, "{s}", .{
9475 @as([]const u8, "runtime-known argument passed to comptime parameter"),
9476 });
9477 errdefer msg.destroy(gpa);
9478
9479 if (sema.generic_call_decl != .none) {
9480 try sema.errNote(block, src, msg, "{s}", .{@as([]const u8, "declared comptime here")});
9481 }
9482 break :msg msg;
9483 };
9484 return sema.failWithOwnedErrorMsg(msg);
9485 }
9486
9487 if (try sema.typeRequiresComptime(param_ty)) {
9488 if (try sema.resolveMaybeUndefVal(air_ref)) |val| {
9489 sema.comptime_args[param_index] = val.toIntern();
9490 return;
9491 }
9492 const msg = msg: {
9493 const src_loc = sema.genericArgSrcLoc(block, param_index, src);
9494 const msg = try Module.ErrorMsg.create(gpa, src_loc, "{s}", .{
9495 @as([]const u8, "runtime-known argument passed to comptime-only type parameter"),
9496 });
9497 errdefer msg.destroy(gpa);
9498
9499 if (sema.generic_call_decl != .none) {
9500 try sema.errNote(block, src, msg, "{s}", .{@as([]const u8, "declared here")});
9501 }
9502
9503 try sema.explainWhyTypeIsComptime(msg, src_loc, param_ty);
9504
9505 break :msg msg;
9506 };
9507 return sema.failWithOwnedErrorMsg(msg);
9508 }
9509
9510 // The parameter is runtime-known.
9511 // The map is already populated but we do need to add a runtime parameter.
9512 try block.params.append(sema.arena, .{
9513 .ty = param_ty.toIntern(),
9514 .is_comptime = false,
9515 .name = param_name,
9516 });
9517 return;
9518 }
95199628
9520 // We are evaluating a generic function without any comptime args provided.9629 // We are evaluating a generic function without any comptime args provided.
95219630
...@@ -23152,7 +23261,21 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -23152,7 +23261,21 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
23152 const callee_ty = sema.typeOf(func);23261 const callee_ty = sema.typeOf(func);
23153 const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false);23262 const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false);
23154 const ensure_result_used = extra.flags.ensure_result_used;23263 const ensure_result_used = extra.flags.ensure_result_used;
23155 return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null, .@"@call");23264 return sema.analyzeCall(
23265 block,
23266 func,
23267 func_ty,
23268 func_src,
23269 call_src,
23270 modifier,
23271 ensure_result_used,
23272 .{ .call_builtin = .{
23273 .call_node_offset = inst_data.src_node,
23274 .args = resolved_args,
23275 } },
23276 null,
23277 .@"@call",
23278 );
23156}23279}
2315723280
23158fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {23281fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
test/behavior/call.zig+61
...@@ -430,3 +430,64 @@ test "method call as parameter type" {...@@ -430,3 +430,64 @@ test "method call as parameter type" {
430 try expectEqual(@as(u64, 123), S.foo(S{}, 123));430 try expectEqual(@as(u64, 123), S.foo(S{}, 123));
431 try expectEqual(@as(u64, 500), S.foo(S{}, 500));431 try expectEqual(@as(u64, 500), S.foo(S{}, 500));
432}432}
433
434test "non-anytype generic parameters provide result type" {
435 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
436 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
437 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
438 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
439 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
440 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
441
442 const S = struct {
443 fn f(comptime T: type, y: T) !void {
444 try expectEqual(@as(T, 123), y);
445 }
446
447 fn g(x: anytype, y: @TypeOf(x)) !void {
448 try expectEqual(@as(@TypeOf(x), 0x222), y);
449 }
450 };
451
452 var rt_u16: u16 = 123;
453 var rt_u32: u32 = 0x10000222;
454
455 try S.f(u8, @intCast(rt_u16));
456 try S.f(u8, @intCast(123));
457
458 try S.g(rt_u16, @truncate(rt_u32));
459 try S.g(rt_u16, @truncate(0x10000222));
460
461 try comptime S.f(u8, @intCast(123));
462 try comptime S.g(@as(u16, undefined), @truncate(0x99990222));
463}
464
465test "argument to generic function has correct result type" {
466 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
467 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
470 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
471 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
472
473 const S = struct {
474 fn foo(_: anytype, e: enum { a, b }) bool {
475 return e == .b;
476 }
477
478 fn doTheTest() !void {
479 var t = true;
480
481 // Since the enum literal passes through a runtime conditional here, these can only
482 // compile if RLS provides the correct result type to the argument
483 try expect(foo({}, if (!t) .a else .b));
484 try expect(!foo("dummy", if (t) .a else .b));
485 try expect(foo({}, if (t) .b else .a));
486 try expect(!foo(123, if (t) .a else .a));
487 try expect(foo(123, if (t) .b else .b));
488 }
489 };
490
491 try S.doTheTest();
492 try comptime S.doTheTest();
493}