authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-05 05:27:48+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-09 06:46:47+00:00
loge9bd2d45d4bbaf7eff7e95bc3ef7a0123b66a103
treeda18bc40935c7dd9698d792eae3d102fa0ad67ae
parent3f95003d4c57650f9b4779f55c8d7368b137337c
signaturelock-open Commit is signed but in an unrecognized format.

Sema: rewrite semantic analysis of function calls

This rewrite improves some error messages, hugely simplifies the logic, and fixes several bugs. One of these bugs is technically a new rule which Andrew and I agreed on: if a parameter has a comptime-only type but is not declared `comptime`, then the corresponding call argument should not be *evaluated* at comptime; only resolved. Implementing this required changing how function types work a little, which in turn required allowing a new kind of function coercion for some generic use cases: function coercions are now allowed to implicitly *remove* `comptime` annotations from parameters with comptime-only types. This is okay because removing the annotation affects only the call site. Resolves: #22262

36 files changed, 797 insertions(+), 1176 deletions(-)

lib/compiler/aro_translate_c.zig+1
...@@ -168,6 +168,7 @@ pub fn translate(...@@ -168,6 +168,7 @@ pub fn translate(
168 context.pattern_list.deinit(gpa);168 context.pattern_list.deinit(gpa);
169 }169 }
170170
171 @setEvalBranchQuota(2000);
171 inline for (@typeInfo(std.zig.c_builtins).@"struct".decls) |decl| {172 inline for (@typeInfo(std.zig.c_builtins).@"struct".decls) |decl| {
172 const builtin_fn = try ZigTag.pub_var_simple.create(arena, .{173 const builtin_fn = try ZigTag.pub_var_simple.create(arena, .{
173 .name = decl.name,174 .name = decl.name,
lib/std/math/log_int.zig+1
...@@ -61,6 +61,7 @@ pub fn log_int(comptime T: type, base: T, x: T) Log2Int(T) {...@@ -61,6 +61,7 @@ pub fn log_int(comptime T: type, base: T, x: T) Log2Int(T) {
61}61}
6262
63test "log_int" {63test "log_int" {
64 @setEvalBranchQuota(2000);
64 // Test all unsigned integers with 2, 3, ..., 64 bits.65 // Test all unsigned integers with 2, 3, ..., 64 bits.
65 // We cannot test 0 or 1 bits since base must be > 1.66 // We cannot test 0 or 1 bits since base must be > 1.
66 inline for (2..64 + 1) |bits| {67 inline for (2..64 + 1) |bits| {
lib/std/os/windows.zig+1
...@@ -1468,6 +1468,7 @@ fn mountmgrIsVolumeName(name: []const u16) bool {...@@ -1468,6 +1468,7 @@ fn mountmgrIsVolumeName(name: []const u16) bool {
1468}1468}
14691469
1470test mountmgrIsVolumeName {1470test mountmgrIsVolumeName {
1471 @setEvalBranchQuota(2000);
1471 const L = std.unicode.utf8ToUtf16LeStringLiteral;1472 const L = std.unicode.utf8ToUtf16LeStringLiteral;
1472 try std.testing.expect(mountmgrIsVolumeName(L("\\\\?\\Volume{383da0b0-717f-41b6-8c36-00500992b58d}")));1473 try std.testing.expect(mountmgrIsVolumeName(L("\\\\?\\Volume{383da0b0-717f-41b6-8c36-00500992b58d}")));
1473 try std.testing.expect(mountmgrIsVolumeName(L("\\??\\Volume{383da0b0-717f-41b6-8c36-00500992b58d}")));1474 try std.testing.expect(mountmgrIsVolumeName(L("\\??\\Volume{383da0b0-717f-41b6-8c36-00500992b58d}")));
lib/std/zig.zig+4-2
...@@ -749,6 +749,8 @@ pub const SimpleComptimeReason = enum(u32) {...@@ -749,6 +749,8 @@ pub const SimpleComptimeReason = enum(u32) {
749 array_mul_factor,749 array_mul_factor,
750 slice_cat_operand,750 slice_cat_operand,
751 comptime_call_target,751 comptime_call_target,
752 inline_call_target,
753 generic_call_target,
752 wasm_memory_index,754 wasm_memory_index,
753 work_group_dim_index,755 work_group_dim_index,
754756
...@@ -791,7 +793,6 @@ pub const SimpleComptimeReason = enum(u32) {...@@ -791,7 +793,6 @@ pub const SimpleComptimeReason = enum(u32) {
791 struct_field_default_value,793 struct_field_default_value,
792 enum_field_tag_value,794 enum_field_tag_value,
793 slice_single_item_ptr_bounds,795 slice_single_item_ptr_bounds,
794 comptime_param_arg,
795 stored_to_comptime_field,796 stored_to_comptime_field,
796 stored_to_comptime_var,797 stored_to_comptime_var,
797 casted_to_comptime_enum,798 casted_to_comptime_enum,
...@@ -828,6 +829,8 @@ pub const SimpleComptimeReason = enum(u32) {...@@ -828,6 +829,8 @@ pub const SimpleComptimeReason = enum(u32) {
828 .array_mul_factor => "array multiplication factor must be comptime-known",829 .array_mul_factor => "array multiplication factor must be comptime-known",
829 .slice_cat_operand => "slice being concatenated must be comptime-known",830 .slice_cat_operand => "slice being concatenated must be comptime-known",
830 .comptime_call_target => "function being called at comptime must be comptime-known",831 .comptime_call_target => "function being called at comptime must be comptime-known",
832 .inline_call_target => "function being called inline must be comptime-known",
833 .generic_call_target => "generic function being called must be comptime-known",
831 .wasm_memory_index => "wasm memory index must be comptime-known",834 .wasm_memory_index => "wasm memory index must be comptime-known",
832 .work_group_dim_index => "work group dimension index must be comptime-known",835 .work_group_dim_index => "work group dimension index must be comptime-known",
833836
...@@ -865,7 +868,6 @@ pub const SimpleComptimeReason = enum(u32) {...@@ -865,7 +868,6 @@ pub const SimpleComptimeReason = enum(u32) {
865 .struct_field_default_value => "struct field default value must be comptime-known",868 .struct_field_default_value => "struct field default value must be comptime-known",
866 .enum_field_tag_value => "enum field tag value must be comptime-known",869 .enum_field_tag_value => "enum field tag value must be comptime-known",
867 .slice_single_item_ptr_bounds => "slice of single-item pointer must have comptime-known bounds",870 .slice_single_item_ptr_bounds => "slice of single-item pointer must have comptime-known bounds",
868 .comptime_param_arg => "argument to comptime parameter must be comptime-known",
869 .stored_to_comptime_field => "value stored to a comptime field must be comptime-known",871 .stored_to_comptime_field => "value stored to a comptime field must be comptime-known",
870 .stored_to_comptime_var => "value stored to a comptime variable must be comptime-known",872 .stored_to_comptime_var => "value stored to a comptime variable must be comptime-known",
871 .casted_to_comptime_enum => "value casted to enum with 'comptime_int' tag type must be comptime-known",873 .casted_to_comptime_enum => "value casted to enum with 'comptime_int' tag type must be comptime-known",
lib/std/zig/AstGen.zig-3
...@@ -10209,9 +10209,6 @@ fn callExpr(...@@ -10209,9 +10209,6 @@ fn callExpr(
1020910209
10210 const callee = try calleeExpr(gz, scope, ri.rl, call.ast.fn_expr);10210 const callee = try calleeExpr(gz, scope, ri.rl, call.ast.fn_expr);
10211 const modifier: std.builtin.CallModifier = blk: {10211 const modifier: std.builtin.CallModifier = blk: {
10212 if (gz.is_comptime) {
10213 break :blk .compile_time;
10214 }
10215 if (call.async_token != null) {10212 if (call.async_token != null) {
10216 break :blk .async_kw;10213 break :blk .async_kw;
10217 }10214 }
lib/std/zig/Zir.zig+9-2
...@@ -4735,6 +4735,7 @@ pub const FnInfo = struct {...@@ -4735,6 +4735,7 @@ pub const FnInfo = struct {
4735 body: []const Inst.Index,4735 body: []const Inst.Index,
4736 ret_ty_ref: Zir.Inst.Ref,4736 ret_ty_ref: Zir.Inst.Ref,
4737 total_params_len: u32,4737 total_params_len: u32,
4738 inferred_error_set: bool,
4738};4739};
47394740
4740pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index {4741pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index {
...@@ -4774,8 +4775,9 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -4774,8 +4775,9 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
4774 body: []const Inst.Index,4775 body: []const Inst.Index,
4775 ret_ty_ref: Inst.Ref,4776 ret_ty_ref: Inst.Ref,
4776 ret_ty_body: []const Inst.Index,4777 ret_ty_body: []const Inst.Index,
4778 ies: bool,
4777 } = switch (tags[@intFromEnum(fn_inst)]) {4779 } = switch (tags[@intFromEnum(fn_inst)]) {
4778 .func, .func_inferred => blk: {4780 .func, .func_inferred => |tag| blk: {
4779 const inst_data = datas[@intFromEnum(fn_inst)].pl_node;4781 const inst_data = datas[@intFromEnum(fn_inst)].pl_node;
4780 const extra = zir.extraData(Inst.Func, inst_data.payload_index);4782 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
47814783
...@@ -4805,6 +4807,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -4805,6 +4807,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
4805 .ret_ty_ref = ret_ty_ref,4807 .ret_ty_ref = ret_ty_ref,
4806 .ret_ty_body = ret_ty_body,4808 .ret_ty_body = ret_ty_body,
4807 .body = body,4809 .body = body,
4810 .ies = tag == .func_inferred,
4808 };4811 };
4809 },4812 },
4810 .func_fancy => blk: {4813 .func_fancy => blk: {
...@@ -4812,7 +4815,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -4812,7 +4815,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
4812 const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);4815 const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
48134816
4814 var extra_index: usize = extra.end;4817 var extra_index: usize = extra.end;
4815 var ret_ty_ref: Inst.Ref = .void_type;4818 var ret_ty_ref: Inst.Ref = .none;
4816 var ret_ty_body: []const Inst.Index = &.{};4819 var ret_ty_body: []const Inst.Index = &.{};
48174820
4818 if (extra.data.bits.has_cc_body) {4821 if (extra.data.bits.has_cc_body) {
...@@ -4828,6 +4831,8 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -4828,6 +4831,8 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
4828 } else if (extra.data.bits.has_ret_ty_ref) {4831 } else if (extra.data.bits.has_ret_ty_ref) {
4829 ret_ty_ref = @enumFromInt(zir.extra[extra_index]);4832 ret_ty_ref = @enumFromInt(zir.extra[extra_index]);
4830 extra_index += 1;4833 extra_index += 1;
4834 } else {
4835 ret_ty_ref = .void_type;
4831 }4836 }
48324837
4833 extra_index += @intFromBool(extra.data.bits.has_any_noalias);4838 extra_index += @intFromBool(extra.data.bits.has_any_noalias);
...@@ -4839,6 +4844,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -4839,6 +4844,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
4839 .ret_ty_ref = ret_ty_ref,4844 .ret_ty_ref = ret_ty_ref,
4840 .ret_ty_body = ret_ty_body,4845 .ret_ty_body = ret_ty_body,
4841 .body = body,4846 .body = body,
4847 .ies = extra.data.bits.is_inferred_error,
4842 };4848 };
4843 },4849 },
4844 else => unreachable,4850 else => unreachable,
...@@ -4860,6 +4866,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {...@@ -4860,6 +4866,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
4860 .ret_ty_ref = info.ret_ty_ref,4866 .ret_ty_ref = info.ret_ty_ref,
4861 .body = info.body,4867 .body = info.body,
4862 .total_params_len = total_params_len,4868 .total_params_len = total_params_len,
4869 .inferred_error_set = info.ies,
4863 };4870 };
4864}4871}
48654872
src/Sema.zig+665-1067
...@@ -46,21 +46,6 @@ branch_count: u32 = 0,...@@ -46,21 +46,6 @@ branch_count: u32 = 0,
46/// Populated when returning `error.ComptimeBreak`. Used to communicate the46/// Populated when returning `error.ComptimeBreak`. Used to communicate the
47/// break instruction up the stack to find the corresponding Block.47/// break instruction up the stack to find the corresponding Block.
48comptime_break_inst: Zir.Inst.Index = undefined,48comptime_break_inst: Zir.Inst.Index = undefined,
49/// When doing a generic function instantiation, this array collects a value
50/// for each parameter of the generic owner. `none` for non-comptime parameters.
51/// This is a separate array from `block.params` so that it can be passed
52/// directly to `comptime_args` when calling `InternPool.getFuncInstance`.
53/// This memory is allocated by a parent `Sema` in the temporary arena, and is
54/// used only to add a `func_instance` into the `InternPool`.
55comptime_args: []InternPool.Index = &.{},
56/// Used to communicate from a generic function instantiation to the logic that
57/// creates a generic function instantiation value in `funcCommon`.
58generic_owner: InternPool.Index = .none,
59/// When `generic_owner` is not none, this contains the generic function
60/// instantiation callsite so that compile errors on the parameter types of the
61/// instantiation can point back to the instantiation site in addition to the
62/// declaration site.
63generic_call_src: LazySrcLoc = LazySrcLoc.unneeded,
64/// These are lazily created runtime blocks from block_inline instructions.49/// These are lazily created runtime blocks from block_inline instructions.
65/// They are created when an break_inline passes through a runtime condition, because50/// They are created when an break_inline passes through a runtime condition, because
66/// Sema must convert comptime control flow to runtime control flow, which means51/// Sema must convert comptime control flow to runtime control flow, which means
...@@ -862,12 +847,29 @@ const ComptimeReason = union(enum) {...@@ -862,12 +847,29 @@ const ComptimeReason = union(enum) {
862 union_init,847 union_init,
863 struct_init,848 struct_init,
864 tuple_init,849 tuple_init,
865 param_ty_arg,
866 ret_ty_call,
867 ret_ty_generic_call,
868 },850 },
869 },851 },
870852
853 /// Like `comptime_only`, but for a parameter type.
854 /// Includes a "parameter type declared here" note.
855 comptime_only_param_ty: struct {
856 ty: Type,
857 param_ty_src: LazySrcLoc,
858 },
859
860 /// Like `comptime_only`, but for a return type.
861 /// Includes a "return type declared here" note.
862 comptime_only_ret_ty: struct {
863 ty: Type,
864 is_generic_inst: bool,
865 ret_ty_src: LazySrcLoc,
866 },
867
868 /// Evaluating at comptime because we're evaluating an argument to a parameter marked `comptime`.
869 comptime_param: struct {
870 comptime_src: LazySrcLoc,
871 },
872
871 fn explain(reason: ComptimeReason, sema: *Sema, src: LazySrcLoc, err_msg: *Zcu.ErrorMsg) !void {873 fn explain(reason: ComptimeReason, sema: *Sema, src: LazySrcLoc, err_msg: *Zcu.ErrorMsg) !void {
872 switch (reason) {874 switch (reason) {
873 .simple => |simple| {875 .simple => |simple| {
...@@ -878,13 +880,25 @@ const ComptimeReason = union(enum) {...@@ -878,13 +880,25 @@ const ComptimeReason = union(enum) {
878 .union_init => .{ "initializer of comptime-only union", "must be comptime-known" },880 .union_init => .{ "initializer of comptime-only union", "must be comptime-known" },
879 .struct_init => .{ "initializer of comptime-only struct", "must be comptime-known" },881 .struct_init => .{ "initializer of comptime-only struct", "must be comptime-known" },
880 .tuple_init => .{ "initializer of comptime-only tuple", "must be comptime-known" },882 .tuple_init => .{ "initializer of comptime-only tuple", "must be comptime-known" },
881 .param_ty_arg => .{ "argument to parameter with comptime-only type", "must be comptime-known" },
882 .ret_ty_call => .{ "function with comptime-only return type", "is evaluated at comptime" },
883 .ret_ty_generic_call => .{ "generic function instantiated with comptime-only return type", "is evaluated at comptime" },
884 };883 };
885 try sema.errNote(src, err_msg, "{s} '{}' {s}", .{ pre, co.ty.fmt(sema.pt), post });884 try sema.errNote(src, err_msg, "{s} '{}' {s}", .{ pre, co.ty.fmt(sema.pt), post });
886 try sema.explainWhyTypeIsComptime(err_msg, src, co.ty);885 try sema.explainWhyTypeIsComptime(err_msg, src, co.ty);
887 },886 },
887 .comptime_only_param_ty => |co| {
888 try sema.errNote(src, err_msg, "argument to parameter with comptime-only type '{}' must be comptime-known", .{co.ty.fmt(sema.pt)});
889 try sema.errNote(co.param_ty_src, err_msg, "parameter type declared here", .{});
890 try sema.explainWhyTypeIsComptime(err_msg, src, co.ty);
891 },
892 .comptime_only_ret_ty => |co| {
893 const function_with: []const u8 = if (co.is_generic_inst) "generic function instantiated with" else "function with";
894 try sema.errNote(src, err_msg, "call to {s} comptime-only return type '{}' is evaluated at comptime", .{ function_with, co.ty.fmt(sema.pt) });
895 try sema.errNote(co.ret_ty_src, err_msg, "return type declared here", .{});
896 try sema.explainWhyTypeIsComptime(err_msg, src, co.ty);
897 },
898 .comptime_param => |cp| {
899 try sema.errNote(src, err_msg, "argument to comptime parameter must be comptime-known", .{});
900 try sema.errNote(cp.comptime_src, err_msg, "parameter declared comptime here", .{});
901 },
888 }902 }
889 }903 }
890};904};
...@@ -7423,8 +7437,9 @@ const CallArgsInfo = union(enum) {...@@ -7423,8 +7437,9 @@ const CallArgsInfo = union(enum) {
74237437
7424 /// Analyzes the arg at `arg_index` and coerces it to `param_ty`.7438 /// Analyzes the arg at `arg_index` and coerces it to `param_ty`.
7425 /// `param_ty` may be `generic_poison`. A value of `null` indicates a varargs parameter.7439 /// `param_ty` may be `generic_poison`. A value of `null` indicates a varargs parameter.
7426 /// `func_ty_info` may be the type before instantiation, even if a generic7440 /// `func_ty_info` may be the type before instantiation, even if a generic instantiation is in progress.
7427 /// instantiation has been partially completed.7441 /// Emits a compile error if the argument is not comptime-known despite either `block.isComptime()` or
7442 /// the parameter being marked `comptime`.
7428 fn analyzeArg(7443 fn analyzeArg(
7429 cai: CallArgsInfo,7444 cai: CallArgsInfo,
7430 sema: *Sema,7445 sema: *Sema,
...@@ -7433,6 +7448,7 @@ const CallArgsInfo = union(enum) {...@@ -7433,6 +7448,7 @@ const CallArgsInfo = union(enum) {
7433 maybe_param_ty: ?Type,7448 maybe_param_ty: ?Type,
7434 func_ty_info: InternPool.Key.FuncType,7449 func_ty_info: InternPool.Key.FuncType,
7435 func_inst: Air.Inst.Ref,7450 func_inst: Air.Inst.Ref,
7451 maybe_func_src_inst: ?InternPool.TrackedInst.Index,
7436 ) CompileError!Air.Inst.Ref {7452 ) CompileError!Air.Inst.Ref {
7437 const pt = sema.pt;7453 const pt = sema.pt;
7438 const zcu = pt.zcu;7454 const zcu = pt.zcu;
...@@ -7460,11 +7476,22 @@ const CallArgsInfo = union(enum) {...@@ -7460,11 +7476,22 @@ const CallArgsInfo = union(enum) {
7460 const parent_comptime = block.comptime_reason;7476 const parent_comptime = block.comptime_reason;
7461 defer block.comptime_reason = parent_comptime;7477 defer block.comptime_reason = parent_comptime;
7462 // Note that we are indexing into parameters, not arguments, so use `arg_index` instead of `real_arg_idx`7478 // Note that we are indexing into parameters, not arguments, so use `arg_index` instead of `real_arg_idx`
7463 if (arg_index < @min(param_count, 32) and func_ty_info.paramIsComptime(@intCast(arg_index))) {7479 if (std.math.cast(u5, arg_index)) |i| {
7464 block.comptime_reason = .{ .reason = .{7480 if (i < param_count and func_ty_info.paramIsComptime(i)) {
7465 .src = cai.argSrc(block, arg_index),7481 block.comptime_reason = .{
7466 .r = .{ .simple = .comptime_param_arg },7482 .reason = .{
7467 } };7483 .src = cai.argSrc(block, arg_index),
7484 .r = .{
7485 .comptime_param = .{
7486 .comptime_src = if (maybe_func_src_inst) |src_inst| .{
7487 .base_node_inst = src_inst,
7488 .offset = .{ .func_decl_param_comptime = @intCast(arg_index) },
7489 } else unreachable, // should be non-null because the function is generic
7490 },
7491 },
7492 },
7493 };
7494 }
7468 }7495 }
7469 // Give the arg its result type7496 // Give the arg its result type
7470 const provide_param_ty = if (maybe_param_ty) |t| t else Type.generic_poison;7497 const provide_param_ty = if (maybe_param_ty) |t| t else Type.generic_poison;
...@@ -7472,6 +7499,10 @@ const CallArgsInfo = union(enum) {...@@ -7472,6 +7499,10 @@ const CallArgsInfo = union(enum) {
7472 // Resolve the arg!7499 // Resolve the arg!
7473 const uncoerced_arg = try sema.resolveInlineBody(block, arg_body, zir_call.call_inst);7500 const uncoerced_arg = try sema.resolveInlineBody(block, arg_body, zir_call.call_inst);
74747501
7502 if (block.isComptime() and !try sema.isComptimeKnown(uncoerced_arg)) {
7503 return sema.failWithNeededComptime(block, cai.argSrc(block, arg_index), null);
7504 }
7505
7475 if (sema.typeOf(uncoerced_arg).zigTypeTag(zcu) == .noreturn) {7506 if (sema.typeOf(uncoerced_arg).zigTypeTag(zcu) == .noreturn) {
7476 // This terminates resolution of arguments. The caller should7507 // This terminates resolution of arguments. The caller should
7477 // propagate this.7508 // propagate this.
...@@ -7507,104 +7538,10 @@ const CallArgsInfo = union(enum) {...@@ -7507,104 +7538,10 @@ const CallArgsInfo = union(enum) {
7507 }7538 }
7508};7539};
75097540
7510/// While performing an inline call, we need to switch between two Sema states a few times: the
7511/// state for the caller (with the callee's `code`, `fn_ret_ty`, etc), and the state for the callee.
7512/// These cannot be two separate Sema instances as they must share AIR.
7513/// Therefore, this struct acts as a helper to switch between the two.
7514/// This switching is required during argument evaluation, where function argument analysis must be
7515/// interleaved with resolving generic parameter types.
7516const InlineCallSema = struct {
7517 sema: *Sema,
7518 cur: enum {
7519 caller,
7520 callee,
7521 },
7522
7523 other_code: Zir,
7524 other_func_index: InternPool.Index,
7525 other_fn_ret_ty: Type,
7526 other_fn_ret_ty_ies: ?*InferredErrorSet,
7527 other_inst_map: InstMap,
7528 other_error_return_trace_index_on_fn_entry: Air.Inst.Ref,
7529 other_generic_owner: InternPool.Index,
7530 other_generic_call_src: LazySrcLoc,
7531
7532 /// Sema should currently be set up for the caller (i.e. unchanged yet). This init will not
7533 /// change that. The other parameters contain data for the callee Sema. The other modified
7534 /// Sema fields are all initialized to default values for the callee.
7535 /// Must call deinit on the result.
7536 fn init(
7537 sema: *Sema,
7538 callee_code: Zir,
7539 callee_func_index: InternPool.Index,
7540 callee_error_return_trace_index_on_fn_entry: Air.Inst.Ref,
7541 ) InlineCallSema {
7542 return .{
7543 .sema = sema,
7544 .cur = .caller,
7545 .other_code = callee_code,
7546 .other_func_index = callee_func_index,
7547 .other_fn_ret_ty = Type.void,
7548 .other_fn_ret_ty_ies = null,
7549 .other_inst_map = .{},
7550 .other_error_return_trace_index_on_fn_entry = callee_error_return_trace_index_on_fn_entry,
7551 .other_generic_owner = .none,
7552 .other_generic_call_src = LazySrcLoc.unneeded,
7553 };
7554 }
7555
7556 /// Switch back to the caller Sema if necessary and free all temporary state of the callee Sema.
7557 fn deinit(ics: *InlineCallSema) void {
7558 switch (ics.cur) {
7559 .caller => {},
7560 .callee => ics.swap(),
7561 }
7562 // Callee Sema owns the inst_map memory
7563 ics.other_inst_map.deinit(ics.sema.gpa);
7564 ics.* = undefined;
7565 }
7566
7567 /// Returns a Sema instance suitable for usage from the caller context.
7568 fn caller(ics: *InlineCallSema) *Sema {
7569 switch (ics.cur) {
7570 .caller => {},
7571 .callee => ics.swap(),
7572 }
7573 return ics.sema;
7574 }
7575
7576 /// Returns a Sema instance suitable for usage from the callee context.
7577 fn callee(ics: *InlineCallSema) *Sema {
7578 switch (ics.cur) {
7579 .caller => ics.swap(),
7580 .callee => {},
7581 }
7582 return ics.sema;
7583 }
7584
7585 /// Internal use only. Swaps to the other Sema state.
7586 fn swap(ics: *InlineCallSema) void {
7587 ics.cur = switch (ics.cur) {
7588 .caller => .callee,
7589 .callee => .caller,
7590 };
7591 // zig fmt: off
7592 std.mem.swap(Zir, &ics.sema.code, &ics.other_code);
7593 std.mem.swap(InternPool.Index, &ics.sema.func_index, &ics.other_func_index);
7594 std.mem.swap(Type, &ics.sema.fn_ret_ty, &ics.other_fn_ret_ty);
7595 std.mem.swap(?*InferredErrorSet, &ics.sema.fn_ret_ty_ies, &ics.other_fn_ret_ty_ies);
7596 std.mem.swap(InstMap, &ics.sema.inst_map, &ics.other_inst_map);
7597 std.mem.swap(InternPool.Index, &ics.sema.generic_owner, &ics.other_generic_owner);
7598 std.mem.swap(LazySrcLoc, &ics.sema.generic_call_src, &ics.other_generic_call_src);
7599 std.mem.swap(Air.Inst.Ref, &ics.sema.error_return_trace_index_on_fn_entry, &ics.other_error_return_trace_index_on_fn_entry);
7600 // zig fmt: on
7601 }
7602};
7603
7604fn analyzeCall(7541fn analyzeCall(
7605 sema: *Sema,7542 sema: *Sema,
7606 block: *Block,7543 block: *Block,
7607 func: Air.Inst.Ref,7544 callee: Air.Inst.Ref,
7608 func_ty: Type,7545 func_ty: Type,
7609 func_src: LazySrcLoc,7546 func_src: LazySrcLoc,
7610 call_src: LazySrcLoc,7547 call_src: LazySrcLoc,
...@@ -7616,983 +7553,696 @@ fn analyzeCall(...@@ -7616,983 +7553,696 @@ fn analyzeCall(
7616) CompileError!Air.Inst.Ref {7553) CompileError!Air.Inst.Ref {
7617 const pt = sema.pt;7554 const pt = sema.pt;
7618 const zcu = pt.zcu;7555 const zcu = pt.zcu;
7556 const gpa = zcu.gpa;
7619 const ip = &zcu.intern_pool;7557 const ip = &zcu.intern_pool;
7558 const arena = sema.arena;
7559
7560 if (modifier == .async_kw) {
7561 return sema.failWithUseOfAsync(block, call_src);
7562 }
7563
7564 const maybe_func_inst = try sema.funcDeclSrcInst(callee);
7565 const func_ret_ty_src: LazySrcLoc = if (maybe_func_inst) |fn_decl_inst| .{
7566 .base_node_inst = fn_decl_inst,
7567 .offset = .{ .node_offset_fn_type_ret_ty = 0 },
7568 } else func_src;
76207569
7621 const callee_ty = sema.typeOf(func);
7622 const func_ty_info = zcu.typeToFunc(func_ty).?;7570 const func_ty_info = zcu.typeToFunc(func_ty).?;
7623 const cc = func_ty_info.cc;7571 if (!callConvIsCallable(func_ty_info.cc)) {
7624 if (try sema.resolveValue(func)) |func_val|7572 return sema.failWithOwnedErrorMsg(block, msg: {
7625 if (func_val.isUndef(zcu))
7626 return sema.failWithUseOfUndef(block, call_src);
7627 if (!callConvIsCallable(cc)) {
7628 const maybe_func_inst = try sema.funcDeclSrcInst(func);
7629 const msg = msg: {
7630 const msg = try sema.errMsg(7573 const msg = try sema.errMsg(
7631 func_src,7574 func_src,
7632 "unable to call function with calling convention '{s}'",7575 "unable to call function with calling convention '{s}'",
7633 .{@tagName(cc)},7576 .{@tagName(func_ty_info.cc)},
7634 );7577 );
7635 errdefer msg.destroy(sema.gpa);7578 errdefer msg.destroy(gpa);
7636
7637 if (maybe_func_inst) |func_inst| try sema.errNote(.{7579 if (maybe_func_inst) |func_inst| try sema.errNote(.{
7638 .base_node_inst = func_inst,7580 .base_node_inst = func_inst,
7639 .offset = LazySrcLoc.Offset.nodeOffset(0),7581 .offset = .nodeOffset(0),
7640 }, msg, "function declared here", .{});7582 }, msg, "function declared here", .{});
7641 break :msg msg;7583 break :msg msg;
7642 };7584 });
7643 return sema.failWithOwnedErrorMsg(block, msg);
7644 }7585 }
76457586
7646 const call_tag: Air.Inst.Tag = switch (modifier) {7587 // We need this value in a few code paths.
7647 .auto,7588 const callee_val = try sema.resolveDefinedValue(block, call_src, callee);
7648 .always_inline,7589 // If the callee is a comptime-known *non-extern* function, `func_val` is populated.
7649 .compile_time,7590 // If it is a comptime-known extern function, `func_is_extern` is set instead.
7650 .no_async,7591 // If it is not comptime-known, neither is set.
7651 => Air.Inst.Tag.call,7592 const func_val: ?Value, const func_is_extern: bool = if (callee_val) |c| switch (ip.indexToKey(c.toIntern())) {
76527593 .func => .{ c, false },
7653 .never_tail => Air.Inst.Tag.call_never_tail,7594 .ptr => switch (try sema.pointerDerefExtra(block, func_src, c)) {
7654 .never_inline => Air.Inst.Tag.call_never_inline,7595 .runtime_load, .needed_well_defined, .out_of_bounds => .{ null, false },
7655 .always_tail => Air.Inst.Tag.call_always_tail,7596 .val => |pointee| switch (ip.indexToKey(pointee.toIntern())) {
76567597 .func => .{ pointee, false },
7657 .async_kw => return sema.failWithUseOfAsync(block, call_src),7598 .@"extern" => .{ null, true },
7658 };7599 else => unreachable,
7600 },
7601 },
7602 .@"extern" => .{ null, true },
7603 else => unreachable,
7604 } else .{ null, false };
76597605
7660 if (modifier == .never_inline and func_ty_info.cc == .@"inline") {7606 if (func_ty_info.is_generic and func_val == null) {
7661 return sema.fail(block, call_src, "'never_inline' call of inline function", .{});7607 return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target });
7662 }7608 }
7663 if (modifier == .always_inline and func_ty_info.is_noinline) {
7664 return sema.fail(block, call_src, "'always_inline' call of noinline function", .{});
7665 }
7666
7667 const gpa = sema.gpa;
76687609
7669 const func_ret_ty_src: LazySrcLoc = if (try sema.funcDeclSrcInst(func)) |fn_decl_inst| .{7610 const inline_requested = func_ty_info.cc == .@"inline" or modifier == .always_inline;
7670 .base_node_inst = fn_decl_inst,
7671 .offset = .{ .node_offset_fn_type_ret_ty = 0 },
7672 } else func_src;
76737611
7674 // If this is not `null`, the call is comptime.7612 // If the modifier is `.compile_time`, or if the return type is non-generic and comptime-only,
7675 var comptime_call_reason: ?BlockComptimeReason = cr: {7613 // then we need to enter a comptime scope *now* to make sure the args are comptime-eval'd.
7676 if (block.comptime_reason) |r| break :cr r;7614 const old_block_comptime_reason = block.comptime_reason;
7677 if (modifier == .compile_time) break :cr .{ .reason = .{7615 defer block.comptime_reason = old_block_comptime_reason;
7678 .src = call_src,7616 if (!block.isComptime()) {
7679 .r = .{ .simple = .comptime_call_modifier },7617 if (modifier == .compile_time) {
7680 } };7618 block.comptime_reason = .{ .reason = .{
7681 break :cr null;7619 .src = call_src,
7682 };7620 .r = .{ .simple = .comptime_call_modifier },
7683
7684 const is_generic_call = func_ty_info.is_generic;
7685 var is_inline_call = comptime_call_reason != null or modifier == .always_inline or func_ty_info.cc == .@"inline";
7686 if (!is_inline_call) {
7687 if (try Type.fromInterned(func_ty_info.return_type).comptimeOnlySema(pt)) {
7688 is_inline_call = true;
7689 comptime_call_reason = .{ .reason = .{
7690 .src = func_ret_ty_src,
7691 .r = .{ .comptime_only = .{
7692 .ty = .fromInterned(func_ty_info.return_type),
7693 .msg = .ret_ty_call,
7694 } },
7695 } };7621 } };
7696 }7622 } else if (!inline_requested and try Type.fromInterned(func_ty_info.return_type).comptimeOnlySema(pt)) {
7697 }7623 block.comptime_reason = .{
76987624 .reason = .{
7699 if (sema.func_is_naked and !is_inline_call) {7625 .src = call_src,
7700 const msg = msg: {
7701 const msg = try sema.errMsg(call_src, "runtime {s} not allowed in naked function", .{@tagName(operation)});
7702 errdefer msg.destroy(sema.gpa);
7703
7704 switch (operation) {
7705 .call, .@"@call", .@"@panic", .@"error return" => {},
7706 .@"safety check" => try sema.errNote(call_src, msg, "use @setRuntimeSafety to disable runtime safety", .{}),
7707 }
7708 break :msg msg;
7709 };
7710 return sema.failWithOwnedErrorMsg(block, msg);
7711 }
7712
7713 if (!is_inline_call and is_generic_call) {
7714 var comptime_ret_ty: Type = undefined;
7715 if (sema.instantiateGenericCall(
7716 block,
7717 func,
7718 func_src,
7719 call_src,
7720 ensure_result_used,
7721 args_info,
7722 call_tag,
7723 call_dbg_node,
7724 &comptime_ret_ty,
7725 )) |some| {
7726 return some;
7727 } else |err| switch (err) {
7728 error.GenericPoison => {
7729 is_inline_call = true;
7730 },
7731 error.ComptimeReturn => {
7732 is_inline_call = true;
7733 comptime_call_reason = .{ .reason = .{
7734 .src = func_ret_ty_src,
7735 .r = .{7626 .r = .{
7736 .comptime_only = .{7627 .comptime_only_ret_ty = .{
7737 .ty = comptime_ret_ty,7628 .ty = .fromInterned(func_ty_info.return_type),
7738 .msg = .ret_ty_generic_call,7629 .is_generic_inst = false,
7630 .ret_ty_src = func_ret_ty_src,
7739 },7631 },
7740 },7632 },
7741 } };7633 },
7742 },7634 };
7743 else => |e| return e,
7744 }7635 }
7745 }7636 }
77467637
7747 const is_comptime_call = comptime_call_reason != null;7638 // These values are undefined if `func_val == null`.
7748 // `comptime_call_reason` shouldn't be mutated again7639 const fn_nav: InternPool.Nav, const fn_zir: Zir, const fn_tracked_inst: InternPool.TrackedInst.Index, const fn_zir_inst: Zir.Inst.Index, const fn_zir_info: Zir.FnInfo = if (func_val) |f| b: {
7749 defer assert(is_comptime_call == (comptime_call_reason != null));7640 const info = ip.indexToKey(f.toIntern()).func;
7641 const nav = ip.getNav(info.owner_nav);
7642 const resolved_func_inst = info.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail;
7643 const file = zcu.fileByIndex(resolved_func_inst.file);
7644 assert(file.zir_loaded);
7645 const zir_info = file.zir.getFnInfo(resolved_func_inst.inst);
7646 break :b .{ nav, file.zir, info.zir_body_inst, resolved_func_inst.inst, zir_info };
7647 } else .{ undefined, undefined, undefined, undefined, undefined };
7648
7649 // This is the `inst_map` used when evaluating generic parameters and return types.
7650 var generic_inst_map: InstMap = .{};
7651 defer generic_inst_map.deinit(gpa);
7652 if (func_ty_info.is_generic) {
7653 try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body);
7654 }
7655
7656 // This exists so that `generic_block` below can include a "called from here" note back to this
7657 // call site when analyzing generic parameter/return types.
7658 var generic_inlining: Block.Inlining = if (func_ty_info.is_generic) .{
7659 .call_block = block,
7660 .call_src = call_src,
7661 .has_comptime_args = false, // unused by error reporting
7662 .func = .none, // unused by error reporting
7663 .comptime_result = .none, // unused by error reporting
7664 .merges = undefined, // unused because we'll never `return`
7665 } else undefined;
77507666
7751 if (is_comptime_call and modifier == .never_inline) {7667 // This is the block in which we evaluate generic function components: that is, generic parameter
7752 return sema.fail(block, call_src, "unable to perform 'never_inline' call at compile-time", .{});7668 // types and the generic return type. This must not be used if the function is not generic.
7753 }7669 // `comptime_reason` is set as needed.
7670 var generic_block: Block = if (func_ty_info.is_generic) .{
7671 .parent = null,
7672 .sema = sema,
7673 .namespace = fn_nav.analysis.?.namespace,
7674 .instructions = .{},
7675 .inlining = &generic_inlining,
7676 .src_base_inst = fn_nav.analysis.?.zir_index,
7677 .type_name_ctx = fn_nav.fqn,
7678 } else undefined;
7679 defer if (func_ty_info.is_generic) generic_block.instructions.deinit(gpa);
7680
7681 if (func_ty_info.is_generic) {
7682 // We certainly depend on the generic owner's signature!
7683 try sema.declareDependency(.{ .src_hash = fn_tracked_inst });
7684 }
7685
7686 const args = try arena.alloc(Air.Inst.Ref, args_info.count());
7687 for (args, 0..) |*arg, arg_idx| {
7688 const param_ty: ?Type = if (arg_idx < func_ty_info.param_types.len) ty: {
7689 const raw = func_ty_info.param_types.get(ip)[arg_idx];
7690 if (raw != .generic_poison_type) break :ty .fromInterned(raw);
7691
7692 // We must discover the generic parameter type.
7693 assert(func_ty_info.is_generic);
7694 const param_inst_idx = fn_zir_info.param_body[arg_idx];
7695 const param_inst = fn_zir.instructions.get(@intFromEnum(param_inst_idx));
7696 switch (param_inst.tag) {
7697 .param_anytype, .param_anytype_comptime => break :ty .generic_poison,
7698 .param, .param_comptime => {},
7699 else => unreachable,
7700 }
77547701
7755 const result: Air.Inst.Ref = if (is_inline_call) res: {7702 // Evaluate the generic parameter type. We need to switch out `sema.code` and `sema.inst_map`, because
7756 const old_comptime_reason = block.comptime_reason;7703 // the function definition may be in a different file to the call site.
7757 block.comptime_reason = comptime_call_reason;7704 const old_code = sema.code;
7758 defer block.comptime_reason = old_comptime_reason;7705 const old_inst_map = sema.inst_map;
7706 defer {
7707 generic_inst_map = sema.inst_map;
7708 sema.code = old_code;
7709 sema.inst_map = old_inst_map;
7710 }
7711 sema.code = fn_zir;
7712 sema.inst_map = generic_inst_map;
77597713
7760 const func_val = try sema.resolveConstDefinedValue(block, func_src, func, .{ .simple = .comptime_call_target });7714 const extra = sema.code.extraData(Zir.Inst.Param, param_inst.data.pl_tok.payload_index);
7761 const module_fn_index = switch (zcu.intern_pool.indexToKey(func_val.toIntern())) {7715 const param_src = generic_block.tokenOffset(param_inst.data.pl_tok.src_tok);
7762 .@"extern" => return sema.fail(block, call_src, "{s} call of extern function", .{7716 const body = sema.code.bodySlice(extra.end, extra.data.body_len);
7763 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
7764 }),
7765 .func => func_val.toIntern(),
7766 .ptr => |ptr| blk: {
7767 switch (ptr.base_addr) {
7768 .nav => |nav_index| if (ptr.byte_offset == 0) {
7769 try sema.ensureNavResolved(call_src, nav_index, .fully);
7770 const nav = ip.getNav(nav_index);
7771 if (nav.getExtern(ip) != null)
7772 return sema.fail(block, call_src, "{s} call of extern function pointer", .{
7773 if (is_comptime_call) "comptime" else "inline",
7774 });
7775 break :blk nav.status.fully_resolved.val;
7776 },
7777 else => {},
7778 }
7779 assert(callee_ty.isPtrAtRuntime(zcu));
7780 return sema.fail(block, call_src, "{s} call of function pointer", .{
7781 if (is_comptime_call) "comptime" else "inline",
7782 });
7783 },
7784 else => unreachable,
7785 };
7786 if (func_ty_info.is_var_args) {
7787 return sema.fail(block, call_src, "{s} call of variadic function", .{
7788 if (is_comptime_call) "comptime" else "inline",
7789 });
7790 }
77917717
7792 // Analyze the ZIR. The same ZIR gets analyzed into a runtime function7718 generic_block.comptime_reason = .{ .reason = .{
7793 // or an inlined call depending on what union tag the `label` field is7719 .r = .{ .simple = .function_parameters },
7794 // set to in the `Block`.7720 .src = param_src,
7795 // This block instruction will be used to capture the return value from the7721 } };
7796 // inlined function.
7797 const need_debug_scope = !is_comptime_call and !block.is_typeof and !block.ownerModule().strip;
7798 const block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
7799 try sema.air_instructions.append(gpa, .{
7800 .tag = if (need_debug_scope) .dbg_inline_block else .block,
7801 .data = undefined,
7802 });
7803 // This one is shared among sub-blocks within the same callee, but not
7804 // shared among the entire inline/comptime call stack.
7805 var inlining: Block.Inlining = .{
7806 .call_block = block,
7807 .call_src = call_src,
7808 .has_comptime_args = false,
7809 .func = module_fn_index,
7810 .comptime_result = undefined,
7811 .merges = .{
7812 .src_locs = .{},
7813 .results = .{},
7814 .br_list = .{},
7815 .block_inst = block_inst,
7816 },
7817 };
78187722
7819 const module_fn = zcu.funcInfo(module_fn_index);7723 const ty_ref = try sema.resolveInlineBody(&generic_block, body, param_inst_idx);
7724 const param_ty = try sema.analyzeAsType(&generic_block, param_src, ty_ref);
78207725
7821 // The call site definitely depends on the function's signature.7726 if (!param_ty.isValidParamType(zcu)) {
7822 try sema.declareDependency(.{ .src_hash = module_fn.zir_body_inst });7727 const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
7728 return sema.fail(block, param_src, "parameter of {s}type '{}' not allowed", .{
7729 opaque_str, param_ty.fmt(pt),
7730 });
7731 }
78237732
7824 // This is not a function instance, so the function's `Nav` has analysis7733 break :ty param_ty;
7825 // state -- we don't need to check `generic_owner`.7734 } else null; // vararg
7826 const fn_nav = ip.getNav(module_fn.owner_nav);
78277735
7828 // We effectively want a child Sema here, but can't literally do that, because we need AIR7736 arg.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, callee, maybe_func_inst);
7829 // to be shared. InlineCallSema is a wrapper which handles this for us. While `ics` is in7737 const arg_ty = sema.typeOf(arg.*);
7830 // scope, we should use its `caller`/`callee` methods rather than using `sema` directly7738 if (arg_ty.zigTypeTag(zcu) == .noreturn) {
7831 // whenever performing an operation where the difference matters.7739 return arg.*; // terminate analysis here
7832 var ics = InlineCallSema.init(7740 }
7833 sema,7741
7834 zcu.navFileScope(module_fn.owner_nav).zir,7742 if (func_ty_info.is_generic) {
7835 module_fn_index,7743 // We need to put the argument into `generic_inst_map` so that other parameters can refer to it.
7836 block.error_return_trace_index,7744 const param_inst_idx = fn_zir_info.param_body[arg_idx];
7837 );7745 const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false;
7838 defer ics.deinit();7746 const param_is_comptime = declared_comptime or try arg_ty.comptimeOnlySema(pt);
7747 if (param_is_comptime) {
7748 if (!try sema.isComptimeKnown(arg.*)) {
7749 assert(!declared_comptime); // `analyzeArg` handles this
7750 const arg_src = args_info.argSrc(block, arg_idx);
7751 const param_ty_src: LazySrcLoc = .{
7752 .base_node_inst = maybe_func_inst.?, // the function is generic
7753 .offset = .{ .func_decl_param_ty = @intCast(arg_idx) },
7754 };
7755 return sema.failWithNeededComptime(
7756 block,
7757 arg_src,
7758 .{ .comptime_only_param_ty = .{ .ty = arg_ty, .param_ty_src = param_ty_src } },
7759 );
7760 }
7761 generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, arg.*);
7762 } else {
7763 // We need a dummy instruction with this type. It doesn't actually need to be in any block,
7764 // since it will never be referenced at runtime!
7765 const dummy: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
7766 try sema.air_instructions.append(gpa, .{ .tag = .alloc, .data = .{ .ty = arg_ty } });
7767 generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, dummy.toRef());
7768 }
7769 }
7770 }
78397771
7840 var child_block: Block = .{7772 // This return type is never generic poison.
7841 .parent = null,7773 // However, if it has an IES, it is always associated with the callee value.
7842 .sema = sema,7774 // This is not correct for inline calls (where it should be an ad-hoc IES), nor for generic
7843 // The function body exists in the same namespace as the corresponding function declaration.7775 // calls (where it should be the IES of the instantiation). However, it's how we print this
7844 .namespace = fn_nav.analysis.?.namespace,7776 // in error messages.
7845 .instructions = .{},7777 const resolved_ret_ty: Type = ret_ty: {
7846 .label = null,7778 if (!func_ty_info.is_generic) break :ret_ty .fromInterned(func_ty_info.return_type);
7847 .inlining = &inlining,
7848 .is_typeof = block.is_typeof,
7849 .comptime_reason = if (is_comptime_call) .inlining_parent else null,
7850 .error_return_trace_index = block.error_return_trace_index,
7851 .runtime_cond = block.runtime_cond,
7852 .runtime_loop = block.runtime_loop,
7853 .runtime_index = block.runtime_index,
7854 .src_base_inst = fn_nav.analysis.?.zir_index,
7855 .type_name_ctx = fn_nav.fqn,
7856 };
78577779
7858 const merges = &child_block.inlining.?.merges;7780 const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: {
7781 break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type);
7782 } else func_ty_info.return_type;
78597783
7860 defer child_block.instructions.deinit(gpa);7784 if (maybe_poison_bare != .generic_poison_type) break :ret_ty .fromInterned(func_ty_info.return_type);
7861 defer merges.deinit(gpa);
78627785
7863 try sema.emitBackwardBranch(block, call_src);7786 // Evaluate the generic return type. As with generic parameters, we switch out `sema.code` and `sema.inst_map`.
78647787
7865 // Whether this call should be memoized, set to false if the call can7788 assert(func_ty_info.is_generic);
7866 // mutate comptime state.
7867 // TODO: comptime call memoization is currently not supported under incremental compilation
7868 // since dependencies are not marked on callers. If we want to keep this around (we should
7869 // check that it's worthwhile first!), each memoized call needs an `AnalUnit`.
7870 var should_memoize = !zcu.comp.incremental;
7871
7872 // If it's a comptime function call, we need to memoize it as long as no external
7873 // comptime memory is mutated.
7874 const memoized_arg_values = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len);
7875
7876 const owner_info = zcu.typeToFunc(Type.fromInterned(module_fn.ty)).?;
7877 const new_param_types = try sema.arena.alloc(InternPool.Index, owner_info.param_types.len);
7878 var new_fn_info: InternPool.GetFuncTypeKey = .{
7879 .param_types = new_param_types,
7880 .return_type = owner_info.return_type,
7881 .noalias_bits = owner_info.noalias_bits,
7882 .cc = owner_info.cc,
7883 .is_var_args = owner_info.is_var_args,
7884 .is_noinline = owner_info.is_noinline,
7885 .is_generic = owner_info.is_generic,
7886 };
78877789
7888 // This will have return instructions analyzed as break instructions to7790 const old_code = sema.code;
7889 // the block_inst above. Here we are performing "comptime/inline semantic analysis"7791 const old_inst_map = sema.inst_map;
7890 // for a function body, which means we must map the parameter ZIR instructions to7792 defer {
7891 // the AIR instructions of the callsite. The callee could be a generic function7793 generic_inst_map = sema.inst_map;
7892 // which means its parameter type expressions must be resolved in order and used7794 sema.code = old_code;
7893 // to successively coerce the arguments.7795 sema.inst_map = old_inst_map;
7894 const fn_info = ics.callee().code.getFnInfo(module_fn.zir_body_inst.resolve(ip) orelse return error.AnalysisFail);
7895 try ics.callee().inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
7896
7897 var arg_i: u32 = 0;
7898 for (fn_info.param_body) |inst| {
7899 const opt_noreturn_ref = try analyzeInlineCallArg(
7900 &ics,
7901 block,
7902 &child_block,
7903 inst,
7904 new_param_types,
7905 &arg_i,
7906 args_info,
7907 is_comptime_call,
7908 &should_memoize,
7909 memoized_arg_values,
7910 func_ty_info,
7911 func,
7912 );
7913 if (opt_noreturn_ref) |ref| {
7914 // Analyzing this argument gave a ref of a noreturn type. Terminate argument analysis here.
7915 return ref;
7916 }
7917 }7796 }
7797 sema.code = fn_zir;
7798 sema.inst_map = generic_inst_map;
79187799
7919 // From here, we only really need to use the callee Sema. Make it the active one, then we7800 generic_block.comptime_reason = .{ .reason = .{
7920 // can just use `sema` directly.7801 .r = .{ .simple = .function_ret_ty },
7921 _ = ics.callee();7802 .src = func_ret_ty_src,
7803 } };
79227804
7923 if (!inlining.has_comptime_args) {7805 const bare_ty = if (fn_zir_info.ret_ty_ref != .none) bare: {
7924 var block_it = block;7806 assert(fn_zir_info.ret_ty_body.len == 0);
7925 while (block_it.inlining) |parent_inlining| {7807 break :bare try sema.resolveType(&generic_block, func_ret_ty_src, fn_zir_info.ret_ty_ref);
7926 if (!parent_inlining.has_comptime_args and parent_inlining.func == module_fn_index) {7808 } else bare: {
7927 const err_msg = try sema.errMsg(call_src, "inline call is recursive", .{});7809 assert(fn_zir_info.ret_ty_body.len != 0);
7928 return sema.failWithOwnedErrorMsg(null, err_msg);7810 const ty_ref = try sema.resolveInlineBody(&generic_block, fn_zir_info.ret_ty_body, fn_zir_inst);
7929 }7811 break :bare try sema.analyzeAsType(&generic_block, func_ret_ty_src, ty_ref);
7930 block_it = parent_inlining.call_block;7812 };
7931 }7813 assert(bare_ty.toIntern() != .generic_poison_type);
7814
7815 const full_ty = if (fn_zir_info.inferred_error_set) full: {
7816 try sema.validateErrorUnionPayloadType(block, bare_ty, func_ret_ty_src);
7817 const set = ip.errorUnionSet(func_ty_info.return_type);
7818 break :full try pt.errorUnionType(.fromInterned(set), bare_ty);
7819 } else bare_ty;
7820
7821 if (!full_ty.isValidReturnType(zcu)) {
7822 const opaque_str = if (full_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
7823 return sema.fail(block, func_ret_ty_src, "{s}return type '{}' not allowed", .{
7824 opaque_str, full_ty.fmt(pt),
7825 });
7932 }7826 }
79337827
7934 // In case it is a generic function with an expression for the return type that depends7828 break :ret_ty full_ty;
7935 // on parameters, we must now do the same for the return type as we just did with7829 };
7936 // each of the parameters, resolving the return type and providing it to the child
7937 // `Sema` so that it can be used for the `ret_ptr` instruction.
7938 const ret_ty_src: LazySrcLoc = .{ .base_node_inst = module_fn.zir_body_inst, .offset = .{ .node_offset_fn_type_ret_ty = 0 } };
7939 const ret_ty_inst = if (fn_info.ret_ty_body.len != 0) r: {
7940 const old_child_comptime_reason = child_block.comptime_reason;
7941 defer child_block.comptime_reason = old_child_comptime_reason;
7942 child_block.comptime_reason = .{ .reason = .{
7943 .src = ret_ty_src,
7944 .r = .{ .simple = .function_ret_ty },
7945 } };
7946 break :r try sema.resolveInlineBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst.resolve(ip) orelse return error.AnalysisFail);
7947 } else try sema.resolveInst(fn_info.ret_ty_ref);
7948 sema.fn_ret_ty = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
7949 if (module_fn.analysisUnordered(ip).inferred_error_set) {
7950 // Create a fresh inferred error set type for inline/comptime calls.
7951 const ies = try sema.arena.create(InferredErrorSet);
7952 ies.* = .{ .func = .none };
7953 sema.fn_ret_ty_ies = ies;
7954 sema.fn_ret_ty = Type.fromInterned(try pt.intern(.{ .error_union_type = .{
7955 .error_set_type = .adhoc_inferred_error_set_type,
7956 .payload_type = sema.fn_ret_ty.toIntern(),
7957 } }));
7958 }
79597830
7960 memoize: {7831 // If we've discovered after evaluating arguments that a generic function instantiation is
7961 if (!should_memoize) break :memoize;7832 // comptime-only, then we can mark the block as comptime *now*.
7962 if (!is_comptime_call) break :memoize;7833 if (!inline_requested and !block.isComptime() and try resolved_ret_ty.comptimeOnlySema(pt)) {
7963 const memoized_call_index = ip.getIfExists(.{7834 block.comptime_reason = .{
7964 .memoized_call = .{7835 .reason = .{
7965 .func = module_fn_index,7836 .src = call_src,
7966 .arg_values = memoized_arg_values,7837 .r = .{
7967 .result = undefined, // ignored by hash+eql7838 .comptime_only_ret_ty = .{
7968 .branch_count = undefined, // ignored by hash+eql7839 .ty = resolved_ret_ty,
7840 .is_generic_inst = true,
7841 .ret_ty_src = func_ret_ty_src,
7842 },
7969 },7843 },
7970 }) orelse break :memoize;7844 },
7971 const memoized_call = ip.indexToKey(memoized_call_index).memoized_call;7845 };
7972 if (sema.branch_count + memoized_call.branch_count > sema.branch_quota) {7846 }
7973 // Let the call play out se we get the correct source location for the
7974 // "evaluation exceeded X backwards branches" error.
7975 break :memoize;
7976 }
7977 sema.branch_count += memoized_call.branch_count;
7978 break :res Air.internedToRef(memoized_call.result);
7979 }
79807847
7981 // Since we're doing an inline call, we depend on the source code of the whole7848 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
7982 // function declaration.
7983 try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index });
79847849
7985 new_fn_info.return_type = sema.fn_ret_ty.toIntern();7850 const is_inline_call = block.isComptime() or inline_requested;
7986 if (!is_comptime_call and !block.is_typeof) {
7987 const zir_tags = sema.code.instructions.items(.tag);
7988 for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) {
7989 .param, .param_comptime => {
7990 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].pl_tok;
7991 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
7992 const param_name = sema.code.nullTerminatedString(extra.data.name);
7993 const inst = sema.inst_map.get(param).?;
7994
7995 try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name);
7996 },
7997 .param_anytype, .param_anytype_comptime => {
7998 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].str_tok;
7999 const param_name = inst_data.get(sema.code);
8000 const inst = sema.inst_map.get(param).?;
80017851
8002 try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name);7852 if (!is_inline_call) {
8003 },7853 if (sema.func_is_naked) return sema.failWithOwnedErrorMsg(block, msg: {
8004 else => continue,7854 const msg = try sema.errMsg(call_src, "runtime {s} not allowed in naked function", .{@tagName(operation)});
8005 };7855 errdefer msg.destroy(gpa);
7856 switch (operation) {
7857 .call, .@"@call", .@"@panic", .@"error return" => {},
7858 .@"safety check" => try sema.errNote(call_src, msg, "use @setRuntimeSafety to disable runtime safety", .{}),
7859 }
7860 break :msg msg;
7861 });
7862 for (args, 0..) |arg, arg_idx| {
7863 try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg);
8006 }7864 }
7865 const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: {
7866 if (!func_ty_info.is_generic) break :func .{ callee, args };
80077867
8008 if (is_comptime_call and ensure_result_used) {7868 // Instantiate the generic function!
8009 try sema.ensureResultUsed(block, sema.fn_ret_ty, call_src);
8010 }
80117869
8012 if (is_comptime_call or block.is_typeof) {7870 // This may be an overestimate, but it's definitely sufficient.
8013 // Save the error trace as our first action in the function7871 const max_runtime_args = args_info.count() - @popCount(func_ty_info.comptime_bits);
8014 // to match the behavior of runtime function calls.7872 var runtime_args: std.ArrayListUnmanaged(Air.Inst.Ref) = try .initCapacity(arena, max_runtime_args);
8015 const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block);7873 var runtime_param_tys: std.ArrayListUnmanaged(InternPool.Index) = try .initCapacity(arena, max_runtime_args);
8016 sema.error_return_trace_index_on_fn_entry = error_return_trace_index;
8017 child_block.error_return_trace_index = error_return_trace_index;
8018 }
80197874
8020 // We temporarily set `allow_memoize` to `true` to track this comptime call.7875 const comptime_args = try arena.alloc(InternPool.Index, args_info.count());
8021 // It is restored after this call finishes analysis, so that a caller may
8022 // know whether an in-progress call (containing this call) may be memoized.
8023 const old_allow_memoize = sema.allow_memoize;
8024 defer sema.allow_memoize = old_allow_memoize and sema.allow_memoize;
8025 sema.allow_memoize = true;
80267876
8027 // Store the current eval branch count so we can find out how many eval branches7877 var noalias_bits: u32 = 0;
8028 // the comptime call caused.
8029 const old_branch_count = sema.branch_count;
80307878
8031 const result = result: {7879 for (args, comptime_args, 0..) |arg, *comptime_arg, arg_idx| {
8032 sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) {7880 const arg_ty = sema.typeOf(arg);
8033 error.ComptimeReturn => break :result inlining.comptime_result,
8034 else => |e| return e,
8035 };
8036 break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope);
8037 };
80387881
8039 if (is_comptime_call) {7882 const is_comptime = c: {
8040 const result_val = try sema.resolveConstValue(block, LazySrcLoc.unneeded, result, undefined);7883 if (std.math.cast(u5, arg_idx)) |i| {
8041 const result_interned = result_val.toIntern();7884 if (func_ty_info.paramIsComptime(i)) {
80427885 break :c true;
8043 // Transform ad-hoc inferred error set types into concrete error sets.7886 }
8044 const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned);7887 }
80457888 break :c try arg_ty.comptimeOnlySema(pt);
8046 // If the result can mutate comptime vars, we must not memoize it, as it contains7889 };
8047 // a reference to `comptime_allocs` so is not stable across instances of `Sema`.7890 const is_noalias = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsNoalias(i) else false;
8048 // TODO: check whether any external comptime memory was mutated by the7891
8049 // comptime function call. If so, then do not memoize the call here.7892 if (is_comptime) {
8050 if (should_memoize and sema.allow_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(zcu)) {7893 // We already emitted an error if the argument isn't comptime-known.
8051 _ = try pt.intern(.{ .memoized_call = .{7894 comptime_arg.* = (try sema.resolveValue(arg)).?.toIntern();
8052 .func = module_fn_index,7895 } else {
8053 .arg_values = memoized_arg_values,7896 comptime_arg.* = .none;
8054 .result = result_transformed,7897 if (is_noalias) {
8055 .branch_count = sema.branch_count - old_branch_count,7898 const runtime_idx = runtime_args.items.len;
8056 } });7899 noalias_bits |= @as(u32, 1) << @intCast(runtime_idx);
7900 }
7901 runtime_args.appendAssumeCapacity(arg);
7902 runtime_param_tys.appendAssumeCapacity(arg_ty.toIntern());
7903 }
8057 }7904 }
80587905
8059 break :res Air.internedToRef(result_transformed);7906 const bare_ret_ty = if (fn_zir_info.inferred_error_set) t: {
8060 }7907 break :t resolved_ret_ty.errorUnionPayload(zcu);
7908 } else resolved_ret_ty;
80617909
8062 if (try sema.resolveValue(result)) |result_val| {7910 // We now need to actually create the function instance.
8063 const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern());7911 const func_instance = try ip.getFuncInstance(gpa, pt.tid, .{
8064 break :res Air.internedToRef(result_transformed);7912 .param_types = runtime_param_tys.items,
8065 }7913 .noalias_bits = noalias_bits,
7914 .bare_return_type = bare_ret_ty.toIntern(),
7915 .is_noinline = func_ty_info.is_noinline,
7916 .inferred_error_set = fn_zir_info.inferred_error_set,
7917 .generic_owner = func_val.?.toIntern(),
7918 .comptime_args = comptime_args,
7919 });
80667920
8067 const new_ty = try sema.resolveAdHocInferredErrorSetTy(block, call_src, sema.typeOf(result).toIntern());7921 // This call is problematic as it breaks guarantees about order-independency of semantic analysis.
8068 if (new_ty != .none) {7922 // These guarantees are necessary for incremental compilation and parallel semantic analysis.
8069 // TODO: mutate in place the previous instruction if possible7923 // See: #22410
8070 // rather than adding a bitcast instruction.7924 zcu.funcInfo(func_instance).maxBranchQuota(ip, sema.branch_quota);
8071 break :res try block.addBitCast(Type.fromInterned(new_ty), result);
8072 }
80737925
8074 break :res result;7926 break :func .{ Air.internedToRef(func_instance), runtime_args.items };
8075 } else res: {7927 };
8076 assert(!func_ty_info.is_generic);
80777928
8078 const args = try sema.arena.alloc(Air.Inst.Ref, args_info.count());7929 ref_func: {
8079 for (args, 0..) |*arg_out, arg_idx| {7930 const runtime_func_val = try sema.resolveValue(runtime_func) orelse break :ref_func;
8080 // Non-generic, so param types are already resolved7931 if (!ip.isFuncBody(runtime_func_val.toIntern())) break :ref_func;
8081 const param_ty: ?Type = if (arg_idx < func_ty_info.param_types.len) ty: {7932 try sema.addReferenceEntry(call_src, .wrap(.{ .func = runtime_func_val.toIntern() }));
8082 break :ty Type.fromInterned(func_ty_info.param_types.get(ip)[arg_idx]);7933 try zcu.ensureFuncBodyAnalysisQueued(runtime_func_val.toIntern());
8083 } else null;
8084 if (param_ty) |t| assert(!t.isGenericPoison());
8085 arg_out.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, func);
8086 try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg_out.*);
8087 if (sema.typeOf(arg_out.*).zigTypeTag(zcu) == .noreturn) {
8088 return arg_out.*;
8089 }
8090 }7934 }
80917935
8092 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
8093
8094 switch (sema.owner.unwrap()) {7936 switch (sema.owner.unwrap()) {
8095 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},7937 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
8096 .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {7938 .func => |owner_func| if (resolved_ret_ty.isError(zcu)) {
8097 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);7939 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);
8098 },7940 },
8099 }7941 }
81007942
8101 if (try sema.resolveValue(func)) |func_val| {7943 const call_tag: Air.Inst.Tag = switch (modifier) {
8102 if (zcu.intern_pool.isFuncBody(func_val.toIntern())) {7944 .auto, .no_async => .call,
8103 try sema.addReferenceEntry(call_src, AnalUnit.wrap(.{ .func = func_val.toIntern() }));7945 .never_tail => .call_never_tail,
8104 try zcu.ensureFuncBodyAnalysisQueued(func_val.toIntern());7946 .never_inline => .call_never_inline,
8105 }7947 .always_tail => .call_always_tail,
8106 }
81077948
8108 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).@"struct".fields.len +7949 .always_inline,
8109 args.len);7950 .compile_time,
8110 const func_inst = try block.addInst(.{7951 .async_kw,
7952 => unreachable,
7953 };
7954
7955 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).@"struct".fields.len + runtime_args.len);
7956 const result = try block.addInst(.{
8111 .tag = call_tag,7957 .tag = call_tag,
8112 .data = .{ .pl_op = .{7958 .data = .{ .pl_op = .{
8113 .operand = func,7959 .operand = runtime_func,
8114 .payload = sema.addExtraAssumeCapacity(Air.Call{7960 .payload = sema.addExtraAssumeCapacity(Air.Call{
8115 .args_len = @intCast(args.len),7961 .args_len = @intCast(runtime_args.len),
8116 }),7962 }),
8117 } },7963 } },
8118 });7964 });
8119 sema.appendRefsAssumeCapacity(args);7965 sema.appendRefsAssumeCapacity(runtime_args);
7966
7967 if (ensure_result_used) {
7968 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
7969 }
81207970
8121 if (call_tag == .call_always_tail) {7971 if (call_tag == .call_always_tail) {
8122 if (ensure_result_used) {7972 return sema.handleTailCall(block, call_src, sema.typeOf(runtime_func), result);
8123 try sema.ensureResultUsed(block, sema.typeOf(func_inst), call_src);
8124 }
8125 return sema.handleTailCall(block, call_src, func_ty, func_inst);
8126 }
8127 if (block.wantSafety() and func_ty_info.return_type == .noreturn_type) skip_safety: {
8128 // Function pointers and extern functions aren't guaranteed to
8129 // actually be noreturn so we add a safety check for them.
8130 if (try sema.resolveValue(func)) |func_val| {
8131 switch (zcu.intern_pool.indexToKey(func_val.toIntern())) {
8132 .func => break :skip_safety,
8133 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
8134 .nav => |nav| {
8135 try sema.ensureNavResolved(call_src, nav, .fully);
8136 if (ip.getNav(nav).getExtern(ip) == null) break :skip_safety;
8137 },
8138 else => {},
8139 },
8140 else => {},
8141 }
8142 }
8143 try sema.safetyPanic(block, call_src, .noreturn_returned);
8144 return .unreachable_value;
8145 }7973 }
8146 if (func_ty_info.return_type == .noreturn_type) {7974
8147 _ = try block.addNoOp(.unreach);7975 if (resolved_ret_ty.toIntern() == .noreturn_type) {
7976 const want_check = c: {
7977 if (!block.wantSafety()) break :c false;
7978 if (func_val != null) break :c false;
7979 break :c true;
7980 };
7981 if (want_check) {
7982 try sema.safetyPanic(block, call_src, .noreturn_returned);
7983 } else {
7984 _ = try block.addNoOp(.unreach);
7985 }
8148 return .unreachable_value;7986 return .unreachable_value;
8149 }7987 }
8150 break :res func_inst;
8151 };
81527988
8153 if (ensure_result_used) {7989 return result;
8154 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
8155 }7990 }
8156 return result;
8157}
81587991
8159fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref {7992 // This is an inline call. The function must be comptime-known. We will analyze its body directly using this `Sema`.
8160 const pt = sema.pt;7993
8161 const zcu = pt.zcu;7994 const call_type: []const u8 = if (block.isComptime()) "comptime" else "inline";
8162 const target = zcu.getTarget();7995
8163 const backend = zcu.comp.getZigBackend();7996 if (modifier == .never_inline) {
8164 if (!target_util.supportsTailCall(target, backend)) {7997 return sema.fail(block, call_src, "cannot perform {s} call with 'never_inline' modifier", .{call_type});
8165 return sema.fail(block, call_src, "unable to perform tail call: compiler backend '{s}' does not support tail calls on target architecture '{s}' with the selected CPU feature flags", .{
8166 @tagName(backend), @tagName(target.cpu.arch),
8167 });
8168 }7998 }
8169 const owner_func_ty = Type.fromInterned(zcu.funcInfo(sema.owner.unwrap().func).ty);7999 if (func_ty_info.is_noinline and !block.isComptime()) {
8170 if (owner_func_ty.toIntern() != func_ty.toIntern()) {8000 return sema.fail(block, call_src, "{s} call of noinline function", .{call_type});
8171 return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{
8172 func_ty.fmt(pt), owner_func_ty.fmt(pt),
8173 });
8174 }8001 }
8175 _ = try block.addUnOp(.ret, result);8002 if (func_ty_info.is_var_args) {
8176 return .unreachable_value;8003 return sema.fail(block, call_src, "{s} call of variadic function", .{call_type});
8177}
8178
8179/// Usually, returns null. If an argument was noreturn, returns that ref (which should become the call result).
8180fn analyzeInlineCallArg(
8181 ics: *InlineCallSema,
8182 arg_block: *Block,
8183 param_block: *Block,
8184 inst: Zir.Inst.Index,
8185 new_param_types: []InternPool.Index,
8186 arg_i: *u32,
8187 args_info: CallArgsInfo,
8188 is_comptime_call: bool,
8189 should_memoize: *bool,
8190 memoized_arg_values: []InternPool.Index,
8191 func_ty_info: InternPool.Key.FuncType,
8192 func_inst: Air.Inst.Ref,
8193) !?Air.Inst.Ref {
8194 const zcu = ics.sema.pt.zcu;
8195 const ip = &zcu.intern_pool;
8196 const zir_tags = ics.callee().code.instructions.items(.tag);
8197 switch (zir_tags[@intFromEnum(inst)]) {
8198 .param_comptime, .param_anytype_comptime => param_block.inlining.?.has_comptime_args = true,
8199 else => {},
8200 }8004 }
8201 switch (zir_tags[@intFromEnum(inst)]) {
8202 .param, .param_comptime => {
8203 // Evaluate the parameter type expression now that previous ones have
8204 // been mapped, and coerce the corresponding argument to it.
8205 const pl_tok = ics.callee().code.instructions.items(.data)[@intFromEnum(inst)].pl_tok;
8206 const param_src = param_block.tokenOffset(pl_tok.src_tok);
8207 const extra = ics.callee().code.extraData(Zir.Inst.Param, pl_tok.payload_index);
8208 const param_body = ics.callee().code.bodySlice(extra.end, extra.data.body_len);
8209 const param_ty = param_ty: {
8210 const raw_param_ty = func_ty_info.param_types.get(ip)[arg_i.*];
8211 if (raw_param_ty != .generic_poison_type) break :param_ty raw_param_ty;
8212 const param_ty_inst = try ics.callee().resolveInlineBody(param_block, param_body, inst);
8213 const param_ty = try ics.callee().analyzeAsType(param_block, param_src, param_ty_inst);
8214 break :param_ty param_ty.toIntern();
8215 };
8216 new_param_types[arg_i.*] = param_ty;
8217 const casted_arg = try args_info.analyzeArg(ics.caller(), arg_block, arg_i.*, Type.fromInterned(param_ty), func_ty_info, func_inst);
8218 if (ics.caller().typeOf(casted_arg).zigTypeTag(zcu) == .noreturn) {
8219 return casted_arg;
8220 }
8221 const arg_src = args_info.argSrc(arg_block, arg_i.*);
8222 if (zir_tags[@intFromEnum(inst)] == .param_comptime) {
8223 _ = try ics.caller().resolveConstValue(arg_block, arg_src, casted_arg, .{ .simple = .comptime_param_arg });
8224 } else if (!is_comptime_call and try Type.fromInterned(param_ty).comptimeOnlySema(ics.callee().pt)) {
8225 _ = try ics.caller().resolveConstValue(arg_block, arg_src, casted_arg, .{ .comptime_only = .{
8226 .ty = .fromInterned(param_ty),
8227 .msg = .param_ty_arg,
8228 } });
8229 }
82308005
8231 if (is_comptime_call) {8006 if (func_val == null) {
8232 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, casted_arg);8007 if (func_is_extern) {
8233 const arg_val = try ics.caller().resolveConstValue(arg_block, arg_src, casted_arg, null);8008 return sema.fail(block, call_src, "{s} call of extern function", .{call_type});
8234 switch (arg_val.toIntern()) {8009 }
8235 .generic_poison, .generic_poison_type => {8010 return sema.failWithNeededComptime(
8236 // This function is currently evaluated as part of an as-of-yet unresolvable8011 block,
8237 // parameter or return type.8012 func_src,
8238 return error.GenericPoison;8013 .{ .simple = if (block.isComptime()) .comptime_call_target else .inline_call_target },
8239 },8014 );
8240 else => {},8015 }
8241 }
8242 // Needed so that lazy values do not trigger
8243 // assertion due to type not being resolved
8244 // when the hash function is called.
8245 const resolved_arg_val = try ics.caller().resolveLazyValue(arg_val);
8246 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(zcu);
8247 memoized_arg_values[arg_i.*] = resolved_arg_val.toIntern();
8248 } else {
8249 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
8250 }
8251
8252 if (try ics.caller().resolveValue(casted_arg)) |_| {
8253 param_block.inlining.?.has_comptime_args = true;
8254 }
8255
8256 arg_i.* += 1;
8257 },
8258 .param_anytype, .param_anytype_comptime => {
8259 // No coercion needed.
8260 const uncasted_arg = try args_info.analyzeArg(ics.caller(), arg_block, arg_i.*, Type.generic_poison, func_ty_info, func_inst);
8261 if (ics.caller().typeOf(uncasted_arg).zigTypeTag(zcu) == .noreturn) {
8262 return uncasted_arg;
8263 }
8264 const arg_src = args_info.argSrc(arg_block, arg_i.*);
8265 new_param_types[arg_i.*] = ics.caller().typeOf(uncasted_arg).toIntern();
8266
8267 if (is_comptime_call) {
8268 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
8269 const arg_val = try ics.caller().resolveConstValue(arg_block, arg_src, uncasted_arg, null);
8270 switch (arg_val.toIntern()) {
8271 .generic_poison, .generic_poison_type => {
8272 // This function is currently evaluated as part of an as-of-yet unresolvable
8273 // parameter or return type.
8274 return error.GenericPoison;
8275 },
8276 else => {},
8277 }
8278 // Needed so that lazy values do not trigger
8279 // assertion due to type not being resolved
8280 // when the hash function is called.
8281 const resolved_arg_val = try ics.caller().resolveLazyValue(arg_val);
8282 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(zcu);
8283 memoized_arg_values[arg_i.*] = resolved_arg_val.toIntern();
8284 } else {
8285 if (zir_tags[@intFromEnum(inst)] == .param_anytype_comptime) {
8286 _ = try ics.caller().resolveConstValue(arg_block, arg_src, uncasted_arg, .{ .simple = .comptime_param_arg });
8287 }
8288 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
8289 }
82908016
8291 if (try ics.caller().resolveValue(uncasted_arg)) |_| {8017 if (block.isComptime()) {
8292 param_block.inlining.?.has_comptime_args = true;8018 for (args, 0..) |arg, arg_idx| {
8019 if (!try sema.isComptimeKnown(arg)) {
8020 const arg_src = args_info.argSrc(block, arg_idx);
8021 return sema.failWithNeededComptime(block, arg_src, null);
8293 }8022 }
82948023 }
8295 arg_i.* += 1;
8296 },
8297 else => {},
8298 }8024 }
82998025
8300 return null;8026 // For an inline call, we depend on the source code of the whole function definition.
8301}8027 try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index });
8302
8303fn instantiateGenericCall(
8304 sema: *Sema,
8305 block: *Block,
8306 func: Air.Inst.Ref,
8307 func_src: LazySrcLoc,
8308 call_src: LazySrcLoc,
8309 ensure_result_used: bool,
8310 args_info: CallArgsInfo,
8311 call_tag: Air.Inst.Tag,
8312 call_dbg_node: ?Zir.Inst.Index,
8313 /// Populated when `error.ComptimeReturn` is returned.
8314 comptime_ret_ty: *Type,
8315) CompileError!Air.Inst.Ref {
8316 const pt = sema.pt;
8317 const zcu = pt.zcu;
8318 const gpa = sema.gpa;
8319 const ip = &zcu.intern_pool;
8320
8321 // Generic function pointers are comptime-only types, so `func` is definitely comptime-known.
8322 const func_val = (sema.resolveValue(func) catch unreachable).?;
8323 if (func_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, func_src);
83248028
8325 const generic_owner = switch (zcu.intern_pool.indexToKey(func_val.toIntern())) {8029 try sema.emitBackwardBranch(block, call_src);
8326 .func => func_val.toIntern(),
8327 .ptr => |ptr| ip.getNav(ptr.base_addr.nav).status.fully_resolved.val,
8328 else => unreachable,
8329 };
8330 const generic_owner_func = zcu.intern_pool.indexToKey(generic_owner).func;
8331 const generic_owner_ty_info = zcu.typeToFunc(Type.fromInterned(generic_owner_func.ty)).?;
83328030
8333 try sema.declareDependency(.{ .src_hash = generic_owner_func.zir_body_inst });8031 const want_memoize = m: {
83348032 // TODO: comptime call memoization is currently not supported under incremental compilation
8335 // Even though there may already be a generic instantiation corresponding8033 // since dependencies are not marked on callers. If we want to keep this around (we should
8336 // to this callsite, we must evaluate the expressions of the generic8034 // check that it's worthwhile first!), each memoized call needs an `AnalUnit`.
8337 // function signature with the values of the callsite plugged in.8035 if (zcu.comp.incremental) break :m false;
8338 // Importantly, this may include type coercions that determine whether the8036 if (!block.isComptime()) break :m false;
8339 // instantiation is a match of a previous instantiation.8037 for (args) |a| {
8340 // The actual monomorphization happens via adding `func_instance` to8038 const val = (try sema.resolveValue(a)).?;
8341 // `InternPool`.8039 if (val.canMutateComptimeVarState(zcu)) break :m false;
83428040 }
8343 // Since we are looking at the generic owner here, it has analysis state.8041 break :m true;
8344 const fn_nav = ip.getNav(generic_owner_func.owner_nav);8042 };
8345 const fn_zir = zcu.navFileScope(generic_owner_func.owner_nav).zir;8043 const memoized_arg_values: []const InternPool.Index = if (want_memoize) arg_vals: {
8346 const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip) orelse return error.AnalysisFail);8044 const vals = try sema.arena.alloc(InternPool.Index, args.len);
8045 for (vals, args) |*v, a| v.* = (try sema.resolveValue(a)).?.toIntern();
8046 break :arg_vals vals;
8047 } else undefined;
8048 if (want_memoize) memoize: {
8049 const memoized_call_index = ip.getIfExists(.{
8050 .memoized_call = .{
8051 .func = func_val.?.toIntern(),
8052 .arg_values = memoized_arg_values,
8053 .result = undefined, // ignored by hash+eql
8054 .branch_count = undefined, // ignored by hash+eql
8055 },
8056 }) orelse break :memoize;
8057 const memoized_call = ip.indexToKey(memoized_call_index).memoized_call;
8058 if (sema.branch_count + memoized_call.branch_count > sema.branch_quota) {
8059 // Let the call play out se we get the correct source location for the
8060 // "evaluation exceeded X backwards branches" error.
8061 break :memoize;
8062 }
8063 sema.branch_count += memoized_call.branch_count;
8064 const result = Air.internedToRef(memoized_call.result);
8065 if (ensure_result_used) {
8066 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
8067 }
8068 return result;
8069 }
83478070
8348 const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count());8071 var new_ies: InferredErrorSet = .{ .func = .none };
8349 @memset(comptime_args, .none);
83508072
8351 // We may overestimate the number of runtime args, but this will definitely be sufficient.8073 const old_inst_map = sema.inst_map;
8352 const max_runtime_args = args_info.count() - @popCount(generic_owner_ty_info.comptime_bits);8074 const old_code = sema.code;
8353 var runtime_args = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(sema.arena, max_runtime_args);8075 const old_func_index = sema.func_index;
8076 const old_fn_ret_ty = sema.fn_ret_ty;
8077 const old_fn_ret_ty_ies = sema.fn_ret_ty_ies;
8078 const old_error_return_trace_index_on_fn_entry = sema.error_return_trace_index_on_fn_entry;
8079 defer {
8080 sema.inst_map.deinit(gpa);
8081 sema.inst_map = old_inst_map;
8082 sema.code = old_code;
8083 sema.func_index = old_func_index;
8084 sema.fn_ret_ty = old_fn_ret_ty;
8085 sema.fn_ret_ty_ies = old_fn_ret_ty_ies;
8086 sema.error_return_trace_index_on_fn_entry = old_error_return_trace_index_on_fn_entry;
8087 }
8088 sema.inst_map = .{};
8089 sema.code = fn_zir;
8090 sema.func_index = func_val.?.toIntern();
8091 sema.fn_ret_ty = if (fn_zir_info.inferred_error_set) try pt.errorUnionType(
8092 .fromInterned(.adhoc_inferred_error_set_type),
8093 resolved_ret_ty.errorUnionPayload(zcu),
8094 ) else resolved_ret_ty;
8095 sema.fn_ret_ty_ies = if (fn_zir_info.inferred_error_set) &new_ies else null;
8096
8097 try sema.inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body);
8098 for (args, 0..) |arg, arg_idx| {
8099 sema.inst_map.putAssumeCapacityNoClobber(fn_zir_info.param_body[arg_idx], arg);
8100 }
8101
8102 const need_debug_scope = !block.isComptime() and !block.is_typeof and !block.ownerModule().strip;
8103 const block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
8104 try sema.air_instructions.append(gpa, .{
8105 .tag = if (need_debug_scope) .dbg_inline_block else .block,
8106 .data = undefined,
8107 });
83548108
8355 // Re-run the block that creates the function, with the comptime parameters8109 var inlining: Block.Inlining = .{
8356 // pre-populated inside `inst_map`. This causes `param_comptime` and8110 .call_block = block,
8357 // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a8111 .call_src = call_src,
8358 // new, monomorphized function, with the comptime parameters elided.8112 .has_comptime_args = for (args) |a| {
8359 var child_sema: Sema = .{8113 if (try sema.isComptimeKnown(a)) break true;
8360 .pt = pt,8114 } else false,
8361 .gpa = gpa,8115 .func = func_val.?.toIntern(),
8362 .arena = sema.arena,8116 .comptime_result = undefined,
8363 .code = fn_zir,8117 .merges = .{
8364 // We pass the generic callsite's owner decl here because whatever `Decl`8118 .block_inst = block_inst,
8365 // dependencies are chased at this point should be attached to the8119 .results = .empty,
8366 // callsite, not the `Decl` associated with the `func_instance`.8120 .br_list = .empty,
8367 .owner = sema.owner,8121 .src_locs = .empty,
8368 .func_index = sema.func_index,8122 },
8369 // This may not be known yet, since the calling convention could be generic, but there
8370 // should be no illegal instructions encountered while creating the function anyway.
8371 .func_is_naked = false,
8372 .fn_ret_ty = Type.void,
8373 .fn_ret_ty_ies = null,
8374 .comptime_args = comptime_args,
8375 .generic_owner = generic_owner,
8376 .generic_call_src = call_src,
8377 .branch_quota = sema.branch_quota,
8378 .branch_count = sema.branch_count,
8379 .comptime_err_ret_trace = sema.comptime_err_ret_trace,
8380 };8123 };
8381 defer child_sema.deinit();
8382
8383 var child_block: Block = .{8124 var child_block: Block = .{
8384 .parent = null,8125 .parent = null,
8385 .sema = &child_sema,8126 .sema = sema,
8386 .namespace = fn_nav.analysis.?.namespace,8127 .namespace = fn_nav.analysis.?.namespace,
8387 .instructions = .{},8128 .instructions = .{},
8388 .inlining = null,8129 .inlining = &inlining,
8389 .comptime_reason = undefined, // set as needed8130 .is_typeof = block.is_typeof,
8131 .comptime_reason = if (block.isComptime()) .inlining_parent else null,
8132 .error_return_trace_index = block.error_return_trace_index,
8133 .runtime_cond = block.runtime_cond,
8134 .runtime_loop = block.runtime_loop,
8135 .runtime_index = block.runtime_index,
8390 .src_base_inst = fn_nav.analysis.?.zir_index,8136 .src_base_inst = fn_nav.analysis.?.zir_index,
8391 .type_name_ctx = fn_nav.fqn,8137 .type_name_ctx = fn_nav.fqn,
8392 };8138 };
8393 defer child_block.instructions.deinit(gpa);
8394
8395 try child_sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
8396
8397 for (fn_info.param_body[0..args_info.count()], 0..) |param_inst, arg_index| {
8398 const param_tag = fn_zir.instructions.items(.tag)[@intFromEnum(param_inst)];
83998139
8400 const param_ty = switch (generic_owner_ty_info.param_types.get(ip)[arg_index]) {8140 defer child_block.instructions.deinit(gpa);
8401 else => |ty| Type.fromInterned(ty), // parameter is not generic, so type is already resolved8141 defer inlining.merges.deinit(gpa);
8402 .generic_poison_type => param_ty: {
8403 // We have every parameter before this one, so can resolve this parameter's type now.
8404 // However, first check the param type, since it may be anytype.
8405 switch (param_tag) {
8406 .param_anytype, .param_anytype_comptime => {
8407 // The parameter doesn't have a type.
8408 break :param_ty Type.generic_poison;
8409 },
8410 .param, .param_comptime => {
8411 // We now know every prior parameter, so can resolve this
8412 // parameter's type. The child sema has these types.
8413 const param_data = fn_zir.instructions.items(.data)[@intFromEnum(param_inst)].pl_tok;
8414 const param_extra = fn_zir.extraData(Zir.Inst.Param, param_data.payload_index);
8415 const param_ty_body = fn_zir.bodySlice(param_extra.end, param_extra.data.body_len);
8416
8417 // Make sure any nested instructions don't clobber our work.
8418 const prev_params = child_block.params;
8419 const prev_no_partial_func_ty = child_sema.no_partial_func_ty;
8420 const prev_generic_owner = child_sema.generic_owner;
8421 const prev_generic_call_src = child_sema.generic_call_src;
8422 child_block.params = .{};
8423 child_sema.no_partial_func_ty = true;
8424 child_sema.generic_owner = .none;
8425 child_sema.generic_call_src = LazySrcLoc.unneeded;
8426 defer {
8427 child_block.params = prev_params;
8428 child_sema.no_partial_func_ty = prev_no_partial_func_ty;
8429 child_sema.generic_owner = prev_generic_owner;
8430 child_sema.generic_call_src = prev_generic_call_src;
8431 }
84328142
8433 const param_ty_src = child_block.tokenOffset(param_data.src_tok);8143 if (!inlining.has_comptime_args) {
8434 child_block.comptime_reason = .{ .reason = .{8144 var block_it = block;
8435 .src = param_ty_src,8145 while (block_it.inlining) |parent_inlining| {
8436 .r = .{ .simple = .type },8146 if (!parent_inlining.has_comptime_args and parent_inlining.func == func_val.?.toIntern()) {
8437 } };8147 return sema.fail(block, call_src, "inline call is recursive", .{});
8438 const param_ty_inst = try child_sema.resolveInlineBody(&child_block, param_ty_body, param_inst);8148 }
8439 break :param_ty try child_sema.analyzeAsType(&child_block, param_ty_src, param_ty_inst);8149 block_it = parent_inlining.call_block;
8440 },
8441 else => unreachable,
8442 }
8443 },
8444 };
8445 const arg_ref = try args_info.analyzeArg(sema, block, arg_index, param_ty, generic_owner_ty_info, func);
8446 try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_index), arg_ref);
8447 const arg_ty = sema.typeOf(arg_ref);
8448 if (arg_ty.zigTypeTag(zcu) == .noreturn) {
8449 // This terminates argument analysis.
8450 return arg_ref;
8451 }8150 }
8151 }
84528152
8453 const arg_is_comptime = switch (param_tag) {8153 if (!block.isComptime() and !block.is_typeof) {
8454 .param_comptime, .param_anytype_comptime => true,8154 const zir_tags = sema.code.instructions.items(.tag);
8455 .param, .param_anytype => try arg_ty.comptimeOnlySema(pt),8155 const zir_datas = sema.code.instructions.items(.data);
8456 else => unreachable,8156 for (fn_zir_info.param_body) |inst| switch (zir_tags[@intFromEnum(inst)]) {
8157 .param, .param_comptime => {
8158 const extra = sema.code.extraData(Zir.Inst.Param, zir_datas[@intFromEnum(inst)].pl_tok.payload_index);
8159 const param_name = sema.code.nullTerminatedString(extra.data.name);
8160 const air_inst = sema.inst_map.get(inst).?;
8161 try sema.addDbgVar(&child_block, air_inst, .dbg_arg_inline, param_name);
8162 },
8163 .param_anytype, .param_anytype_comptime => {
8164 const param_name = zir_datas[@intFromEnum(inst)].str_tok.get(sema.code);
8165 const air_inst = sema.inst_map.get(inst).?;
8166 try sema.addDbgVar(&child_block, air_inst, .dbg_arg_inline, param_name);
8167 },
8168 else => {},
8457 };8169 };
8458
8459 if (arg_is_comptime) {
8460 if (try sema.resolveValue(arg_ref)) |arg_val| {
8461 comptime_args[arg_index] = arg_val.toIntern();
8462 child_sema.inst_map.putAssumeCapacityNoClobber(
8463 param_inst,
8464 Air.internedToRef(arg_val.toIntern()),
8465 );
8466 } else switch (param_tag) {
8467 .param_comptime,
8468 .param_anytype_comptime,
8469 => return sema.failWithOwnedErrorMsg(block, msg: {
8470 const arg_src = args_info.argSrc(block, arg_index);
8471 const msg = try sema.errMsg(arg_src, "runtime-known argument passed to comptime parameter", .{});
8472 errdefer msg.destroy(sema.gpa);
8473 const param_src = child_block.tokenOffset(switch (param_tag) {
8474 .param_comptime => fn_zir.instructions.items(.data)[@intFromEnum(param_inst)].pl_tok.src_tok,
8475 .param_anytype_comptime => fn_zir.instructions.items(.data)[@intFromEnum(param_inst)].str_tok.src_tok,
8476 else => unreachable,
8477 });
8478 try child_sema.errNote(param_src, msg, "declared comptime here", .{});
8479 break :msg msg;
8480 }),
8481
8482 .param,
8483 .param_anytype,
8484 => return sema.failWithOwnedErrorMsg(block, msg: {
8485 const arg_src = args_info.argSrc(block, arg_index);
8486 const msg = try sema.errMsg(arg_src, "runtime-known argument passed to parameter of comptime-only type", .{});
8487 errdefer msg.destroy(sema.gpa);
8488 const param_src = child_block.tokenOffset(switch (param_tag) {
8489 .param => fn_zir.instructions.items(.data)[@intFromEnum(param_inst)].pl_tok.src_tok,
8490 .param_anytype => fn_zir.instructions.items(.data)[@intFromEnum(param_inst)].str_tok.src_tok,
8491 else => unreachable,
8492 });
8493 try child_sema.errNote(param_src, msg, "declared here", .{});
8494 try sema.explainWhyTypeIsComptime(msg, arg_src, arg_ty);
8495 break :msg msg;
8496 }),
8497
8498 else => unreachable,
8499 }
8500 } else {
8501 // The parameter is runtime-known.
8502 const param_name: Zir.NullTerminatedString = switch (param_tag) {
8503 .param_anytype => fn_zir.instructions.items(.data)[@intFromEnum(param_inst)].str_tok.start,
8504 .param => name: {
8505 const inst_data = fn_zir.instructions.items(.data)[@intFromEnum(param_inst)].pl_tok;
8506 const extra = fn_zir.extraData(Zir.Inst.Param, inst_data.payload_index);
8507 break :name extra.data.name;
8508 },
8509 else => unreachable,
8510 };
8511 child_sema.inst_map.putAssumeCapacityNoClobber(param_inst, try child_block.addInst(.{
8512 .tag = .arg,
8513 .data = .{ .arg = .{
8514 .ty = Air.internedToRef(arg_ty.toIntern()),
8515 .name = if (child_block.ownerModule().strip)
8516 .none
8517 else
8518 try sema.appendAirString(fn_zir.nullTerminatedString(param_name)),
8519 } },
8520 }));
8521 try child_block.params.append(sema.arena, .{
8522 .ty = arg_ty.toIntern(), // This is the type after coercion
8523 .is_comptime = false, // We're adding only runtime args to the instantiation
8524 .name = param_name,
8525 });
8526 runtime_args.appendAssumeCapacity(arg_ref);
8527 }
8528 }8170 }
85298171
8530 // We've already handled parameters, so don't resolve the whole body. Instead, just8172 child_block.error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block);
8531 // do the instructions after the params (i.e. the func itself).8173 // Save the error trace as our first action in the function
8532 child_block.comptime_reason = .{ .reason = .{8174 // to match the behavior of runtime function calls.
8533 .src = call_src,8175 const error_return_trace_index_on_parent_fn_entry = sema.error_return_trace_index_on_fn_entry;
8534 .r = .{ .simple = .type },8176 sema.error_return_trace_index_on_fn_entry = child_block.error_return_trace_index;
8535 } };8177 defer sema.error_return_trace_index_on_fn_entry = error_return_trace_index_on_parent_fn_entry;
8536 const new_func_inst = try child_sema.resolveInlineBody(&child_block, fn_info.param_body[args_info.count()..], fn_info.param_body_inst);
8537 const callee_index = (child_sema.resolveConstDefinedValue(&child_block, LazySrcLoc.unneeded, new_func_inst, undefined) catch unreachable).toIntern();
85388178
8539 const callee = zcu.funcInfo(callee_index);8179 // We temporarily set `allow_memoize` to `true` to track this comptime call.
8540 callee.maxBranchQuota(ip, sema.branch_quota);8180 // It is restored after the call finishes analysis, so that a caller may
8181 // know whether an in-progress call (containing this call) may be memoized.
8182 const old_allow_memoize = sema.allow_memoize;
8183 defer sema.allow_memoize = old_allow_memoize and sema.allow_memoize;
8184 sema.allow_memoize = true;
85418185
8542 // Make a runtime call to the new function, making sure to omit the comptime args.8186 // Store the current eval branch count so we can find out how many eval branches
8543 const func_ty = Type.fromInterned(callee.ty);8187 // the comptime call caused.
8544 const func_ty_info = zcu.typeToFunc(func_ty).?;8188 const old_branch_count = sema.branch_count;
85458189
8546 // If the call evaluated to a return type that requires comptime, never mind8190 const result_raw: Air.Inst.Ref = result: {
8547 // our generic instantiation. Instead we need to perform a comptime call.8191 sema.analyzeFnBody(&child_block, fn_zir_info.body) catch |err| switch (err) {
8548 if (try Type.fromInterned(func_ty_info.return_type).comptimeOnlySema(pt)) {8192 error.ComptimeReturn => break :result inlining.comptime_result,
8549 comptime_ret_ty.* = .fromInterned(func_ty_info.return_type);8193 else => |e| return e,
8550 return error.ComptimeReturn;8194 };
8551 }8195 break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, &inlining.merges, need_debug_scope);
8552 // Similarly, if the call evaluated to a generic type we need to instead8196 };
8553 // call it inline.
8554 if (func_ty_info.is_generic or func_ty_info.cc == .@"inline") {
8555 return error.GenericPoison;
8556 }
85578197
8558 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);8198 const result: Air.Inst.Ref = if (try sema.resolveValue(result_raw)) |result_val| r: {
8199 const val_resolved = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern());
8200 break :r Air.internedToRef(val_resolved);
8201 } else r: {
8202 const resolved_ty = try sema.resolveAdHocInferredErrorSetTy(block, call_src, sema.typeOf(result_raw).toIntern());
8203 if (resolved_ty == .none) break :r result_raw;
8204 // TODO: mutate in place the previous instruction if possible
8205 // rather than adding a bitcast instruction.
8206 break :r try block.addBitCast(.fromInterned(resolved_ty), result_raw);
8207 };
85598208
8560 switch (sema.owner.unwrap()) {8209 if (block.isComptime()) {
8561 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},8210 const result_val = (try sema.resolveValue(result)).?;
8562 .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {8211 if (want_memoize and sema.allow_memoize and !result_val.canMutateComptimeVarState(zcu)) {
8563 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);8212 _ = try pt.intern(.{ .memoized_call = .{
8564 },8213 .func = func_val.?.toIntern(),
8214 .arg_values = memoized_arg_values,
8215 .result = result_val.toIntern(),
8216 .branch_count = sema.branch_count - old_branch_count,
8217 } });
8218 }
8565 }8219 }
85668220
8567 try sema.addReferenceEntry(call_src, AnalUnit.wrap(.{ .func = callee_index }));
8568 try zcu.ensureFuncBodyAnalysisQueued(callee_index);
8569
8570 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).@"struct".fields.len + runtime_args.items.len);
8571 const result = try block.addInst(.{
8572 .tag = call_tag,
8573 .data = .{ .pl_op = .{
8574 .operand = Air.internedToRef(callee_index),
8575 .payload = sema.addExtraAssumeCapacity(Air.Call{
8576 .args_len = @intCast(runtime_args.items.len),
8577 }),
8578 } },
8579 });
8580 sema.appendRefsAssumeCapacity(runtime_args.items);
8581
8582 // `child_sema` is owned by us, so just take its exports.
8583 try sema.exports.appendSlice(sema.gpa, child_sema.exports.items);
8584
8585 if (ensure_result_used) {8221 if (ensure_result_used) {
8586 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);8222 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
8587 }8223 }
8588 if (call_tag == .call_always_tail) {8224
8589 return sema.handleTailCall(block, call_src, func_ty, result);8225 return result;
8226}
8227
8228fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref {
8229 const pt = sema.pt;
8230 const zcu = pt.zcu;
8231 const target = zcu.getTarget();
8232 const backend = zcu.comp.getZigBackend();
8233 if (!target_util.supportsTailCall(target, backend)) {
8234 return sema.fail(block, call_src, "unable to perform tail call: compiler backend '{s}' does not support tail calls on target architecture '{s}' with the selected CPU feature flags", .{
8235 @tagName(backend), @tagName(target.cpu.arch),
8236 });
8590 }8237 }
8591 if (func_ty.fnReturnType(zcu).isNoReturn(zcu)) {8238 const owner_func_ty = Type.fromInterned(zcu.funcInfo(sema.owner.unwrap().func).ty);
8592 _ = try block.addNoOp(.unreach);8239 if (owner_func_ty.toIntern() != func_ty.toIntern()) {
8593 return .unreachable_value;8240 return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{
8241 func_ty.fmt(pt), owner_func_ty.fmt(pt),
8242 });
8594 }8243 }
8595 return result;8244 _ = try block.addUnOp(.ret, result);
8245 return .unreachable_value;
8596}8246}
85978247
8598fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {8248fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -9576,9 +9226,7 @@ fn zirFunc(...@@ -9576,9 +9226,7 @@ fn zirFunc(
9576 // the callconv based on whether it is exported. Otherwise, the callconv defaults9226 // the callconv based on whether it is exported. Otherwise, the callconv defaults
9577 // to `.auto`.9227 // to `.auto`.
9578 const cc: std.builtin.CallingConvention = if (has_body) cc: {9228 const cc: std.builtin.CallingConvention = if (has_body) cc: {
9579 const func_decl_nav = if (sema.generic_owner != .none) nav: {9229 const func_decl_nav = sema.owner.unwrap().nav_val;
9580 break :nav zcu.funcInfo(sema.generic_owner).owner_nav;
9581 } else sema.owner.unwrap().nav_val;
9582 const fn_is_exported = exported: {9230 const fn_is_exported = exported: {
9583 const decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(ip) orelse return error.AnalysisFail;9231 const decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(ip) orelse return error.AnalysisFail;
9584 const zir_decl = sema.code.getDeclaration(decl_inst);9232 const zir_decl = sema.code.getDeclaration(decl_inst);
...@@ -9635,17 +9283,11 @@ fn resolveGenericBody(...@@ -9635,17 +9283,11 @@ fn resolveGenericBody(
9635 // Make sure any nested param instructions don't clobber our work.9283 // Make sure any nested param instructions don't clobber our work.
9636 const prev_params = block.params;9284 const prev_params = block.params;
9637 const prev_no_partial_func_type = sema.no_partial_func_ty;9285 const prev_no_partial_func_type = sema.no_partial_func_ty;
9638 const prev_generic_owner = sema.generic_owner;
9639 const prev_generic_call_src = sema.generic_call_src;
9640 block.params = .{};9286 block.params = .{};
9641 sema.no_partial_func_ty = true;9287 sema.no_partial_func_ty = true;
9642 sema.generic_owner = .none;
9643 sema.generic_call_src = LazySrcLoc.unneeded;
9644 defer {9288 defer {
9645 block.params = prev_params;9289 block.params = prev_params;
9646 sema.no_partial_func_ty = prev_no_partial_func_type;9290 sema.no_partial_func_ty = prev_no_partial_func_type;
9647 sema.generic_owner = prev_generic_owner;
9648 sema.generic_call_src = prev_generic_call_src;
9649 }9291 }
96509292
9651 const uncasted = sema.resolveInlineBody(block, body, func_inst) catch |err| break :err err;9293 const uncasted = sema.resolveInlineBody(block, body, func_inst) catch |err| break :err err;
...@@ -9911,16 +9553,10 @@ fn funcCommon(...@@ -9911,16 +9553,10 @@ fn funcCommon(
9911 const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });9553 const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });
9912 const func_src = block.nodeOffset(src_node_offset);9554 const func_src = block.nodeOffset(src_node_offset);
99139555
9914 var is_generic = bare_return_type.isGenericPoison();9556 if (bare_return_type.isGenericPoison() and sema.no_partial_func_ty) return error.GenericPoison;
99159557
9916 if (var_args) {9558 const ret_ty_requires_comptime = try bare_return_type.comptimeOnlySema(pt);
9917 if (is_generic) {9559 var is_generic = bare_return_type.isGenericPoison() or ret_ty_requires_comptime;
9918 return sema.fail(block, func_src, "generic function cannot be variadic", .{});
9919 }
9920 try sema.checkCallConvSupportsVarArgs(block, cc_src, cc);
9921 }
9922
9923 const is_source_decl = sema.generic_owner == .none;
99249560
9925 var comptime_bits: u32 = 0;9561 var comptime_bits: u32 = 0;
9926 for (block.params.items(.ty), block.params.items(.is_comptime), 0..) |param_ty_ip, param_is_comptime, i| {9562 for (block.params.items(.ty), block.params.items(.is_comptime), 0..) |param_ty_ip, param_is_comptime, i| {
...@@ -9933,16 +9569,21 @@ fn funcCommon(...@@ -9933,16 +9569,21 @@ fn funcCommon(
9933 .fn_proto_node_offset = src_node_offset,9569 .fn_proto_node_offset = src_node_offset,
9934 .param_index = @intCast(i),9570 .param_index = @intCast(i),
9935 } });9571 } });
9936 const requires_comptime = try param_ty.comptimeOnlySema(pt);9572 const param_ty_comptime = try param_ty.comptimeOnlySema(pt);
9937 if (param_is_comptime or requires_comptime) {9573 const param_ty_generic = param_ty.isGenericPoison();
9574 if (param_ty_generic and sema.no_partial_func_ty) {
9575 return error.GenericPoison;
9576 }
9577 if (param_is_comptime or param_ty_comptime or param_ty_generic) {
9578 is_generic = true;
9579 }
9580 if (param_is_comptime) {
9938 comptime_bits |= @as(u32, 1) << @intCast(i); // TODO: handle cast error9581 comptime_bits |= @as(u32, 1) << @intCast(i); // TODO: handle cast error
9939 }9582 }
9940 const this_generic = param_ty.isGenericPoison();
9941 is_generic = is_generic or this_generic;
9942 if (param_is_comptime and !target_util.fnCallConvAllowsZigTypes(cc)) {9583 if (param_is_comptime and !target_util.fnCallConvAllowsZigTypes(cc)) {
9943 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});9584 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
9944 }9585 }
9945 if (this_generic and !sema.no_partial_func_ty and !target_util.fnCallConvAllowsZigTypes(cc)) {9586 if (param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc)) {
9946 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});9587 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
9947 }9588 }
9948 if (!param_ty.isValidParamType(zcu)) {9589 if (!param_ty.isValidParamType(zcu)) {
...@@ -9951,7 +9592,7 @@ fn funcCommon(...@@ -9951,7 +9592,7 @@ fn funcCommon(
9951 opaque_str, param_ty.fmt(pt),9592 opaque_str, param_ty.fmt(pt),
9952 });9593 });
9953 }9594 }
9954 if (!this_generic and !target_util.fnCallConvAllowsZigTypes(cc) and !try sema.validateExternType(param_ty, .param_ty)) {9595 if (!param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc) and !try sema.validateExternType(param_ty, .param_ty)) {
9955 const msg = msg: {9596 const msg = msg: {
9956 const msg = try sema.errMsg(param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{9597 const msg = try sema.errMsg(param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
9957 param_ty.fmt(pt), @tagName(cc),9598 param_ty.fmt(pt), @tagName(cc),
...@@ -9965,7 +9606,7 @@ fn funcCommon(...@@ -9965,7 +9606,7 @@ fn funcCommon(
9965 };9606 };
9966 return sema.failWithOwnedErrorMsg(block, msg);9607 return sema.failWithOwnedErrorMsg(block, msg);
9967 }9608 }
9968 if (is_source_decl and requires_comptime and !param_is_comptime and has_body and !block.isComptime()) {9609 if (param_ty_comptime and !param_is_comptime and has_body and !block.isComptime()) {
9969 const msg = msg: {9610 const msg = msg: {
9970 const msg = try sema.errMsg(param_src, "parameter of type '{}' must be declared comptime", .{9611 const msg = try sema.errMsg(param_src, "parameter of type '{}' must be declared comptime", .{
9971 param_ty.fmt(pt),9612 param_ty.fmt(pt),
...@@ -9979,7 +9620,7 @@ fn funcCommon(...@@ -9979,7 +9620,7 @@ fn funcCommon(
9979 };9620 };
9980 return sema.failWithOwnedErrorMsg(block, msg);9621 return sema.failWithOwnedErrorMsg(block, msg);
9981 }9622 }
9982 if (is_source_decl and !this_generic and is_noalias and9623 if (!param_ty_generic and is_noalias and
9983 !(param_ty.zigTypeTag(zcu) == .pointer or param_ty.isPtrLikeOptional(zcu)))9624 !(param_ty.zigTypeTag(zcu) == .pointer or param_ty.isPtrLikeOptional(zcu)))
9984 {9625 {
9985 return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});9626 return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});
...@@ -10007,48 +9648,17 @@ fn funcCommon(...@@ -10007,48 +9648,17 @@ fn funcCommon(
10007 }9648 }
10008 }9649 }
100099650
10010 const ret_ty_requires_comptime = try bare_return_type.comptimeOnlySema(pt);9651 if (var_args) {
9652 if (is_generic) {
9653 return sema.fail(block, func_src, "generic function cannot be variadic", .{});
9654 }
9655 try sema.checkCallConvSupportsVarArgs(block, cc_src, cc);
9656 }
9657
10011 const ret_poison = bare_return_type.isGenericPoison();9658 const ret_poison = bare_return_type.isGenericPoison();
10012 const final_is_generic = is_generic or comptime_bits != 0 or ret_ty_requires_comptime;
100139659
10014 const param_types = block.params.items(.ty);9660 const param_types = block.params.items(.ty);
100159661
10016 if (!is_source_decl) {
10017 assert(has_body);
10018 assert(!is_generic);
10019 assert(comptime_bits == 0);
10020 assert(!var_args);
10021 if (inferred_error_set) {
10022 try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
10023 }
10024 const func_index = try ip.getFuncInstance(gpa, pt.tid, .{
10025 .param_types = param_types,
10026 .noalias_bits = noalias_bits,
10027 .bare_return_type = bare_return_type.toIntern(),
10028 .is_noinline = is_noinline,
10029 .inferred_error_set = inferred_error_set,
10030 .generic_owner = sema.generic_owner,
10031 .comptime_args = sema.comptime_args,
10032 });
10033 return finishFunc(
10034 sema,
10035 block,
10036 func_index,
10037 .none,
10038 ret_poison,
10039 bare_return_type,
10040 ret_ty_src,
10041 cc,
10042 is_source_decl,
10043 ret_ty_requires_comptime,
10044 func_inst,
10045 cc_src,
10046 is_noinline,
10047 is_generic,
10048 final_is_generic,
10049 );
10050 }
10051
10052 if (inferred_error_set) {9662 if (inferred_error_set) {
10053 assert(has_body);9663 assert(has_body);
10054 if (!ret_poison)9664 if (!ret_poison)
...@@ -10062,7 +9672,7 @@ fn funcCommon(...@@ -10062,7 +9672,7 @@ fn funcCommon(
10062 .bare_return_type = bare_return_type.toIntern(),9672 .bare_return_type = bare_return_type.toIntern(),
10063 .cc = cc,9673 .cc = cc,
10064 .is_var_args = var_args,9674 .is_var_args = var_args,
10065 .is_generic = final_is_generic,9675 .is_generic = is_generic,
10066 .is_noinline = is_noinline,9676 .is_noinline = is_noinline,
100679677
10068 .zir_body_inst = try block.trackZir(func_inst),9678 .zir_body_inst = try block.trackZir(func_inst),
...@@ -10080,13 +9690,11 @@ fn funcCommon(...@@ -10080,13 +9690,11 @@ fn funcCommon(
10080 bare_return_type,9690 bare_return_type,
10081 ret_ty_src,9691 ret_ty_src,
10082 cc,9692 cc,
10083 is_source_decl,
10084 ret_ty_requires_comptime,9693 ret_ty_requires_comptime,
10085 func_inst,9694 func_inst,
10086 cc_src,9695 cc_src,
10087 is_noinline,9696 is_noinline,
10088 is_generic,9697 is_generic,
10089 final_is_generic,
10090 );9698 );
10091 }9699 }
100929700
...@@ -10097,7 +9705,7 @@ fn funcCommon(...@@ -10097,7 +9705,7 @@ fn funcCommon(
10097 .return_type = bare_return_type.toIntern(),9705 .return_type = bare_return_type.toIntern(),
10098 .cc = cc,9706 .cc = cc,
10099 .is_var_args = var_args,9707 .is_var_args = var_args,
10100 .is_generic = final_is_generic,9708 .is_generic = is_generic,
10101 .is_noinline = is_noinline,9709 .is_noinline = is_noinline,
10102 });9710 });
101039711
...@@ -10122,13 +9730,11 @@ fn funcCommon(...@@ -10122,13 +9730,11 @@ fn funcCommon(
10122 bare_return_type,9730 bare_return_type,
10123 ret_ty_src,9731 ret_ty_src,
10124 cc,9732 cc,
10125 is_source_decl,
10126 ret_ty_requires_comptime,9733 ret_ty_requires_comptime,
10127 func_inst,9734 func_inst,
10128 cc_src,9735 cc_src,
10129 is_noinline,9736 is_noinline,
10130 is_generic,9737 is_generic,
10131 final_is_generic,
10132 );9738 );
10133 }9739 }
101349740
...@@ -10141,13 +9747,11 @@ fn funcCommon(...@@ -10141,13 +9747,11 @@ fn funcCommon(
10141 bare_return_type,9747 bare_return_type,
10142 ret_ty_src,9748 ret_ty_src,
10143 cc,9749 cc,
10144 is_source_decl,
10145 ret_ty_requires_comptime,9750 ret_ty_requires_comptime,
10146 func_inst,9751 func_inst,
10147 cc_src,9752 cc_src,
10148 is_noinline,9753 is_noinline,
10149 is_generic,9754 is_generic,
10150 final_is_generic,
10151 );9755 );
10152}9756}
101539757
...@@ -10160,13 +9764,11 @@ fn finishFunc(...@@ -10160,13 +9764,11 @@ fn finishFunc(
10160 bare_return_type: Type,9764 bare_return_type: Type,
10161 ret_ty_src: LazySrcLoc,9765 ret_ty_src: LazySrcLoc,
10162 cc_resolved: std.builtin.CallingConvention,9766 cc_resolved: std.builtin.CallingConvention,
10163 is_source_decl: bool,
10164 ret_ty_requires_comptime: bool,9767 ret_ty_requires_comptime: bool,
10165 func_inst: Zir.Inst.Index,9768 func_inst: Zir.Inst.Index,
10166 cc_src: LazySrcLoc,9769 cc_src: LazySrcLoc,
10167 is_noinline: bool,9770 is_noinline: bool,
10168 is_generic: bool,9771 is_generic: bool,
10169 final_is_generic: bool,
10170) CompileError!Air.Inst.Ref {9772) CompileError!Air.Inst.Ref {
10171 const pt = sema.pt;9773 const pt = sema.pt;
10172 const zcu = pt.zcu;9774 const zcu = pt.zcu;
...@@ -10203,7 +9805,7 @@ fn finishFunc(...@@ -10203,7 +9805,7 @@ fn finishFunc(
102039805
10204 // If the return type is comptime-only but not dependent on parameters then9806 // If the return type is comptime-only but not dependent on parameters then
10205 // all parameter types also need to be comptime.9807 // all parameter types also need to be comptime.
10206 if (is_source_decl and opt_func_index != .none and ret_ty_requires_comptime and !block.isComptime()) comptime_check: {9808 if (opt_func_index != .none and ret_ty_requires_comptime and !block.isComptime()) comptime_check: {
10207 for (block.params.items(.is_comptime)) |is_comptime| {9809 for (block.params.items(.is_comptime)) |is_comptime| {
10208 if (!is_comptime) break;9810 if (!is_comptime) break;
10209 } else break :comptime_check;9811 } else break :comptime_check;
...@@ -10300,8 +9902,7 @@ fn finishFunc(...@@ -10300,8 +9902,7 @@ fn finishFunc(
10300 }),9902 }),
10301 }9903 }
103029904
10303 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;9905 if (!is_generic and sema.wantErrorReturnTracing(return_type)) {
10304 if (!final_is_generic and sema.wantErrorReturnTracing(return_type)) {
10305 // Make sure that StackTrace's fields are resolved so that the backend can9906 // Make sure that StackTrace's fields are resolved so that the backend can
10306 // lower this fn type.9907 // lower this fn type.
10307 const unresolved_stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(0), .StackTrace);9908 const unresolved_stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(0), .StackTrace);
...@@ -10328,17 +9929,11 @@ fn zirParam(...@@ -10328,17 +9929,11 @@ fn zirParam(
10328 // Make sure any nested param instructions don't clobber our work.9929 // Make sure any nested param instructions don't clobber our work.
10329 const prev_params = block.params;9930 const prev_params = block.params;
10330 const prev_no_partial_func_type = sema.no_partial_func_ty;9931 const prev_no_partial_func_type = sema.no_partial_func_ty;
10331 const prev_generic_owner = sema.generic_owner;
10332 const prev_generic_call_src = sema.generic_call_src;
10333 block.params = .{};9932 block.params = .{};
10334 sema.no_partial_func_ty = true;9933 sema.no_partial_func_ty = true;
10335 sema.generic_owner = .none;
10336 sema.generic_call_src = LazySrcLoc.unneeded;
10337 defer {9934 defer {
10338 block.params = prev_params;9935 block.params = prev_params;
10339 sema.no_partial_func_ty = prev_no_partial_func_type;9936 sema.no_partial_func_ty = prev_no_partial_func_type;
10340 sema.generic_owner = prev_generic_owner;
10341 sema.generic_call_src = prev_generic_call_src;
10342 }9937 }
103439938
10344 if (sema.resolveInlineBody(block, body, inst)) |param_ty_inst| {9939 if (sema.resolveInlineBody(block, body, inst)) |param_ty_inst| {
...@@ -26646,11 +26241,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -26646,11 +26241,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
26646 break :blk try sema.analyzeValueAsCallconv(block, cc_src, cc_val);26241 break :blk try sema.analyzeValueAsCallconv(block, cc_src, cc_val);
26647 } else cc: {26242 } else cc: {
26648 if (has_body) {26243 if (has_body) {
26649 const func_decl_nav = if (sema.generic_owner != .none) nav: {26244 const func_decl_nav = sema.owner.unwrap().nav_val;
26650 // Generic instance -- use the original function declaration to
26651 // look for the `export` syntax.
26652 break :nav zcu.funcInfo(sema.generic_owner).owner_nav;
26653 } else sema.owner.unwrap().nav_val;
26654 const func_decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(&zcu.intern_pool) orelse return error.AnalysisFail;26245 const func_decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(&zcu.intern_pool) orelse return error.AnalysisFail;
26655 const zir_decl = sema.code.getDeclaration(func_decl_inst);26246 const zir_decl = sema.code.getDeclaration(func_decl_inst);
26656 if (zir_decl.linkage == .@"export") {26247 if (zir_decl.linkage == .@"export") {
...@@ -31068,9 +30659,16 @@ fn coerceInMemoryAllowedFns(...@@ -31068,9 +30659,16 @@ fn coerceInMemoryAllowedFns(
31068 const dest_param_ty: Type = .fromInterned(dest_info.param_types.get(ip)[param_i]);30659 const dest_param_ty: Type = .fromInterned(dest_info.param_types.get(ip)[param_i]);
31069 const src_param_ty: Type = .fromInterned(src_info.param_types.get(ip)[param_i]);30660 const src_param_ty: Type = .fromInterned(src_info.param_types.get(ip)[param_i]);
3107030661
31071 const src_is_comptime = src_info.paramIsComptime(@intCast(param_i));30662 comptime_param: {
31072 const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i));30663 const src_is_comptime = src_info.paramIsComptime(@intCast(param_i));
31073 if (src_is_comptime != dest_is_comptime) {30664 const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i));
30665 if (src_is_comptime == dest_is_comptime) break :comptime_param;
30666 if (!dest_is_mut and src_is_comptime and !dest_is_comptime and try dest_param_ty.comptimeOnlySema(pt)) {
30667 // A parameter which is marked `comptime` can drop that annotation if the type is comptime-only.
30668 // The function remains generic, and the parameter is going to be comptime-resolved either way,
30669 // so this just affects whether or not the argument is comptime-evaluated at the call site.
30670 break :comptime_param;
30671 }
31074 return .{ .fn_param_comptime = .{30672 return .{ .fn_param_comptime = .{
31075 .index = param_i,30673 .index = param_i,
31076 .wanted = dest_is_comptime,30674 .wanted = dest_is_comptime,
src/Zcu.zig+24
...@@ -1928,6 +1928,24 @@ pub const SrcLoc = struct {...@@ -1928,6 +1928,24 @@ pub const SrcLoc = struct {
1928 },1928 },
1929 }1929 }
1930 },1930 },
1931 .func_decl_param_comptime => |param_idx| {
1932 const tree = try src_loc.file_scope.getTree(gpa);
1933 var buf: [1]Ast.Node.Index = undefined;
1934 const full = tree.fullFnProto(&buf, src_loc.base_node).?;
1935 var param_it = full.iterate(tree);
1936 for (0..param_idx) |_| assert(param_it.next() != null);
1937 const param = param_it.next().?;
1938 return tree.tokenToSpan(param.comptime_noalias.?);
1939 },
1940 .func_decl_param_ty => |param_idx| {
1941 const tree = try src_loc.file_scope.getTree(gpa);
1942 var buf: [1]Ast.Node.Index = undefined;
1943 const full = tree.fullFnProto(&buf, src_loc.base_node).?;
1944 var param_it = full.iterate(tree);
1945 for (0..param_idx) |_| assert(param_it.next() != null);
1946 const param = param_it.next().?;
1947 return tree.nodeToSpan(param.type_expr);
1948 },
1931 }1949 }
1932 }1950 }
1933};1951};
...@@ -2235,6 +2253,12 @@ pub const LazySrcLoc = struct {...@@ -2235,6 +2253,12 @@ pub const LazySrcLoc = struct {
2235 /// The source location points to the "tag" capture (second capture) of2253 /// The source location points to the "tag" capture (second capture) of
2236 /// a specific case of a `switch`.2254 /// a specific case of a `switch`.
2237 switch_tag_capture: SwitchCapture,2255 switch_tag_capture: SwitchCapture,
2256 /// The source location points to the `comptime` token on the given comptime parameter,
2257 /// where the base node is a function declaration. The value is the parameter index.
2258 func_decl_param_comptime: u32,
2259 /// The source location points to the type annotation on the given function parameter,
2260 /// where the base node is a function declaration. The value is the parameter index.
2261 func_decl_param_ty: u32,
22382262
2239 pub const FnProtoParam = struct {2263 pub const FnProtoParam = struct {
2240 /// The offset of the function prototype AST node.2264 /// The offset of the function prototype AST node.
src/translate_c.zig+1
...@@ -160,6 +160,7 @@ pub fn translate(...@@ -160,6 +160,7 @@ pub fn translate(
160 context.pattern_list.deinit(gpa);160 context.pattern_list.deinit(gpa);
161 }161 }
162162
163 @setEvalBranchQuota(2000);
163 inline for (@typeInfo(std.zig.c_builtins).@"struct".decls) |decl| {164 inline for (@typeInfo(std.zig.c_builtins).@"struct".decls) |decl| {
164 const builtin = try Tag.pub_var_simple.create(arena, .{165 const builtin = try Tag.pub_var_simple.create(arena, .{
165 .name = decl.name,166 .name = decl.name,
test/behavior/eval.zig+1-1
...@@ -363,7 +363,7 @@ test "comptime modification of const struct field" {...@@ -363,7 +363,7 @@ test "comptime modification of const struct field" {
363}363}
364364
365test "refer to the type of a generic function" {365test "refer to the type of a generic function" {
366 const Func = fn (type) void;366 const Func = fn (comptime type) void;
367 const f: Func = doNothingWithType;367 const f: Func = doNothingWithType;
368 f(i32);368 f(i32);
369}369}
test/behavior/generics.zig+1-1
...@@ -427,7 +427,7 @@ test "generic function passed as comptime argument" {...@@ -427,7 +427,7 @@ test "generic function passed as comptime argument" {
427 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO427 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
428428
429 const S = struct {429 const S = struct {
430 fn doMath(comptime f: fn (type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void {430 fn doMath(comptime f: fn (comptime type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void {
431 const result = try f(i32, a, b);431 const result = try f(i32, a, b);
432 try expect(result == 11);432 try expect(result == 11);
433 }433 }
test/behavior/struct.zig+1-1
...@@ -1511,7 +1511,7 @@ test "if inside struct init inside if" {...@@ -1511,7 +1511,7 @@ test "if inside struct init inside if" {
15111511
1512test "optional generic function label struct field" {1512test "optional generic function label struct field" {
1513 const Options = struct {1513 const Options = struct {
1514 isFoo: ?fn (type) u8 = defaultIsFoo,1514 isFoo: ?fn (comptime type) u8 = defaultIsFoo,
1515 fn defaultIsFoo(comptime _: type) u8 {1515 fn defaultIsFoo(comptime _: type) u8 {
1516 return 123;1516 return 123;
1517 }1517 }
test/behavior/typename.zig+1-1
...@@ -238,7 +238,7 @@ test "comptime parameters not converted to anytype in function type" {...@@ -238,7 +238,7 @@ test "comptime parameters not converted to anytype in function type" {
238 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO238 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
239 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO239 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
240240
241 const T = fn (fn (type) void, void) void;241 const T = fn (comptime fn (comptime type) void, void) void;
242 try expectEqualStrings("fn (comptime fn (comptime type) void, void) void", @typeName(T));242 try expectEqualStrings("fn (comptime fn (comptime type) void, void) void", @typeName(T));
243}243}
244244
test/cases/compile_errors/arg_to_non_comptime_param_with_comptime_only_type_is_not_evaluated_at_comptime.zig created+36
...@@ -0,0 +1,36 @@
1//! Whew, that filename is a bit of a mouthful!
2//! To maximise consistency with other parts of the language, function arguments expressions are
3//! only *evaluated* at comptime if the parameter is declared `comptime`. If the parameter type is
4//! comptime-only, but the parameter is not declared `comptime`, the evaluation happens at runtime,
5//! and the value is just comptime-resolved.
6
7export fn foo() void {
8 // This function is itself generic, with the comptime-only parameter being generic.
9 simpleGeneric(type, if (cond()) u8 else u16);
10}
11
12export fn bar() void {
13 // This function is not generic; once `Wrapper` is called, its parameter type is immediately known.
14 Wrapper(type).inner(if (cond()) u8 else u16);
15}
16
17fn simpleGeneric(comptime T: type, _: T) void {}
18
19fn Wrapper(comptime T: type) type {
20 return struct {
21 fn inner(_: T) void {}
22 };
23}
24
25fn cond() bool {
26 return true;
27}
28
29// error
30//
31// :9:25: error: value with comptime-only type 'type' depends on runtime control flow
32// :9:33: note: runtime control flow here
33// :9:25: note: types are not available at runtime
34// :14:25: error: value with comptime-only type 'type' depends on runtime control flow
35// :14:33: note: runtime control flow here
36// :14:25: note: types are not available at runtime
test/cases/compile_errors/bad_usage_of_call.zig+3-3
...@@ -42,8 +42,8 @@ noinline fn dummy2() void {}...@@ -42,8 +42,8 @@ noinline fn dummy2() void {}
42// :2:23: error: expected a tuple, found 'void'42// :2:23: error: expected a tuple, found 'void'
43// :5:21: error: unable to perform 'never_inline' call at compile-time43// :5:21: error: unable to perform 'never_inline' call at compile-time
44// :8:21: error: unable to perform 'never_tail' call at compile-time44// :8:21: error: unable to perform 'never_tail' call at compile-time
45// :11:5: error: 'never_inline' call of inline function45// :11:5: error: cannot perform inline call with 'never_inline' modifier
46// :15:26: error: modifier 'compile_time' requires a comptime-known function46// :15:26: error: modifier 'compile_time' requires a comptime-known function
47// :18:9: error: 'always_inline' call of noinline function47// :18:9: error: inline call of noinline function
48// :21:9: error: 'always_inline' call of noinline function48// :21:9: error: inline call of noinline function
49// :26:27: error: modifier 'always_inline' requires a comptime-known function49// :26:27: error: modifier 'always_inline' requires a comptime-known function
test/cases/compile_errors/comptime_call_of_function_pointer.zig+2-3
...@@ -4,7 +4,6 @@ export fn entry() void {...@@ -4,7 +4,6 @@ export fn entry() void {
4}4}
55
6// error6// error
7// backend=stage2
8// target=native
9//7//
10// :3:20: error: comptime call of function pointer8// :3:14: error: unable to resolve comptime value
9// :3:14: note: function being called at comptime must be comptime-known
test/cases/compile_errors/condition_comptime_reason_explained.zig+4-2
...@@ -36,11 +36,13 @@ pub export fn entry2() void {...@@ -36,11 +36,13 @@ pub export fn entry2() void {
36//36//
37// :8:9: error: unable to resolve comptime value37// :8:9: error: unable to resolve comptime value
38// :19:15: note: called at comptime from here38// :19:15: note: called at comptime from here
39// :7:13: note: function with comptime-only return type 'tmp.S' is evaluated at comptime39// :19:15: note: call to function with comptime-only return type 'tmp.S' is evaluated at comptime
40// :7:13: note: return type declared here
40// :2:12: note: struct requires comptime because of this field41// :2:12: note: struct requires comptime because of this field
41// :2:12: note: use '*const fn () void' for a function pointer type42// :2:12: note: use '*const fn () void' for a function pointer type
42// :22:13: error: unable to resolve comptime value43// :22:13: error: unable to resolve comptime value
43// :32:19: note: called at comptime from here44// :32:19: note: called at comptime from here
44// :21:17: note: function with comptime-only return type 'tmp.S' is evaluated at comptime45// :32:19: note: call to function with comptime-only return type 'tmp.S' is evaluated at comptime
46// :21:17: note: return type declared here
45// :2:12: note: struct requires comptime because of this field47// :2:12: note: struct requires comptime because of this field
46// :2:12: note: use '*const fn () void' for a function pointer type48// :2:12: note: use '*const fn () void' for a function pointer type
test/cases/compile_errors/dereference_anyopaque.zig+3-50
...@@ -1,54 +1,7 @@...@@ -1,54 +1,7 @@
1const std = @import("std");1export fn foo(ptr: *anyopaque) void {
22 _ = ptr.*;
3const Error = error{Something};
4
5fn next() Error!void {
6 return;
7}
8
9fn parse(comptime T: type, allocator: std.mem.Allocator) !void {
10 parseFree(T, undefined, allocator);
11 _ = (try next()) != null;
12}
13
14fn parseFree(comptime T: type, value: T, allocator: std.mem.Allocator) void {
15 switch (@typeInfo(T)) {
16 .@"struct" => |structInfo| {
17 inline for (structInfo.fields) |field| {
18 if (!field.is_comptime)
19 parseFree(field.type, undefined, allocator);
20 }
21 },
22 .pointer => |ptrInfo| {
23 switch (ptrInfo.size) {
24 .One => {
25 parseFree(ptrInfo.child, value.*, allocator);
26 },
27 .Slice => {
28 for (value) |v|
29 parseFree(ptrInfo.child, v, allocator);
30 },
31 else => unreachable,
32 }
33 },
34 else => unreachable,
35 }
36}
37
38pub export fn entry() void {
39 const allocator = std.testing.failing_allocator;
40 _ = parse(std.StringArrayHashMap(bool), allocator) catch return;
41}3}
424
43// error5// error
44// target=native
45// backend=llvm
46//6//
47// :11:22: error: comparison of 'void' with null7// :2:12: error: cannot load opaque type 'anyopaque'
48// :25:51: error: cannot load opaque type 'anyopaque'
49// :25:51: error: values of type 'fn (*anyopaque, usize, u8, usize) ?[*]u8' must be comptime-known, but operand value is runtime-known
50// :25:51: note: use '*const fn (*anyopaque, usize, u8, usize) ?[*]u8' for a function pointer type
51// :25:51: error: values of type 'fn (*anyopaque, []u8, u8, usize, usize) bool' must be comptime-known, but operand value is runtime-known
52// :25:51: note: use '*const fn (*anyopaque, []u8, u8, usize, usize) bool' for a function pointer type
53// :25:51: error: values of type 'fn (*anyopaque, []u8, u8, usize) void' must be comptime-known, but operand value is runtime-known
54// :25:51: note: use '*const fn (*anyopaque, []u8, u8, usize) void' for a function pointer type
test/cases/compile_errors/explain_why_fn_is_called_at_comptime.zig+2-1
...@@ -15,6 +15,7 @@ pub export fn entry() void {...@@ -15,6 +15,7 @@ pub export fn entry() void {
15// error15// error
16//16//
17// :12:13: error: unable to resolve comptime value17// :12:13: error: unable to resolve comptime value
18// :7:16: note: function with comptime-only return type 'tmp.S' is evaluated at comptime18// :12:12: note: call to function with comptime-only return type 'tmp.S' is evaluated at comptime
19// :7:16: note: return type declared here
19// :2:12: note: struct requires comptime because of this field20// :2:12: note: struct requires comptime because of this field
20// :2:12: note: use '*const fn () void' for a function pointer type21// :2:12: note: use '*const fn () void' for a function pointer type
test/cases/compile_errors/explain_why_generic_fn_is_called_at_comptime.zig+2-1
...@@ -17,6 +17,7 @@ pub export fn entry() void {...@@ -17,6 +17,7 @@ pub export fn entry() void {
17// error17// error
18//18//
19// :15:13: error: unable to resolve comptime value19// :15:13: error: unable to resolve comptime value
20// :9:38: note: generic function instantiated with comptime-only return type 'tmp.S(fn () void)' is evaluated at comptime20// :15:12: note: call to generic function instantiated with comptime-only return type 'tmp.S(fn () void)' is evaluated at comptime
21// :9:38: note: return type declared here
21// :3:16: note: struct requires comptime because of this field22// :3:16: note: struct requires comptime because of this field
22// :3:16: note: use '*const fn () void' for a function pointer type23// :3:16: note: use '*const fn () void' for a function pointer type
test/cases/compile_errors/generic_function_instance_with_non-constant_expression.zig+3-4
...@@ -10,8 +10,7 @@ export fn entry() usize {...@@ -10,8 +10,7 @@ export fn entry() usize {
10}10}
1111
12// error12// error
13// backend=stage2
14// target=native
15//13//
16// :5:16: error: runtime-known argument passed to comptime parameter14// :5:16: error: unable to resolve comptime value
17// :1:17: note: declared comptime here15// :5:16: note: argument to comptime parameter must be comptime-known
16// :1:8: note: parameter declared comptime here
test/cases/compile_errors/generic_function_instantiation_inherits_parent_branch_quota.zig+1-2
...@@ -22,9 +22,8 @@ fn Type(comptime n: usize) type {...@@ -22,9 +22,8 @@ fn Type(comptime n: usize) type {
22}22}
2323
24// error24// error
25// backend=stage2
26// target=native
27//25//
28// :21:16: error: evaluation exceeded 1001 backwards branches26// :21:16: error: evaluation exceeded 1001 backwards branches
29// :21:16: note: use @setEvalBranchQuota() to raise the branch limit from 100127// :21:16: note: use @setEvalBranchQuota() to raise the branch limit from 1001
30// :16:34: note: called from here28// :16:34: note: called from here
29// :8:15: note: called from here
test/cases/compile_errors/generic_instantiation_failure_in_generic_function_return_type.zig+1
...@@ -40,3 +40,4 @@ pub fn is(comptime id: std.builtin.TypeId) TraitFn {...@@ -40,3 +40,4 @@ pub fn is(comptime id: std.builtin.TypeId) TraitFn {
40// target=native40// target=native
41//41//
42// :8:48: error: expected type 'type', found 'bool'42// :8:48: error: expected type 'type', found 'bool'
43// :5:21: note: called from here
test/cases/compile_errors/generic_method_call_with_invalid_param.zig+3-4
...@@ -22,12 +22,11 @@ const S = struct {...@@ -22,12 +22,11 @@ const S = struct {
22};22};
2323
24// error24// error
25// backend=stage2
26// target=native
27//25//
28// :3:18: error: expected type 'bool', found 'void'26// :3:18: error: expected type 'bool', found 'void'
29// :19:43: note: parameter type declared here27// :19:43: note: parameter type declared here
30// :8:18: error: expected type 'void', found 'bool'28// :8:18: error: expected type 'void', found 'bool'
31// :20:43: note: parameter type declared here29// :20:43: note: parameter type declared here
32// :15:26: error: runtime-known argument passed to comptime parameter30// :15:26: error: unable to resolve comptime value
33// :21:57: note: declared comptime here31// :15:26: note: argument to comptime parameter must be comptime-known
32// :21:48: note: parameter declared comptime here
test/cases/compile_errors/global_variable_initializer_must_be_constant_expression.zig-2
...@@ -5,7 +5,5 @@ export fn entry() i32 {...@@ -5,7 +5,5 @@ export fn entry() i32 {
5}5}
66
7// error7// error
8// backend=stage2
9// target=native
10//8//
11// :2:14: error: comptime call of extern function9// :2:14: error: comptime call of extern function
test/cases/compile_errors/inline_call_runtime_value_to_comptime_param.zig+1-2
...@@ -10,8 +10,7 @@ pub export fn entry() void {...@@ -10,8 +10,7 @@ pub export fn entry() void {
10}10}
1111
12// error12// error
13// backend=stage2
14// target=native
15//13//
16// :5:18: error: unable to resolve comptime value14// :5:18: error: unable to resolve comptime value
17// :5:18: note: argument to comptime parameter must be comptime-known15// :5:18: note: argument to comptime parameter must be comptime-known
16// :1:24: note: parameter declared comptime here
test/cases/compile_errors/invalid_extern_function_call.zig+2-4
...@@ -9,8 +9,6 @@ export fn entry1() void {...@@ -9,8 +9,6 @@ export fn entry1() void {
9}9}
1010
11// error11// error
12// backend=stage2
13// target=native
14//12//
15// :4:15: error: comptime call of extern function pointer13// :4:15: error: comptime call of extern function
16// :8:5: error: inline call of extern function pointer14// :8:5: error: inline call of extern function
test/cases/compile_errors/invalid_pointer_for_var_type.zig-2
...@@ -7,7 +7,5 @@ export fn f() void {...@@ -7,7 +7,5 @@ export fn f() void {
7}7}
88
9// error9// error
10// backend=stage2
11// target=native
12//10//
13// :2:16: error: comptime call of extern function11// :2:16: error: comptime call of extern function
test/cases/compile_errors/nested_generic_function_param_type_mismatch.zig+2-2
...@@ -19,6 +19,6 @@ pub export fn entry() void {...@@ -19,6 +19,6 @@ pub export fn entry() void {
19// backend=llvm19// backend=llvm
20// target=native20// target=native
21//21//
22// :15:28: error: expected type '*const fn (comptime type, u8, u8) u32', found '*const fn (void, u8, u8) u32'22// :15:28: error: expected type '*const fn (type, u8, u8) u32', found '*const fn (void, u8, u8) u32'
23// :15:28: note: pointer type child 'fn (void, u8, u8) u32' cannot cast into pointer type child 'fn (comptime type, u8, u8) u32'23// :15:28: note: pointer type child 'fn (void, u8, u8) u32' cannot cast into pointer type child 'fn (type, u8, u8) u32'
24// :15:28: note: non-generic function cannot cast into a generic function24// :15:28: note: non-generic function cannot cast into a generic function
test/cases/compile_errors/never_inline_call_of_inline_fn_with_comptime_param.zig+2-2
...@@ -19,5 +19,5 @@ export fn entry2() void {...@@ -19,5 +19,5 @@ export fn entry2() void {
1919
20// error20// error
21//21//
22// :14:5: error: 'never_inline' call of inline function22// :14:5: error: cannot perform inline call with 'never_inline' modifier
23// :17:5: error: 'never_inline' call of inline function23// :17:5: error: cannot perform inline call with 'never_inline' modifier
test/cases/compile_errors/non-const_expression_in_struct_literal_outside_function.zig-2
...@@ -9,7 +9,5 @@ export fn entry() usize {...@@ -9,7 +9,5 @@ export fn entry() usize {
9}9}
1010
11// error11// error
12// backend=stage2
13// target=native
14//12//
15// :4:27: error: comptime call of extern function13// :4:27: error: comptime call of extern function
test/cases/compile_errors/non_comptime_param_in_comptime_function.zig+3-2
...@@ -11,5 +11,6 @@ export fn entry() void {...@@ -11,5 +11,6 @@ export fn entry() void {
11// error11// error
12//12//
13// :8:11: error: unable to resolve comptime value13// :8:11: error: unable to resolve comptime value
14// :1:20: note: function with comptime-only return type 'type' is evaluated at comptime14// :8:10: note: call to function with comptime-only return type 'type' is evaluated at comptime
15// :1:20: note: types are not available at runtime15// :1:20: note: return type declared here
16// :8:10: note: types are not available at runtime
test/cases/compile_errors/recursive_inline_fn.zig+4-2
...@@ -29,8 +29,10 @@ pub export fn entry2() void {...@@ -29,8 +29,10 @@ pub export fn entry2() void {
29}29}
3030
31// error31// error
32// backend=stage2
33// target=native
34//32//
35// :5:27: error: inline call is recursive33// :5:27: error: inline call is recursive
34// :12:12: note: called from here
36// :24:10: error: inline call is recursive35// :24:10: error: inline call is recursive
36// :20:10: note: called from here
37// :16:11: note: called from here
38// :28:10: note: called from here
test/cases/compile_errors/runtime_operation_in_comptime_scope.zig+3-2
...@@ -27,8 +27,9 @@ var rt: u32 = undefined;...@@ -27,8 +27,9 @@ var rt: u32 = undefined;
27// :19:5: note: operation is runtime due to this operand27// :19:5: note: operation is runtime due to this operand
28// :14:8: note: called at comptime from here28// :14:8: note: called at comptime from here
29// :10:12: note: called at comptime from here29// :10:12: note: called at comptime from here
30// :13:10: note: function with comptime-only return type 'type' is evaluated at comptime30// :10:12: note: call to function with comptime-only return type 'type' is evaluated at comptime
31// :13:10: note: types are not available at runtime31// :13:10: note: return type declared here
32// :10:12: note: types are not available at runtime
32// :2:8: note: called from here33// :2:8: note: called from here
33// :19:8: error: unable to evaluate comptime expression34// :19:8: error: unable to evaluate comptime expression
34// :19:5: note: operation is runtime due to this operand35// :19:5: note: operation is runtime due to this operand
test/compile_errors.zig+9-6
...@@ -57,8 +57,9 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void {...@@ -57,8 +57,9 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void {
57 \\}57 \\}
58 , &[_][]const u8{58 , &[_][]const u8{
59 ":3:12: error: unable to resolve comptime value",59 ":3:12: error: unable to resolve comptime value",
60 ":2:55: note: generic function instantiated with comptime-only return type '?fn () void' is evaluated at comptime",60 ":3:19: note: call to generic function instantiated with comptime-only return type '?fn () void' is evaluated at comptime",
61 ":2:55: note: use '*const fn () void' for a function pointer type",61 ":2:55: note: return type declared here",
62 ":3:19: note: use '*const fn () void' for a function pointer type",
62 });63 });
63 case.addSourceFile("b.zig",64 case.addSourceFile("b.zig",
64 \\pub const ElfDynLib = struct {65 \\pub const ElfDynLib = struct {
...@@ -193,10 +194,12 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void {...@@ -193,10 +194,12 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void {
193 \\ import.anytypeFunction(S{ .x = x, .y = u32 });194 \\ import.anytypeFunction(S{ .x = x, .y = u32 });
194 \\}195 \\}
195 , &[_][]const u8{196 , &[_][]const u8{
196 ":4:33: error: runtime-known argument passed to comptime parameter",197 ":4:33: error: unable to resolve comptime value",
197 ":1:38: note: declared comptime here",198 ":4:33: note: argument to comptime parameter must be comptime-known",
198 ":8:36: error: runtime-known argument passed to comptime parameter",199 ":1:29: note: parameter declared comptime here",
199 ":2:41: note: declared comptime here",200 ":8:36: error: unable to resolve comptime value",
201 ":8:36: note: argument to comptime parameter must be comptime-known",
202 ":2:32: note: parameter declared comptime here",
200 ":13:32: error: unable to resolve comptime value",203 ":13:32: error: unable to resolve comptime value",
201 ":13:32: note: initializer of comptime-only struct 'tmp.callAnytypeFunctionWithRuntimeComptimeOnlyType.S' must be comptime-known",204 ":13:32: note: initializer of comptime-only struct 'tmp.callAnytypeFunctionWithRuntimeComptimeOnlyType.S' must be comptime-known",
202 ":12:35: note: struct requires comptime because of this field",205 ":12:35: note: struct requires comptime because of this field",
test/standalone/simple/std_enums_big_enums.zig+1
...@@ -31,6 +31,7 @@ pub fn main() void {...@@ -31,6 +31,7 @@ pub fn main() void {
31 var bounded_multiset = std.enums.BoundedEnumMultiset(big.Big, u8).init(.{});31 var bounded_multiset = std.enums.BoundedEnumMultiset(big.Big, u8).init(.{});
32 _ = &bounded_multiset;32 _ = &bounded_multiset;
3333
34 @setEvalBranchQuota(3000);
34 var array = std.enums.EnumArray(big.Big, u8).init(undefined);35 var array = std.enums.EnumArray(big.Big, u8).init(undefined);
35 array = std.enums.EnumArray(big.Big, u8).initDefault(123, .{});36 array = std.enums.EnumArray(big.Big, u8).initDefault(123, .{});
36}37}