| ... | ... | @@ -335,6 +335,7 @@ pub const Block = struct { |
| 335 | 335 | /// It is shared among all the blocks in an inline or comptime called |
| 336 | 336 | /// function. |
| 337 | 337 | pub const Inlining = struct { |
| 338 | func: ?*Module.Fn, |
| 338 | 339 | comptime_result: Air.Inst.Ref, |
| 339 | 340 | merges: Merges, |
| 340 | 341 | }; |
| ... | ... | @@ -6428,7 +6429,6 @@ fn analyzeCall( |
| 6428 | 6429 | }), |
| 6429 | 6430 | else => unreachable, |
| 6430 | 6431 | }; |
| 6431 | | if (!is_comptime_call and module_fn.state == .sema_failure) return error.AnalysisFail; |
| 6432 | 6432 | if (func_ty_info.is_var_args) { |
| 6433 | 6433 | return sema.fail(block, call_src, "{s} call of variadic function", .{ |
| 6434 | 6434 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), |
| ... | ... | @@ -6448,6 +6448,7 @@ fn analyzeCall( |
| 6448 | 6448 | // This one is shared among sub-blocks within the same callee, but not |
| 6449 | 6449 | // shared among the entire inline/comptime call stack. |
| 6450 | 6450 | var inlining: Block.Inlining = .{ |
| 6451 | .func = null, |
| 6451 | 6452 | .comptime_result = undefined, |
| 6452 | 6453 | .merges = .{ |
| 6453 | 6454 | .results = .{}, |
| ... | ... | @@ -6534,6 +6535,7 @@ fn analyzeCall( |
| 6534 | 6535 | const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst); |
| 6535 | 6536 | try sema.inst_map.ensureSpaceForInstructions(sema.gpa, fn_info.param_body); |
| 6536 | 6537 | |
| 6538 | var has_comptime_args = false; |
| 6537 | 6539 | var arg_i: usize = 0; |
| 6538 | 6540 | for (fn_info.param_body) |inst| { |
| 6539 | 6541 | sema.analyzeInlineCallArg( |
| ... | ... | @@ -6549,6 +6551,7 @@ fn analyzeCall( |
| 6549 | 6551 | memoized_call_key, |
| 6550 | 6552 | func_ty_info.param_types, |
| 6551 | 6553 | func, |
| 6554 | &has_comptime_args, |
| 6552 | 6555 | ) catch |err| switch (err) { |
| 6553 | 6556 | error.NeededSourceLocation => { |
| 6554 | 6557 | _ = sema.inst_map.remove(inst); |
| ... | ... | @@ -6566,6 +6569,7 @@ fn analyzeCall( |
| 6566 | 6569 | memoized_call_key, |
| 6567 | 6570 | func_ty_info.param_types, |
| 6568 | 6571 | func, |
| 6572 | &has_comptime_args, |
| 6569 | 6573 | ); |
| 6570 | 6574 | unreachable; |
| 6571 | 6575 | }, |
| ... | ... | @@ -6573,6 +6577,19 @@ fn analyzeCall( |
| 6573 | 6577 | }; |
| 6574 | 6578 | } |
| 6575 | 6579 | |
| 6580 | if (!has_comptime_args and module_fn.state == .sema_failure) return error.AnalysisFail; |
| 6581 | |
| 6582 | const recursive_msg = "inline call is recursive"; |
| 6583 | var head = if (!has_comptime_args) block else null; |
| 6584 | while (head) |some| { |
| 6585 | const parent_inlining = some.inlining orelse break; |
| 6586 | if (parent_inlining.func == module_fn) { |
| 6587 | return sema.fail(block, call_src, recursive_msg, .{}); |
| 6588 | } |
| 6589 | head = some.parent; |
| 6590 | } |
| 6591 | if (!has_comptime_args) inlining.func = module_fn; |
| 6592 | |
| 6576 | 6593 | // In case it is a generic function with an expression for the return type that depends |
| 6577 | 6594 | // on parameters, we must now do the same for the return type as we just did with |
| 6578 | 6595 | // each of the parameters, resolving the return type and providing it to the child |
| ... | ... | @@ -6657,6 +6674,7 @@ fn analyzeCall( |
| 6657 | 6674 | error.ComptimeReturn => break :result inlining.comptime_result, |
| 6658 | 6675 | error.AnalysisFail => { |
| 6659 | 6676 | const err_msg = sema.err orelse return err; |
| 6677 | if (std.mem.eql(u8, err_msg.msg, recursive_msg)) return err; |
| 6660 | 6678 | try sema.errNote(block, call_src, err_msg, "called from here", .{}); |
| 6661 | 6679 | err_msg.clearTrace(sema.gpa); |
| 6662 | 6680 | return err; |
| ... | ... | @@ -6814,8 +6832,13 @@ fn analyzeInlineCallArg( |
| 6814 | 6832 | memoized_call_key: Module.MemoizedCall.Key, |
| 6815 | 6833 | raw_param_types: []const Type, |
| 6816 | 6834 | func_inst: Air.Inst.Ref, |
| 6835 | has_comptime_args: *bool, |
| 6817 | 6836 | ) !void { |
| 6818 | 6837 | const zir_tags = sema.code.instructions.items(.tag); |
| 6838 | switch (zir_tags[inst]) { |
| 6839 | .param_comptime, .param_anytype_comptime => has_comptime_args.* = true, |
| 6840 | else => {}, |
| 6841 | } |
| 6819 | 6842 | switch (zir_tags[inst]) { |
| 6820 | 6843 | .param, .param_comptime => { |
| 6821 | 6844 | // Evaluate the parameter type expression now that previous ones have |
| ... | ... | @@ -6870,23 +6893,20 @@ fn analyzeInlineCallArg( |
| 6870 | 6893 | .ty = param_ty, |
| 6871 | 6894 | .val = arg_val, |
| 6872 | 6895 | }; |
| 6873 | | } else if (zir_tags[inst] == .param_comptime or try sema.typeRequiresComptime(param_ty)) { |
| 6874 | | sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg); |
| 6875 | | } else if (try sema.resolveMaybeUndefVal(casted_arg)) |val| { |
| 6876 | | // We have a comptime value but we need a runtime value to preserve inlining semantics, |
| 6877 | | const wrapped = try sema.addConstant(param_ty, try Value.Tag.runtime_value.create(sema.arena, val)); |
| 6878 | | sema.inst_map.putAssumeCapacityNoClobber(inst, wrapped); |
| 6879 | 6896 | } else { |
| 6880 | 6897 | sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg); |
| 6881 | 6898 | } |
| 6882 | 6899 | |
| 6900 | if (try sema.resolveMaybeUndefVal(casted_arg)) |_| { |
| 6901 | has_comptime_args.* = true; |
| 6902 | } |
| 6903 | |
| 6883 | 6904 | arg_i.* += 1; |
| 6884 | 6905 | }, |
| 6885 | 6906 | .param_anytype, .param_anytype_comptime => { |
| 6886 | 6907 | // No coercion needed. |
| 6887 | 6908 | const uncasted_arg = uncasted_args[arg_i.*]; |
| 6888 | 6909 | new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg); |
| 6889 | | const param_ty = sema.typeOf(uncasted_arg); |
| 6890 | 6910 | |
| 6891 | 6911 | if (is_comptime_call) { |
| 6892 | 6912 | sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); |
| ... | ... | @@ -6912,16 +6932,14 @@ fn analyzeInlineCallArg( |
| 6912 | 6932 | .ty = sema.typeOf(uncasted_arg), |
| 6913 | 6933 | .val = arg_val, |
| 6914 | 6934 | }; |
| 6915 | | } else if (zir_tags[inst] == .param_anytype_comptime or try sema.typeRequiresComptime(param_ty)) { |
| 6916 | | sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); |
| 6917 | | } else if (try sema.resolveMaybeUndefVal(uncasted_arg)) |val| { |
| 6918 | | // We have a comptime value but we need a runtime value to preserve inlining semantics, |
| 6919 | | const wrapped = try sema.addConstant(param_ty, try Value.Tag.runtime_value.create(sema.arena, val)); |
| 6920 | | sema.inst_map.putAssumeCapacityNoClobber(inst, wrapped); |
| 6921 | 6935 | } else { |
| 6922 | 6936 | sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); |
| 6923 | 6937 | } |
| 6924 | 6938 | |
| 6939 | if (try sema.resolveMaybeUndefVal(uncasted_arg)) |_| { |
| 6940 | has_comptime_args.* = true; |
| 6941 | } |
| 6942 | |
| 6925 | 6943 | arg_i.* += 1; |
| 6926 | 6944 | }, |
| 6927 | 6945 | else => {}, |