| ... | @@ -6152,9 +6152,23 @@ fn analyzeCall( | ... | @@ -6152,9 +6152,23 @@ fn analyzeCall( |
| 6152 | if (ensure_result_used) { | 6152 | if (ensure_result_used) { |
| 6153 | try sema.ensureResultUsed(block, result, call_src); | 6153 | try sema.ensureResultUsed(block, result, call_src); |
| 6154 | } | 6154 | } |
| | 6155 | if (call_tag == .call_always_tail) { |
| | 6156 | return sema.handleTailCall(block, call_src, func_ty, result); |
| | 6157 | } |
| 6155 | return result; | 6158 | return result; |
| 6156 | } | 6159 | } |
| 6157 | | 6160 | |
| | 6161 | fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref { |
| | 6162 | const func_decl = sema.mod.declPtr(sema.owner_func.?.owner_decl); |
| | 6163 | if (!func_ty.eql(func_decl.ty, sema.mod)) { |
| | 6164 | return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{ |
| | 6165 | func_ty.fmt(sema.mod), func_decl.ty.fmt(sema.mod), |
| | 6166 | }); |
| | 6167 | } |
| | 6168 | _ = try block.addUnOp(.ret, result); |
| | 6169 | return Air.Inst.Ref.unreachable_value; |
| | 6170 | } |
| | 6171 | |
| 6158 | fn analyzeInlineCallArg( | 6172 | fn analyzeInlineCallArg( |
| 6159 | sema: *Sema, | 6173 | sema: *Sema, |
| 6160 | arg_block: *Block, | 6174 | arg_block: *Block, |
| ... | @@ -6670,7 +6684,8 @@ fn instantiateGenericCall( | ... | @@ -6670,7 +6684,8 @@ fn instantiateGenericCall( |
| 6670 | try sema.requireFunctionBlock(block, call_src); | 6684 | try sema.requireFunctionBlock(block, call_src); |
| 6671 | | 6685 | |
| 6672 | const comptime_args = callee.comptime_args.?; | 6686 | const comptime_args = callee.comptime_args.?; |
| 6673 | const new_fn_info = mod.declPtr(callee.owner_decl).ty.fnInfo(); | 6687 | const func_ty = mod.declPtr(callee.owner_decl).ty; |
| | 6688 | const new_fn_info = func_ty.fnInfo(); |
| 6674 | const runtime_args_len = @intCast(u32, new_fn_info.param_types.len); | 6689 | const runtime_args_len = @intCast(u32, new_fn_info.param_types.len); |
| 6675 | const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len); | 6690 | const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len); |
| 6676 | { | 6691 | { |
| ... | @@ -6717,7 +6732,7 @@ fn instantiateGenericCall( | ... | @@ -6717,7 +6732,7 @@ fn instantiateGenericCall( |
| 6717 | | 6732 | |
| 6718 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + | 6733 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 6719 | runtime_args_len); | 6734 | runtime_args_len); |
| 6720 | const func_inst = try block.addInst(.{ | 6735 | const result = try block.addInst(.{ |
| 6721 | .tag = call_tag, | 6736 | .tag = call_tag, |
| 6722 | .data = .{ .pl_op = .{ | 6737 | .data = .{ .pl_op = .{ |
| 6723 | .operand = callee_inst, | 6738 | .operand = callee_inst, |
| ... | @@ -6729,9 +6744,12 @@ fn instantiateGenericCall( | ... | @@ -6729,9 +6744,12 @@ fn instantiateGenericCall( |
| 6729 | sema.appendRefsAssumeCapacity(runtime_args); | 6744 | sema.appendRefsAssumeCapacity(runtime_args); |
| 6730 | | 6745 | |
| 6731 | if (ensure_result_used) { | 6746 | if (ensure_result_used) { |
| 6732 | try sema.ensureResultUsed(block, func_inst, call_src); | 6747 | try sema.ensureResultUsed(block, result, call_src); |
| 6733 | } | 6748 | } |
| 6734 | return func_inst; | 6749 | if (call_tag == .call_always_tail) { |
| | 6750 | return sema.handleTailCall(block, call_src, func_ty, result); |
| | 6751 | } |
| | 6752 | return result; |
| 6735 | } | 6753 | } |
| 6736 | | 6754 | |
| 6737 | fn emitDbgInline( | 6755 | fn emitDbgInline( |
| ... | @@ -19262,7 +19280,7 @@ fn resolveCallOptions( | ... | @@ -19262,7 +19280,7 @@ fn resolveCallOptions( |
| 19262 | return wanted_modifier; | 19280 | return wanted_modifier; |
| 19263 | }, | 19281 | }, |
| 19264 | // These can be upgraded to comptime. nosuspend bit can be safely ignored. | 19282 | // These can be upgraded to comptime. nosuspend bit can be safely ignored. |
| 19265 | .always_tail, .always_inline, .compile_time => { | 19283 | .always_inline, .compile_time => { |
| 19266 | _ = (try sema.resolveDefinedValue(block, func_src, func)) orelse { | 19284 | _ = (try sema.resolveDefinedValue(block, func_src, func)) orelse { |
| 19267 | return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(wanted_modifier)}); | 19285 | return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(wanted_modifier)}); |
| 19268 | }; | 19286 | }; |
| ... | @@ -19272,6 +19290,12 @@ fn resolveCallOptions( | ... | @@ -19272,6 +19290,12 @@ fn resolveCallOptions( |
| 19272 | } | 19290 | } |
| 19273 | return wanted_modifier; | 19291 | return wanted_modifier; |
| 19274 | }, | 19292 | }, |
| | 19293 | .always_tail => { |
| | 19294 | if (is_comptime) { |
| | 19295 | return .compile_time; |
| | 19296 | } |
| | 19297 | return wanted_modifier; |
| | 19298 | }, |
| 19275 | .async_kw => { | 19299 | .async_kw => { |
| 19276 | if (is_nosuspend) { | 19300 | if (is_nosuspend) { |
| 19277 | return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{}); | 19301 | return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{}); |