| ... | @@ -335,6 +335,7 @@ pub const Block = struct { | ... | @@ -335,6 +335,7 @@ pub const Block = struct { |
| 335 | /// It is shared among all the blocks in an inline or comptime called | 335 | /// It is shared among all the blocks in an inline or comptime called |
| 336 | /// function. | 336 | /// function. |
| 337 | pub const Inlining = struct { | 337 | pub const Inlining = struct { |
| | 338 | func: ?*Module.Fn, |
| 338 | comptime_result: Air.Inst.Ref, | 339 | comptime_result: Air.Inst.Ref, |
| 339 | merges: Merges, | 340 | merges: Merges, |
| 340 | }; | 341 | }; |
| ... | @@ -6428,7 +6429,6 @@ fn analyzeCall( | ... | @@ -6428,7 +6429,6 @@ fn analyzeCall( |
| 6428 | }), | 6429 | }), |
| 6429 | else => unreachable, | 6430 | else => unreachable, |
| 6430 | }; | 6431 | }; |
| 6431 | if (!is_comptime_call and module_fn.state == .sema_failure) return error.AnalysisFail; | | |
| 6432 | if (func_ty_info.is_var_args) { | 6432 | if (func_ty_info.is_var_args) { |
| 6433 | return sema.fail(block, call_src, "{s} call of variadic function", .{ | 6433 | return sema.fail(block, call_src, "{s} call of variadic function", .{ |
| 6434 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), | 6434 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), |
| ... | @@ -6448,6 +6448,7 @@ fn analyzeCall( | ... | @@ -6448,6 +6448,7 @@ fn analyzeCall( |
| 6448 | // This one is shared among sub-blocks within the same callee, but not | 6448 | // This one is shared among sub-blocks within the same callee, but not |
| 6449 | // shared among the entire inline/comptime call stack. | 6449 | // shared among the entire inline/comptime call stack. |
| 6450 | var inlining: Block.Inlining = .{ | 6450 | var inlining: Block.Inlining = .{ |
| | 6451 | .func = null, |
| 6451 | .comptime_result = undefined, | 6452 | .comptime_result = undefined, |
| 6452 | .merges = .{ | 6453 | .merges = .{ |
| 6453 | .results = .{}, | 6454 | .results = .{}, |
| ... | @@ -6534,6 +6535,7 @@ fn analyzeCall( | ... | @@ -6534,6 +6535,7 @@ fn analyzeCall( |
| 6534 | const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst); | 6535 | const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst); |
| 6535 | try sema.inst_map.ensureSpaceForInstructions(sema.gpa, fn_info.param_body); | 6536 | try sema.inst_map.ensureSpaceForInstructions(sema.gpa, fn_info.param_body); |
| 6536 | | 6537 | |
| | 6538 | var has_comptime_args = false; |
| 6537 | var arg_i: usize = 0; | 6539 | var arg_i: usize = 0; |
| 6538 | for (fn_info.param_body) |inst| { | 6540 | for (fn_info.param_body) |inst| { |
| 6539 | sema.analyzeInlineCallArg( | 6541 | sema.analyzeInlineCallArg( |
| ... | @@ -6549,6 +6551,7 @@ fn analyzeCall( | ... | @@ -6549,6 +6551,7 @@ fn analyzeCall( |
| 6549 | memoized_call_key, | 6551 | memoized_call_key, |
| 6550 | func_ty_info.param_types, | 6552 | func_ty_info.param_types, |
| 6551 | func, | 6553 | func, |
| | 6554 | &has_comptime_args, |
| 6552 | ) catch |err| switch (err) { | 6555 | ) catch |err| switch (err) { |
| 6553 | error.NeededSourceLocation => { | 6556 | error.NeededSourceLocation => { |
| 6554 | _ = sema.inst_map.remove(inst); | 6557 | _ = sema.inst_map.remove(inst); |
| ... | @@ -6566,6 +6569,7 @@ fn analyzeCall( | ... | @@ -6566,6 +6569,7 @@ fn analyzeCall( |
| 6566 | memoized_call_key, | 6569 | memoized_call_key, |
| 6567 | func_ty_info.param_types, | 6570 | func_ty_info.param_types, |
| 6568 | func, | 6571 | func, |
| | 6572 | &has_comptime_args, |
| 6569 | ); | 6573 | ); |
| 6570 | unreachable; | 6574 | unreachable; |
| 6571 | }, | 6575 | }, |
| ... | @@ -6573,6 +6577,19 @@ fn analyzeCall( | ... | @@ -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 | // In case it is a generic function with an expression for the return type that depends | 6593 | // In case it is a generic function with an expression for the return type that depends |
| 6577 | // on parameters, we must now do the same for the return type as we just did with | 6594 | // on parameters, we must now do the same for the return type as we just did with |
| 6578 | // each of the parameters, resolving the return type and providing it to the child | 6595 | // each of the parameters, resolving the return type and providing it to the child |
| ... | @@ -6657,6 +6674,7 @@ fn analyzeCall( | ... | @@ -6657,6 +6674,7 @@ fn analyzeCall( |
| 6657 | error.ComptimeReturn => break :result inlining.comptime_result, | 6674 | error.ComptimeReturn => break :result inlining.comptime_result, |
| 6658 | error.AnalysisFail => { | 6675 | error.AnalysisFail => { |
| 6659 | const err_msg = sema.err orelse return err; | 6676 | const err_msg = sema.err orelse return err; |
| | 6677 | if (std.mem.eql(u8, err_msg.msg, recursive_msg)) return err; |
| 6660 | try sema.errNote(block, call_src, err_msg, "called from here", .{}); | 6678 | try sema.errNote(block, call_src, err_msg, "called from here", .{}); |
| 6661 | err_msg.clearTrace(sema.gpa); | 6679 | err_msg.clearTrace(sema.gpa); |
| 6662 | return err; | 6680 | return err; |
| ... | @@ -6814,8 +6832,13 @@ fn analyzeInlineCallArg( | ... | @@ -6814,8 +6832,13 @@ fn analyzeInlineCallArg( |
| 6814 | memoized_call_key: Module.MemoizedCall.Key, | 6832 | memoized_call_key: Module.MemoizedCall.Key, |
| 6815 | raw_param_types: []const Type, | 6833 | raw_param_types: []const Type, |
| 6816 | func_inst: Air.Inst.Ref, | 6834 | func_inst: Air.Inst.Ref, |
| | 6835 | has_comptime_args: *bool, |
| 6817 | ) !void { | 6836 | ) !void { |
| 6818 | const zir_tags = sema.code.instructions.items(.tag); | 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 | switch (zir_tags[inst]) { | 6842 | switch (zir_tags[inst]) { |
| 6820 | .param, .param_comptime => { | 6843 | .param, .param_comptime => { |
| 6821 | // Evaluate the parameter type expression now that previous ones have | 6844 | // Evaluate the parameter type expression now that previous ones have |
| ... | @@ -6870,23 +6893,20 @@ fn analyzeInlineCallArg( | ... | @@ -6870,23 +6893,20 @@ fn analyzeInlineCallArg( |
| 6870 | .ty = param_ty, | 6893 | .ty = param_ty, |
| 6871 | .val = arg_val, | 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 | } else { | 6896 | } else { |
| 6880 | sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg); | 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 | arg_i.* += 1; | 6904 | arg_i.* += 1; |
| 6884 | }, | 6905 | }, |
| 6885 | .param_anytype, .param_anytype_comptime => { | 6906 | .param_anytype, .param_anytype_comptime => { |
| 6886 | // No coercion needed. | 6907 | // No coercion needed. |
| 6887 | const uncasted_arg = uncasted_args[arg_i.*]; | 6908 | const uncasted_arg = uncasted_args[arg_i.*]; |
| 6888 | new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg); | 6909 | new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg); |
| 6889 | const param_ty = sema.typeOf(uncasted_arg); | | |
| 6890 | | 6910 | |
| 6891 | if (is_comptime_call) { | 6911 | if (is_comptime_call) { |
| 6892 | sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); | 6912 | sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); |
| ... | @@ -6912,16 +6932,14 @@ fn analyzeInlineCallArg( | ... | @@ -6912,16 +6932,14 @@ fn analyzeInlineCallArg( |
| 6912 | .ty = sema.typeOf(uncasted_arg), | 6932 | .ty = sema.typeOf(uncasted_arg), |
| 6913 | .val = arg_val, | 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 | } else { | 6935 | } else { |
| 6922 | sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); | 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 | arg_i.* += 1; | 6943 | arg_i.* += 1; |
| 6926 | }, | 6944 | }, |
| 6927 | else => {}, | 6945 | else => {}, |