implement async functions returning structs

This commit is contained in:
Andrew Kelley 2019-08-02 19:27:27 -04:00
parent 5bd330e76c
commit 0920bb0872
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
3 changed files with 65 additions and 8 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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();
}