implement async functions returning structs
This commit is contained in:
parent
5bd330e76c
commit
0920bb0872
|
@ -1,3 +1,4 @@
|
|||
* struct types as the return type of an async function. make sure it works with return result locations.
|
||||
* compile error for error: expected anyframe->T, found 'anyframe'
|
||||
* compile error for error: expected anyframe->T, found 'i32'
|
||||
* await of a non async function
|
||||
|
@ -15,5 +16,6 @@
|
|||
* peer type resolution of *@Frame(func) and anyframe
|
||||
* peer type resolution of *@Frame(func) and anyframe->T when the return type matches
|
||||
* returning a value from within a suspend block
|
||||
* struct types as the return type of an async function. make sure it works with return result locations.
|
||||
* make resuming inside a suspend block, with nothing after it, a must-tail call.
|
||||
* make sure there are safety tests for all the new safety features (search the new PanicFnId enum values)
|
||||
* error return tracing
|
||||
|
|
|
@ -503,7 +503,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
|
|||
// nothing to do
|
||||
} else if (type_is_nonnull_ptr(return_type)) {
|
||||
addLLVMAttr(llvm_fn, 0, "nonnull");
|
||||
} else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
|
||||
} else if (!is_async && want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
|
||||
// Sret pointers must not be address 0
|
||||
addLLVMArgAttr(llvm_fn, 0, "nonnull");
|
||||
addLLVMArgAttr(llvm_fn, 0, "sret");
|
||||
|
@ -3241,8 +3241,13 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
|
|||
static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable,
|
||||
IrInstructionReturnPtr *instruction)
|
||||
{
|
||||
src_assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type),
|
||||
instruction->base.source_node);
|
||||
if (!type_has_bits(instruction->base.value.type))
|
||||
return nullptr;
|
||||
src_assert(g->cur_ret_ptr != nullptr, instruction->base.source_node);
|
||||
if (fn_is_async(g->cur_fn)) {
|
||||
LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_arg_start, "");
|
||||
return LLVMBuildLoad(g->builder, ptr_ptr, "");
|
||||
}
|
||||
return g->cur_ret_ptr;
|
||||
}
|
||||
|
||||
|
@ -3506,6 +3511,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
|||
if (ret_has_bits) {
|
||||
ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start + 1, "");
|
||||
}
|
||||
|
||||
// Use the result location which is inside the frame if this is an async call.
|
||||
if (ret_has_bits) {
|
||||
LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start, "");
|
||||
LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
|
||||
}
|
||||
} else if (callee_is_async) {
|
||||
frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc);
|
||||
awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_ret_ptr,
|
||||
|
@ -3513,6 +3524,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
|||
if (ret_has_bits) {
|
||||
ret_ptr = result_loc;
|
||||
}
|
||||
|
||||
// Use the call instruction's result location.
|
||||
if (ret_has_bits) {
|
||||
LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start, "");
|
||||
LLVMBuildStore(g->builder, result_loc, ret_ptr_ptr);
|
||||
}
|
||||
}
|
||||
if (instruction->is_async || callee_is_async) {
|
||||
assert(frame_result_loc != nullptr);
|
||||
|
@ -3525,10 +3542,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
|||
LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_awaiter_index, "");
|
||||
LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);
|
||||
|
||||
if (ret_has_bits) {
|
||||
LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start, "");
|
||||
LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
|
||||
}
|
||||
}
|
||||
if (!instruction->is_async && !callee_is_async) {
|
||||
if (first_arg_ret) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
|
||||
var global_x: i32 = 1;
|
||||
|
||||
|
@ -357,3 +358,44 @@ test "heap allocated async function frame" {
|
|||
};
|
||||
try S.doTheTest();
|
||||
}
|
||||
|
||||
test "async function call return value" {
|
||||
const S = struct {
|
||||
var frame: anyframe = undefined;
|
||||
var pt = Point{.x = 10, .y = 11 };
|
||||
|
||||
fn doTheTest() void {
|
||||
expectEqual(pt.x, 10);
|
||||
expectEqual(pt.y, 11);
|
||||
_ = async first();
|
||||
expectEqual(pt.x, 10);
|
||||
expectEqual(pt.y, 11);
|
||||
resume frame;
|
||||
expectEqual(pt.x, 1);
|
||||
expectEqual(pt.y, 2);
|
||||
}
|
||||
|
||||
fn first() void {
|
||||
pt = second(1, 2);
|
||||
}
|
||||
|
||||
fn second(x: i32, y: i32) Point {
|
||||
return other(x, y);
|
||||
}
|
||||
|
||||
fn other(x: i32, y: i32) Point {
|
||||
frame = @frame();
|
||||
suspend;
|
||||
return Point{
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
}
|
||||
|
||||
const Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
};
|
||||
};
|
||||
S.doTheTest();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user