| ... | @@ -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 the | 46 | /// 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. |
| 48 | comptime_break_inst: Zir.Inst.Index = undefined, | 48 | comptime_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`. | | |
| 55 | comptime_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`. | | |
| 58 | generic_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. | | |
| 63 | generic_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, because | 50 | /// 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 means | 51 | /// 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 | }, |
| 870 | | 852 | |
| | 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) { |
| 7423 | | 7437 | |
| 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 generic | 7440 | /// `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 type | 7496 | // 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); |
| 7474 | | 7501 | |
| | 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 should | 7507 | // 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 | }; |
| 7509 | | 7540 | |
| 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. | | |
| 7516 | const 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 | | | |
| 7604 | fn analyzeCall( | 7541 | fn 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; |
| 7620 | | 7569 | |
| 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 | } |
| 7645 | | 7586 | |
| 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())) { |
| 7652 | | 7593 | .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())) { |
| 7656 | | 7597 | .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 }; |
| 7659 | | 7605 | |
| 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; | | |
| 7668 | | 7609 | |
| 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; | | |
| 7673 | | 7611 | |
| 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 = .{ |
| 7698 | | 7624 | .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 | } |
| 7746 | | 7637 | |
| 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 again | 7639 | 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; |
| 7750 | | 7666 | |
| 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 | } |
| 7754 | | 7701 | |
| 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; |
| 7759 | | 7713 | |
| 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 | } | | |
| 7791 | | 7717 | |
| 7792 | // Analyze the ZIR. The same ZIR gets analyzed into a runtime function | 7718 | generic_block.comptime_reason = .{ .reason = .{ |
| 7793 | // or an inlined call depending on what union tag the `label` field is | 7719 | .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 the | 7721 | } }; |
| 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 | }; | | |
| 7818 | | 7722 | |
| 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); |
| 7820 | | 7725 | |
| 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 | } |
| 7823 | | 7732 | |
| 7824 | // This is not a function instance, so the function's `Nav` has analysis | 7733 | 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); | | |
| 7827 | | 7735 | |
| 7828 | // We effectively want a child Sema here, but can't literally do that, because we need AIR | 7736 | 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 in | 7737 | const arg_ty = sema.typeOf(arg.*); |
| 7830 | // scope, we should use its `caller`/`callee` methods rather than using `sema` directly | 7738 | 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 | } |
| 7839 | | 7771 | |
| 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 | }; | | |
| 7857 | | 7779 | |
| 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; |
| 7859 | | 7783 | |
| 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); | | |
| 7862 | | 7785 | |
| 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`. |
| 7864 | | 7787 | |
| 7865 | // Whether this call should be memoized, set to false if the call can | 7788 | 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 | }; | | |
| 7887 | | 7789 | |
| 7888 | // This will have return instructions analyzed as break instructions to | 7790 | 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 to | 7792 | defer { |
| 7891 | // the AIR instructions of the callsite. The callee could be a generic function | 7793 | generic_inst_map = sema.inst_map; |
| 7892 | // which means its parameter type expressions must be resolved in order and used | 7794 | 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; |
| 7918 | | 7799 | |
| 7919 | // From here, we only really need to use the callee Sema. Make it the active one, then we | 7800 | 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 | } }; |
| 7922 | | 7804 | |
| 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 | } |
| 7933 | | 7827 | |
| 7934 | // In case it is a generic function with an expression for the return type that depends | 7828 | break :ret_ty full_ty; |
| 7935 | // on parameters, we must now do the same for the return type as we just did with | 7829 | }; |
| 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 | } | | |
| 7959 | | 7830 | |
| 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+eql | 7838 | .comptime_only_ret_ty = .{ |
| 7968 | .branch_count = undefined, // ignored by hash+eql | 7839 | .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 | } | | |
| 7980 | | 7847 | |
| 7981 | // Since we're doing an inline call, we depend on the source code of the whole | 7848 | if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); |
| 7982 | // function declaration. | | |
| 7983 | try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index }); | | |
| 7984 | | 7849 | |
| 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).?; | | |
| 8001 | | 7851 | |
| 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 }; |
| 8007 | | 7867 | |
| 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 | } | | |
| 8011 | | 7869 | |
| 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 function | 7871 | 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 | } | | |
| 8019 | | 7874 | |
| 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; | | |
| 8026 | | 7876 | |
| 8027 | // Store the current eval branch count so we can find out how many eval branches | 7877 | var noalias_bits: u32 = 0; |
| 8028 | // the comptime call caused. | | |
| 8029 | const old_branch_count = sema.branch_count; | | |
| 8030 | | 7878 | |
| 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 | }; | | |
| 8038 | | 7881 | |
| 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)) { |
| 8042 | | 7885 | 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 | } |
| 8045 | | 7888 | break :c try arg_ty.comptimeOnlySema(pt); |
| 8046 | // If the result can mutate comptime vars, we must not memoize it, as it contains | 7889 | }; |
| 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 the | 7891 | |
| 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 | } |
| 8058 | | 7905 | |
| 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; |
| 8061 | | 7909 | |
| 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 | }); |
| 8066 | | 7920 | |
| 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 possible | 7923 | // 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 | } | | |
| 8073 | | 7925 | |
| 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); | | |
| 8077 | | 7928 | |
| 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 resolved | 7931 | 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 | } |
| 8091 | | 7935 | |
| 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 | } |
| 8100 | | 7942 | |
| 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 | } | | |
| 8107 | | 7948 | |
| 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 | } |
| 8120 | | 7970 | |
| 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 | }; | | |
| 8152 | | 7988 | |
| 8153 | if (ensure_result_used) { | 7989 | return result; |
| 8154 | try sema.ensureResultUsed(block, sema.typeOf(result), call_src); | | |
| 8155 | } | 7990 | } |
| 8156 | return result; | | |
| 8157 | } | | |
| 8158 | | 7991 | |
| 8159 | fn 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). | | |
| 8180 | fn 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 | } | | |
| 8230 | | 8005 | |
| 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 unresolvable | 8011 | 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 | } | | |
| 8290 | | 8016 | |
| 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 | } |
| 8294 | | 8023 | } |
| 8295 | arg_i.* += 1; | | |
| 8296 | }, | | |
| 8297 | else => {}, | | |
| 8298 | } | 8024 | } |
| 8299 | | 8025 | |
| 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 | | | |
| 8303 | fn 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); | | |
| 8324 | | 8028 | |
| 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)).?; | | |
| 8332 | | 8030 | |
| 8333 | try sema.declareDependency(.{ .src_hash = generic_owner_func.zir_body_inst }); | 8031 | const want_memoize = m: { |
| 8334 | | 8032 | // TODO: comptime call memoization is currently not supported under incremental compilation |
| 8335 | // Even though there may already be a generic instantiation corresponding | 8033 | // 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 generic | 8034 | // 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 the | 8036 | 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` to | 8038 | const val = (try sema.resolveValue(a)).?; |
| 8341 | // `InternPool`. | 8039 | if (val.canMutateComptimeVarState(zcu)) break :m false; |
| 8342 | | 8040 | } |
| 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 | } |
| 8347 | | 8070 | |
| 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); | | |
| 8350 | | 8072 | |
| 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 | }); |
| 8354 | | 8108 | |
| 8355 | // Re-run the block that creates the function, with the comptime parameters | 8109 | var inlining: Block.Inlining = .{ |
| 8356 | // pre-populated inside `inst_map`. This causes `param_comptime` and | 8110 | .call_block = block, |
| 8357 | // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a | 8111 | .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 the | 8119 | .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 needed | 8130 | .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)]; | | |
| 8399 | | 8139 | |
| 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 resolved | 8141 | 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 | } | | |
| 8432 | | 8142 | |
| 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 | } |
| 8452 | | 8152 | |
| 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 | } |
| 8529 | | 8171 | |
| 8530 | // We've already handled parameters, so don't resolve the whole body. Instead, just | 8172 | 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(); | | |
| 8538 | | 8178 | |
| 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; |
| 8541 | | 8185 | |
| 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; |
| 8545 | | 8189 | |
| 8546 | // If the call evaluated to a return type that requires comptime, never mind | 8190 | 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 instead | 8196 | }; |
| 8553 | // call it inline. | | |
| 8554 | if (func_ty_info.is_generic or func_ty_info.cc == .@"inline") { | | |
| 8555 | return error.GenericPoison; | | |
| 8556 | } | | |
| 8557 | | 8197 | |
| 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 | }; |
| 8559 | | 8208 | |
| 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 | } |
| 8566 | | 8220 | |
| 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 | |
| | 8228 | fn 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 | } |
| 8597 | | 8247 | |
| 8598 | fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 8248 | fn 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 defaults | 9226 | // 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 | } |
| 9650 | | 9292 | |
| 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); |
| 9913 | | 9555 | |
| 9914 | var is_generic = bare_return_type.isGenericPoison(); | 9556 | if (bare_return_type.isGenericPoison() and sema.no_partial_func_ty) return error.GenericPoison; |
| 9915 | | 9557 | |
| 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; | | |
| 9924 | | 9560 | |
| 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 error | 9581 | 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 and | 9623 | 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 | } |
| 10009 | | 9650 | |
| 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; | | |
| 10013 | | 9659 | |
| 10014 | const param_types = block.params.items(.ty); | 9660 | const param_types = block.params.items(.ty); |
| 10015 | | 9661 | |
| 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, |
| 10067 | | 9677 | |
| 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 | } |
| 10092 | | 9700 | |
| ... | @@ -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 | }); |
| 10103 | | 9711 | |
| ... | @@ -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 | } |
| 10134 | | 9740 | |
| ... | @@ -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 | } |
| 10153 | | 9757 | |
| ... | @@ -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( |
| 10203 | | 9805 | |
| 10204 | // If the return type is comptime-only but not dependent on parameters then | 9806 | // 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 | } |
| 10302 | | 9904 | |
| 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 can | 9906 | // 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 | } |
| 10343 | | 9938 | |
| 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]); |
| 31070 | | 30661 | |
| 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, |