authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-02 01:05:34-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-02 01:06:00-04:00
log056c4e2c988c0a2ff6f1be8fe18a0a056d848271
tree86d830fbc801536ec06d7f5d7e609ff01e32288a
parent0f879d02a4c4b1de0e28c2863c1e5f3760eb5b19
signature Commit is signed but in an unrecognized format.

implement async await and return


9 files changed, 384 insertions(+), 146 deletions(-)

BRANCH_TODO+5-1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1 * await1 * compile error for error: expected anyframe->T, found 'anyframe'
2 * compile error for error: expected anyframe->T, found 'i32'
2 * await of a non async function3 * await of a non async function
3 * await in single-threaded mode4 * await in single-threaded mode
4 * async call on a non async function5 * async call on a non async function
...@@ -13,3 +14,6 @@...@@ -13,3 +14,6 @@
13 * @typeInfo for @Frame(func)14 * @typeInfo for @Frame(func)
14 * peer type resolution of *@Frame(func) and anyframe15 * peer type resolution of *@Frame(func) and anyframe
15 * peer type resolution of *@Frame(func) and anyframe->T when the return type matches16 * peer type resolution of *@Frame(func) and anyframe->T when the return type matches
17 * returning a value from within a suspend block
18 * struct types as the return type of an async function. make sure it works with return result locations.
19 * make resuming inside a suspend block, with nothing after it, a must-tail call.
src/all_types.hpp+9-1
...@@ -1550,6 +1550,8 @@ enum PanicMsgId {...@@ -1550,6 +1550,8 @@ enum PanicMsgId {
1550 PanicMsgIdFloatToInt,1550 PanicMsgIdFloatToInt,
1551 PanicMsgIdPtrCastNull,1551 PanicMsgIdPtrCastNull,
1552 PanicMsgIdBadResume,1552 PanicMsgIdBadResume,
1553 PanicMsgIdBadAwait,
1554 PanicMsgIdBadReturn,
15531555
1554 PanicMsgIdCount,1556 PanicMsgIdCount,
1555};1557};
...@@ -1795,7 +1797,6 @@ struct CodeGen {...@@ -1795,7 +1797,6 @@ struct CodeGen {
1795 ZigType *entry_arg_tuple;1797 ZigType *entry_arg_tuple;
1796 ZigType *entry_enum_literal;1798 ZigType *entry_enum_literal;
1797 ZigType *entry_any_frame;1799 ZigType *entry_any_frame;
1798 ZigType *entry_async_fn;
1799 } builtin_types;1800 } builtin_types;
18001801
1801 ZigType *align_amt_type;1802 ZigType *align_amt_type;
...@@ -2348,6 +2349,7 @@ enum IrInstructionId {...@@ -2348,6 +2349,7 @@ enum IrInstructionId {
2348 IrInstructionIdUnionInitNamedField,2349 IrInstructionIdUnionInitNamedField,
2349 IrInstructionIdSuspendBegin,2350 IrInstructionIdSuspendBegin,
2350 IrInstructionIdSuspendBr,2351 IrInstructionIdSuspendBr,
2352 IrInstructionIdAwait,
2351 IrInstructionIdCoroResume,2353 IrInstructionIdCoroResume,
2352};2354};
23532355
...@@ -3600,6 +3602,12 @@ struct IrInstructionSuspendBr {...@@ -3600,6 +3602,12 @@ struct IrInstructionSuspendBr {
3600 IrBasicBlock *resume_block;3602 IrBasicBlock *resume_block;
3601};3603};
36023604
3605struct IrInstructionAwait {
3606 IrInstruction base;
3607
3608 IrInstruction *frame;
3609};
3610
3603struct IrInstructionCoroResume {3611struct IrInstructionCoroResume {
3604 IrInstruction base;3612 IrInstruction base;
36053613
src/analyze.cpp+21-4
...@@ -3807,6 +3807,9 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {...@@ -3807,6 +3807,9 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
3807 } else if (fn->inferred_async_node->type == NodeTypeSuspend) {3807 } else if (fn->inferred_async_node->type == NodeTypeSuspend) {
3808 add_error_note(g, msg, fn->inferred_async_node,3808 add_error_note(g, msg, fn->inferred_async_node,
3809 buf_sprintf("suspends here"));3809 buf_sprintf("suspends here"));
3810 } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) {
3811 add_error_note(g, msg, fn->inferred_async_node,
3812 buf_sprintf("await is a suspend point"));
3810 } else {3813 } else {
3811 zig_unreachable();3814 zig_unreachable();
3812 }3815 }
...@@ -7361,7 +7364,7 @@ static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {...@@ -7361,7 +7364,7 @@ static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {
7361 param_di_types.append(get_llvm_di_type(g, gen_type));7364 param_di_types.append(get_llvm_di_type(g, gen_type));
7362 }7365 }
7363 if (is_async) {7366 if (is_async) {
7364 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(1);7367 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(2);
73657368
7366 ZigType *frame_type = get_any_frame_type(g, fn_type_id->return_type);7369 ZigType *frame_type = get_any_frame_type(g, fn_type_id->return_type);
7367 gen_param_types.append(get_llvm_type(g, frame_type));7370 gen_param_types.append(get_llvm_type(g, frame_type));
...@@ -7370,6 +7373,13 @@ static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {...@@ -7370,6 +7373,13 @@ static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {
7370 fn_type->data.fn.gen_param_info[0].src_index = 0;7373 fn_type->data.fn.gen_param_info[0].src_index = 0;
7371 fn_type->data.fn.gen_param_info[0].gen_index = 0;7374 fn_type->data.fn.gen_param_info[0].gen_index = 0;
7372 fn_type->data.fn.gen_param_info[0].type = frame_type;7375 fn_type->data.fn.gen_param_info[0].type = frame_type;
7376
7377 gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize));
7378 param_di_types.append(get_llvm_di_type(g, g->builtin_types.entry_usize));
7379
7380 fn_type->data.fn.gen_param_info[1].src_index = 1;
7381 fn_type->data.fn.gen_param_info[1].gen_index = 1;
7382 fn_type->data.fn.gen_param_info[1].type = g->builtin_types.entry_usize;
7373 } else {7383 } else {
7374 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);7384 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
7375 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {7385 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
...@@ -7434,15 +7444,21 @@ void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn) {...@@ -7434,15 +7444,21 @@ void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn) {
74347444
7435 ZigType *gen_return_type = g->builtin_types.entry_void;7445 ZigType *gen_return_type = g->builtin_types.entry_void;
7436 ZigList<ZigLLVMDIType *> param_di_types = {};7446 ZigList<ZigLLVMDIType *> param_di_types = {};
7447 ZigList<LLVMTypeRef> gen_param_types = {};
7437 // first "parameter" is return value7448 // first "parameter" is return value
7438 param_di_types.append(get_llvm_di_type(g, gen_return_type));7449 param_di_types.append(get_llvm_di_type(g, gen_return_type));
74397450
7440 ZigType *frame_type = get_coro_frame_type(g, fn);7451 ZigType *frame_type = get_coro_frame_type(g, fn);
7441 ZigType *ptr_type = get_pointer_to_type(g, frame_type, false);7452 ZigType *ptr_type = get_pointer_to_type(g, frame_type, false);
7442 LLVMTypeRef gen_param_type = get_llvm_type(g, ptr_type);7453 gen_param_types.append(get_llvm_type(g, ptr_type));
7443 param_di_types.append(get_llvm_di_type(g, ptr_type));7454 param_di_types.append(get_llvm_di_type(g, ptr_type));
74447455
7445 fn->raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type), &gen_param_type, 1, false);7456 // this parameter is used to pass the result pointer when await completes
7457 gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize));
7458 param_di_types.append(get_llvm_di_type(g, g->builtin_types.entry_usize));
7459
7460 fn->raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
7461 gen_param_types.items, gen_param_types.length, false);
7446 fn->raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);7462 fn->raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
7447}7463}
74487464
...@@ -7493,7 +7509,8 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re...@@ -7493,7 +7509,8 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re
7493 8*g->pointer_size_bytes, 8*g->builtin_types.entry_usize->abi_align, buf_ptr(&any_frame_type->name));7509 8*g->pointer_size_bytes, 8*g->builtin_types.entry_usize->abi_align, buf_ptr(&any_frame_type->name));
74947510
7495 LLVMTypeRef llvm_void = LLVMVoidType();7511 LLVMTypeRef llvm_void = LLVMVoidType();
7496 LLVMTypeRef fn_type = LLVMFunctionType(llvm_void, &any_frame_type->llvm_type, 1, false);7512 LLVMTypeRef arg_types[] = {any_frame_type->llvm_type, g->builtin_types.entry_usize->llvm_type};
7513 LLVMTypeRef fn_type = LLVMFunctionType(llvm_void, arg_types, 2, false);
7497 LLVMTypeRef usize_type_ref = get_llvm_type(g, g->builtin_types.entry_usize);7514 LLVMTypeRef usize_type_ref = get_llvm_type(g, g->builtin_types.entry_usize);
7498 ZigLLVMDIType *usize_di_type = get_llvm_di_type(g, g->builtin_types.entry_usize);7515 ZigLLVMDIType *usize_di_type = get_llvm_di_type(g, g->builtin_types.entry_usize);
7499 ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);7516 ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
src/ast_render.cpp+3-1
...@@ -1149,9 +1149,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1149,9 +1149,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1149 }1149 }
1150 case NodeTypeSuspend:1150 case NodeTypeSuspend:
1151 {1151 {
1152 fprintf(ar->f, "suspend");
1153 if (node->data.suspend.block != nullptr) {1152 if (node->data.suspend.block != nullptr) {
1153 fprintf(ar->f, "suspend ");
1154 render_node_grouped(ar, node->data.suspend.block);1154 render_node_grouped(ar, node->data.suspend.block);
1155 } else {
1156 fprintf(ar->f, "suspend\n");
1155 }1157 }
1156 break;1158 break;
1157 }1159 }
src/codegen.cpp+154-8
...@@ -873,6 +873,10 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -873,6 +873,10 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
873 return buf_create_from_str("cast causes pointer to be null");873 return buf_create_from_str("cast causes pointer to be null");
874 case PanicMsgIdBadResume:874 case PanicMsgIdBadResume:
875 return buf_create_from_str("invalid resume of async function");875 return buf_create_from_str("invalid resume of async function");
876 case PanicMsgIdBadAwait:
877 return buf_create_from_str("async function awaited twice");
878 case PanicMsgIdBadReturn:
879 return buf_create_from_str("async function returned twice");
876 }880 }
877 zig_unreachable();881 zig_unreachable();
878}882}
...@@ -1991,14 +1995,66 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut...@@ -1991,14 +1995,66 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
19911995
1992static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {1996static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
1993 if (fn_is_async(g->cur_fn)) {1997 if (fn_is_async(g->cur_fn)) {
1998 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
1999 LLVMValueRef locals_ptr = g->cur_ret_ptr;
2000 bool ret_type_has_bits = return_instruction->value != nullptr &&
2001 type_has_bits(return_instruction->value->value.type);
2002 ZigType *ret_type = ret_type_has_bits ? return_instruction->value->value.type : nullptr;
2003
1994 if (ir_want_runtime_safety(g, &return_instruction->base)) {2004 if (ir_want_runtime_safety(g, &return_instruction->base)) {
1995 LLVMValueRef locals_ptr = g->cur_ret_ptr;
1996 LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, locals_ptr, coro_fn_ptr_index, "");2005 LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, locals_ptr, coro_fn_ptr_index, "");
1997 LLVMValueRef new_resume_fn = g->cur_fn->resume_blocks.last()->split_llvm_fn;2006 LLVMValueRef new_resume_fn = g->cur_fn->resume_blocks.last()->split_llvm_fn;
1998 LLVMBuildStore(g->builder, new_resume_fn, resume_index_ptr);2007 LLVMBuildStore(g->builder, new_resume_fn, resume_index_ptr);
1999 }2008 }
20002009
2010 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, locals_ptr, coro_awaiter_index, "");
2011 LLVMValueRef result_ptr_as_usize;
2012 if (ret_type_has_bits) {
2013 LLVMValueRef result_ptr_ptr = LLVMBuildStructGEP(g->builder, locals_ptr, coro_arg_start, "");
2014 LLVMValueRef result_ptr = LLVMBuildLoad(g->builder, result_ptr_ptr, "");
2015 if (!handle_is_ptr(ret_type)) {
2016 // It's a scalar, so it didn't get written to the result ptr. Do that now.
2017 LLVMBuildStore(g->builder, ir_llvm_value(g, return_instruction->value), result_ptr);
2018 }
2019 result_ptr_as_usize = LLVMBuildPtrToInt(g->builder, result_ptr, usize_type_ref, "");
2020 } else {
2021 result_ptr_as_usize = LLVMGetUndef(usize_type_ref);
2022 }
2023 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
2024 LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref);
2025 LLVMValueRef prev_val = LLVMBuildAtomicRMW(g->builder, LLVMAtomicRMWBinOpXchg, awaiter_ptr,
2026 all_ones, LLVMAtomicOrderingSequentiallyConsistent, g->is_single_threaded);
2027
2028 LLVMBasicBlockRef bad_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadReturn");
2029 LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn");
2030 LLVMBasicBlockRef resume_them_block = LLVMAppendBasicBlock(g->cur_fn_val, "ResumeThem");
2031
2032 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, resume_them_block, 2);
2033
2034 LLVMAddCase(switch_instr, zero, early_return_block);
2035 LLVMAddCase(switch_instr, all_ones, bad_return_block);
2036
2037 // Something has gone horribly wrong, and this is an invalid second return.
2038 LLVMPositionBuilderAtEnd(g->builder, bad_return_block);
2039 gen_assertion(g, PanicMsgIdBadReturn, &return_instruction->base);
2040
2041 // The caller will deal with fetching the result - we're done.
2042 LLVMPositionBuilderAtEnd(g->builder, early_return_block);
2001 LLVMBuildRetVoid(g->builder);2043 LLVMBuildRetVoid(g->builder);
2044
2045 // We need to resume the caller by tail calling them.
2046 LLVMPositionBuilderAtEnd(g->builder, resume_them_block);
2047 ZigType *any_frame_type = get_any_frame_type(g, ret_type);
2048 LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, prev_val,
2049 get_llvm_type(g, any_frame_type), "");
2050 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, their_frame_ptr, coro_fn_ptr_index, "");
2051 LLVMValueRef awaiter_fn = LLVMBuildLoad(g->builder, fn_ptr_ptr, "");
2052 LLVMValueRef args[] = {their_frame_ptr, result_ptr_as_usize};
2053 LLVMValueRef call_inst = ZigLLVMBuildCall(g->builder, awaiter_fn, args, 2, LLVMFastCallConv,
2054 ZigLLVM_FnInlineAuto, "");
2055 ZigLLVMSetTailCall(call_inst);
2056 LLVMBuildRetVoid(g->builder);
2057
2002 return nullptr;2058 return nullptr;
2003 }2059 }
2004 if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {2060 if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {
...@@ -3514,14 +3570,17 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3514,14 +3570,17 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3514 }3570 }
3515 }3571 }
3516 if (instruction->is_async) {3572 if (instruction->is_async) {
3517 ZigLLVMBuildCall(g->builder, fn_val, &frame_result_loc, 1, llvm_cc, fn_inline, "");3573 LLVMValueRef args[] = {frame_result_loc, LLVMGetUndef(g->builtin_types.entry_usize->llvm_type)};
3574 ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, fn_inline, "");
3518 return nullptr;3575 return nullptr;
3519 } else if (callee_is_async) {3576 } else if (callee_is_async) {
3577 ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true);
3520 LLVMValueRef split_llvm_fn = make_fn_llvm_value(g, g->cur_fn);3578 LLVMValueRef split_llvm_fn = make_fn_llvm_value(g, g->cur_fn);
3521 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_fn_ptr_index, "");3579 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_fn_ptr_index, "");
3522 LLVMBuildStore(g->builder, split_llvm_fn, fn_ptr_ptr);3580 LLVMBuildStore(g->builder, split_llvm_fn, fn_ptr_ptr);
35233581
3524 LLVMValueRef call_inst = ZigLLVMBuildCall(g->builder, fn_val, &frame_result_loc, 1, llvm_cc, fn_inline, "");3582 LLVMValueRef args[] = {frame_result_loc, LLVMGetUndef(g->builtin_types.entry_usize->llvm_type)};
3583 LLVMValueRef call_inst = ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, fn_inline, "");
3525 ZigLLVMSetTailCall(call_inst);3584 ZigLLVMSetTailCall(call_inst);
3526 LLVMBuildRetVoid(g->builder);3585 LLVMBuildRetVoid(g->builder);
35273586
...@@ -3530,7 +3589,15 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3530,7 +3589,15 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3530 LLVMBasicBlockRef call_bb = LLVMAppendBasicBlock(split_llvm_fn, "CallResume");3589 LLVMBasicBlockRef call_bb = LLVMAppendBasicBlock(split_llvm_fn, "CallResume");
3531 LLVMPositionBuilderAtEnd(g->builder, call_bb);3590 LLVMPositionBuilderAtEnd(g->builder, call_bb);
3532 render_async_var_decls(g, instruction->base.scope);3591 render_async_var_decls(g, instruction->base.scope);
3533 return nullptr;3592
3593 if (type_has_bits(src_return_type)) {
3594 LLVMValueRef spilled_result_ptr = LLVMGetParam(g->cur_fn_val, 1);
3595 LLVMValueRef casted_spilled_result_ptr = LLVMBuildIntToPtr(g->builder, spilled_result_ptr,
3596 get_llvm_type(g, ptr_result_type), "");
3597 return get_handle_value(g, casted_spilled_result_ptr, src_return_type, ptr_result_type);
3598 } else {
3599 return nullptr;
3600 }
3534 }3601 }
35353602
3536 if (instruction->new_stack == nullptr) {3603 if (instruction->new_stack == nullptr) {
...@@ -4829,7 +4896,7 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,...@@ -4829,7 +4896,7 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
4829 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);4896 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
48304897
4831 if (get_codegen_ptr_type(operand_type) == nullptr) {4898 if (get_codegen_ptr_type(operand_type) == nullptr) {
4832 return LLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, false);4899 return LLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, g->is_single_threaded);
4833 }4900 }
48344901
4835 // it's a pointer but we need to treat it as an int4902 // it's a pointer but we need to treat it as an int
...@@ -4990,14 +5057,89 @@ static LLVMValueRef ir_render_suspend_br(CodeGen *g, IrExecutable *executable,...@@ -4990,14 +5057,89 @@ static LLVMValueRef ir_render_suspend_br(CodeGen *g, IrExecutable *executable,
4990 return nullptr;5057 return nullptr;
4991}5058}
49925059
5060static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwait *instruction) {
5061 LLVMValueRef target_frame_ptr = ir_llvm_value(g, instruction->frame);
5062 ZigType *result_type = instruction->base.value.type;
5063 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);
5064
5065 // Prepare to be suspended
5066 LLVMValueRef split_llvm_fn = make_fn_llvm_value(g, g->cur_fn);
5067 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_fn_ptr_index, "");
5068 LLVMBuildStore(g->builder, split_llvm_fn, fn_ptr_ptr);
5069
5070 // At this point resuming the function will do the correct thing.
5071 // This code is as if it is running inside the suspend block.
5072
5073 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
5074 // caller's own frame pointer
5075 LLVMValueRef awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_ret_ptr, usize_type_ref, "");
5076 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, coro_awaiter_index, "");
5077 LLVMValueRef result_ptr_as_usize;
5078 if (type_has_bits(result_type)) {
5079 LLVMValueRef result_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, coro_arg_start, "");
5080 LLVMValueRef result_ptr = LLVMBuildLoad(g->builder, result_ptr_ptr, "");
5081 result_ptr_as_usize = LLVMBuildPtrToInt(g->builder, result_ptr, usize_type_ref, "");
5082 } else {
5083 result_ptr_as_usize = LLVMGetUndef(usize_type_ref);
5084 }
5085 LLVMValueRef prev_val = LLVMBuildAtomicRMW(g->builder, LLVMAtomicRMWBinOpXchg, awaiter_ptr, awaiter_init_val,
5086 LLVMAtomicOrderingSequentiallyConsistent, g->is_single_threaded);
5087
5088 LLVMBasicBlockRef bad_await_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadAwait");
5089 LLVMBasicBlockRef complete_suspend_block = LLVMAppendBasicBlock(g->cur_fn_val, "CompleteSuspend");
5090 LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn");
5091
5092 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
5093 LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref);
5094 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, bad_await_block, 2);
5095
5096 LLVMAddCase(switch_instr, zero, complete_suspend_block);
5097 LLVMAddCase(switch_instr, all_ones, early_return_block);
5098
5099 // We discovered that another awaiter was already here.
5100 LLVMPositionBuilderAtEnd(g->builder, bad_await_block);
5101 gen_assertion(g, PanicMsgIdBadAwait, &instruction->base);
5102
5103 // Rely on the target to resume us from suspension.
5104 LLVMPositionBuilderAtEnd(g->builder, complete_suspend_block);
5105 LLVMBuildRetVoid(g->builder);
5106
5107 // The async function has already completed. So we use a tail call to resume ourselves.
5108 LLVMPositionBuilderAtEnd(g->builder, early_return_block);
5109 LLVMValueRef args[] = {g->cur_ret_ptr, result_ptr_as_usize};
5110 LLVMValueRef call_inst = ZigLLVMBuildCall(g->builder, split_llvm_fn, args, 2, LLVMFastCallConv,
5111 ZigLLVM_FnInlineAuto, "");
5112 ZigLLVMSetTailCall(call_inst);
5113 LLVMBuildRetVoid(g->builder);
5114
5115 g->cur_fn_val = split_llvm_fn;
5116 g->cur_ret_ptr = LLVMGetParam(split_llvm_fn, 0);
5117 LLVMBasicBlockRef call_bb = LLVMAppendBasicBlock(split_llvm_fn, "AwaitResume");
5118 LLVMPositionBuilderAtEnd(g->builder, call_bb);
5119 render_async_var_decls(g, instruction->base.scope);
5120
5121 if (type_has_bits(result_type)) {
5122 LLVMValueRef spilled_result_ptr = LLVMGetParam(g->cur_fn_val, 1);
5123 LLVMValueRef casted_spilled_result_ptr = LLVMBuildIntToPtr(g->builder, spilled_result_ptr,
5124 get_llvm_type(g, ptr_result_type), "");
5125 return get_handle_value(g, casted_spilled_result_ptr, result_type, ptr_result_type);
5126 } else {
5127 return nullptr;
5128 }
5129}
5130
4993static LLVMTypeRef anyframe_fn_type(CodeGen *g) {5131static LLVMTypeRef anyframe_fn_type(CodeGen *g) {
4994 if (g->anyframe_fn_type != nullptr)5132 if (g->anyframe_fn_type != nullptr)
4995 return g->anyframe_fn_type;5133 return g->anyframe_fn_type;
49965134
5135 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
4997 ZigType *anyframe_type = get_any_frame_type(g, nullptr);5136 ZigType *anyframe_type = get_any_frame_type(g, nullptr);
4998 LLVMTypeRef param_type = get_llvm_type(g, anyframe_type);
4999 LLVMTypeRef return_type = LLVMVoidType();5137 LLVMTypeRef return_type = LLVMVoidType();
5000 LLVMTypeRef fn_type = LLVMFunctionType(return_type, &param_type, 1, false);5138 LLVMTypeRef param_types[] = {
5139 get_llvm_type(g, anyframe_type),
5140 usize_type_ref,
5141 };
5142 LLVMTypeRef fn_type = LLVMFunctionType(return_type, param_types, 2, false);
5001 g->anyframe_fn_type = LLVMPointerType(fn_type, 0);5143 g->anyframe_fn_type = LLVMPointerType(fn_type, 0);
50025144
5003 return g->anyframe_fn_type;5145 return g->anyframe_fn_type;
...@@ -5006,13 +5148,15 @@ static LLVMTypeRef anyframe_fn_type(CodeGen *g) {...@@ -5006,13 +5148,15 @@ static LLVMTypeRef anyframe_fn_type(CodeGen *g) {
5006static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable,5148static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable,
5007 IrInstructionCoroResume *instruction)5149 IrInstructionCoroResume *instruction)
5008{5150{
5151 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
5009 LLVMValueRef frame = ir_llvm_value(g, instruction->frame);5152 LLVMValueRef frame = ir_llvm_value(g, instruction->frame);
5010 ZigType *frame_type = instruction->frame->value.type;5153 ZigType *frame_type = instruction->frame->value.type;
5011 assert(frame_type->id == ZigTypeIdAnyFrame);5154 assert(frame_type->id == ZigTypeIdAnyFrame);
5012 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, frame, coro_fn_ptr_index, "");5155 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, frame, coro_fn_ptr_index, "");
5013 LLVMValueRef uncasted_fn_val = LLVMBuildLoad(g->builder, fn_ptr_ptr, "");5156 LLVMValueRef uncasted_fn_val = LLVMBuildLoad(g->builder, fn_ptr_ptr, "");
5014 LLVMValueRef fn_val = LLVMBuildIntToPtr(g->builder, uncasted_fn_val, anyframe_fn_type(g), "");5157 LLVMValueRef fn_val = LLVMBuildIntToPtr(g->builder, uncasted_fn_val, anyframe_fn_type(g), "");
5015 ZigLLVMBuildCall(g->builder, fn_val, &frame, 1, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");5158 LLVMValueRef args[] = {frame, LLVMGetUndef(usize_type_ref)};
5159 ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");
5016 return nullptr;5160 return nullptr;
5017}5161}
50185162
...@@ -5279,6 +5423,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5279,6 +5423,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5279 return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction);5423 return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction);
5280 case IrInstructionIdFrameSizeGen:5424 case IrInstructionIdFrameSizeGen:
5281 return ir_render_frame_size(g, executable, (IrInstructionFrameSizeGen *)instruction);5425 return ir_render_frame_size(g, executable, (IrInstructionFrameSizeGen *)instruction);
5426 case IrInstructionIdAwait:
5427 return ir_render_await(g, executable, (IrInstructionAwait *)instruction);
5282 }5428 }
5283 zig_unreachable();5429 zig_unreachable();
5284}5430}
src/ir.cpp+82-15
...@@ -1052,6 +1052,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendBr *) {...@@ -1052,6 +1052,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendBr *) {
1052 return IrInstructionIdSuspendBr;1052 return IrInstructionIdSuspendBr;
1053}1053}
10541054
1055static constexpr IrInstructionId ir_instruction_id(IrInstructionAwait *) {
1056 return IrInstructionIdAwait;
1057}
1058
1055static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) {1059static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) {
1056 return IrInstructionIdCoroResume;1060 return IrInstructionIdCoroResume;
1057}1061}
...@@ -3274,6 +3278,17 @@ static IrInstruction *ir_build_suspend_br(IrBuilder *irb, Scope *scope, AstNode...@@ -3274,6 +3278,17 @@ static IrInstruction *ir_build_suspend_br(IrBuilder *irb, Scope *scope, AstNode
3274 return &instruction->base;3278 return &instruction->base;
3275}3279}
32763280
3281static IrInstruction *ir_build_await(IrBuilder *irb, Scope *scope, AstNode *source_node,
3282 IrInstruction *frame)
3283{
3284 IrInstructionAwait *instruction = ir_build_instruction<IrInstructionAwait>(irb, scope, source_node);
3285 instruction->frame = frame;
3286
3287 ir_ref_instruction(frame, irb->current_basic_block);
3288
3289 return &instruction->base;
3290}
3291
3277static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode *source_node,3292static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode *source_node,
3278 IrInstruction *frame)3293 IrInstruction *frame)
3279{3294{
...@@ -7774,11 +7789,26 @@ static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node)...@@ -7774,11 +7789,26 @@ static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node)
7774static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node) {7789static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
7775 assert(node->type == NodeTypeAwaitExpr);7790 assert(node->type == NodeTypeAwaitExpr);
77767791
7777 IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, scope);7792 ZigFn *fn_entry = exec_fn_entry(irb->exec);
7793 if (!fn_entry) {
7794 add_node_error(irb->codegen, node, buf_sprintf("await outside function definition"));
7795 return irb->codegen->invalid_instruction;
7796 }
7797 ScopeSuspend *existing_suspend_scope = get_scope_suspend(scope);
7798 if (existing_suspend_scope) {
7799 if (!existing_suspend_scope->reported_err) {
7800 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot await inside suspend block"));
7801 add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("suspend block here"));
7802 existing_suspend_scope->reported_err = true;
7803 }
7804 return irb->codegen->invalid_instruction;
7805 }
7806
7807 IrInstruction *target_inst = ir_gen_node_extra(irb, node->data.await_expr.expr, scope, LValPtr, nullptr);
7778 if (target_inst == irb->codegen->invalid_instruction)7808 if (target_inst == irb->codegen->invalid_instruction)
7779 return irb->codegen->invalid_instruction;7809 return irb->codegen->invalid_instruction;
77807810
7781 zig_panic("TODO ir_gen_await_expr");7811 return ir_build_await(irb, scope, node, target_inst);
7782}7812}
77837813
7784static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {7814static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
...@@ -7789,15 +7819,6 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod...@@ -7789,15 +7819,6 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
7789 add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));7819 add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));
7790 return irb->codegen->invalid_instruction;7820 return irb->codegen->invalid_instruction;
7791 }7821 }
7792 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope);
7793 if (scope_defer_expr) {
7794 if (!scope_defer_expr->reported_err) {
7795 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside defer expression"));
7796 add_error_note(irb->codegen, msg, scope_defer_expr->base.source_node, buf_sprintf("defer here"));
7797 scope_defer_expr->reported_err = true;
7798 }
7799 return irb->codegen->invalid_instruction;
7800 }
7801 ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);7822 ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);
7802 if (existing_suspend_scope) {7823 if (existing_suspend_scope) {
7803 if (!existing_suspend_scope->reported_err) {7824 if (!existing_suspend_scope->reported_err) {
...@@ -7808,7 +7829,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod...@@ -7808,7 +7829,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
7808 return irb->codegen->invalid_instruction;7829 return irb->codegen->invalid_instruction;
7809 }7830 }
78107831
7811 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "Resume");7832 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
78127833
7813 ir_build_suspend_begin(irb, parent_scope, node, resume_block);7834 ir_build_suspend_begin(irb, parent_scope, node, resume_block);
7814 if (node->data.suspend.block != nullptr) {7835 if (node->data.suspend.block != nullptr) {
...@@ -24372,19 +24393,62 @@ static IrInstruction *ir_analyze_instruction_suspend_br(IrAnalyze *ira, IrInstru...@@ -24372,19 +24393,62 @@ static IrInstruction *ir_analyze_instruction_suspend_br(IrAnalyze *ira, IrInstru
24372 return ir_finish_anal(ira, result);24393 return ir_finish_anal(ira, result);
24373}24394}
2437424395
24375static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstructionCoroResume *instruction) {24396static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwait *instruction) {
24376 IrInstruction *frame_ptr = instruction->frame->child;24397 IrInstruction *frame_ptr = instruction->frame->child;
24377 if (type_is_invalid(frame_ptr->value.type))24398 if (type_is_invalid(frame_ptr->value.type))
24378 return ira->codegen->invalid_instruction;24399 return ira->codegen->invalid_instruction;
2437924400
24401 ZigType *result_type;
24380 IrInstruction *frame;24402 IrInstruction *frame;
24381 if (frame_ptr->value.type->id == ZigTypeIdPointer &&24403 if (frame_ptr->value.type->id == ZigTypeIdPointer &&
24382 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&24404 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&
24383 frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdAnyFrame)24405 frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdCoroFrame)
24384 {24406 {
24385 frame = ir_get_deref(ira, &instruction->base, frame_ptr, nullptr);24407 result_type = frame_ptr->value.type->data.pointer.child_type->data.frame.fn->type_entry->data.fn.fn_type_id.return_type;
24408 frame = frame_ptr;
24386 } else {24409 } else {
24410 frame = ir_get_deref(ira, &instruction->base, frame_ptr, nullptr);
24411 if (frame->value.type->id != ZigTypeIdAnyFrame ||
24412 frame->value.type->data.any_frame.result_type == nullptr)
24413 {
24414 ir_add_error(ira, &instruction->base,
24415 buf_sprintf("expected anyframe->T, found '%s'", buf_ptr(&frame->value.type->name)));
24416 return ira->codegen->invalid_instruction;
24417 }
24418 result_type = frame->value.type->data.any_frame.result_type;
24419 }
24420
24421 ZigType *any_frame_type = get_any_frame_type(ira->codegen, result_type);
24422 IrInstruction *casted_frame = ir_implicit_cast(ira, frame, any_frame_type);
24423 if (type_is_invalid(casted_frame->value.type))
24424 return ira->codegen->invalid_instruction;
24425
24426 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24427 ir_assert(fn_entry != nullptr, &instruction->base);
24428
24429 if (fn_entry->inferred_async_node == nullptr) {
24430 fn_entry->inferred_async_node = instruction->base.source_node;
24431 }
24432
24433 IrInstruction *result = ir_build_await(&ira->new_irb,
24434 instruction->base.scope, instruction->base.source_node, frame);
24435 result->value.type = result_type;
24436 return ir_finish_anal(ira, result);
24437}
24438
24439static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstructionCoroResume *instruction) {
24440 IrInstruction *frame_ptr = instruction->frame->child;
24441 if (type_is_invalid(frame_ptr->value.type))
24442 return ira->codegen->invalid_instruction;
24443
24444 IrInstruction *frame;
24445 if (frame_ptr->value.type->id == ZigTypeIdPointer &&
24446 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&
24447 frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdCoroFrame)
24448 {
24387 frame = frame_ptr;24449 frame = frame_ptr;
24450 } else {
24451 frame = ir_get_deref(ira, &instruction->base, frame_ptr, nullptr);
24388 }24452 }
2438924453
24390 ZigType *any_frame_type = get_any_frame_type(ira->codegen, nullptr);24454 ZigType *any_frame_type = get_any_frame_type(ira->codegen, nullptr);
...@@ -24691,6 +24755,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -24691,6 +24755,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
24691 return ir_analyze_instruction_suspend_br(ira, (IrInstructionSuspendBr *)instruction);24755 return ir_analyze_instruction_suspend_br(ira, (IrInstructionSuspendBr *)instruction);
24692 case IrInstructionIdCoroResume:24756 case IrInstructionIdCoroResume:
24693 return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction);24757 return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction);
24758 case IrInstructionIdAwait:
24759 return ir_analyze_instruction_await(ira, (IrInstructionAwait *)instruction);
24694 }24760 }
24695 zig_unreachable();24761 zig_unreachable();
24696}24762}
...@@ -24826,6 +24892,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -24826,6 +24892,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
24826 case IrInstructionIdSuspendBegin:24892 case IrInstructionIdSuspendBegin:
24827 case IrInstructionIdSuspendBr:24893 case IrInstructionIdSuspendBr:
24828 case IrInstructionIdCoroResume:24894 case IrInstructionIdCoroResume:
24895 case IrInstructionIdAwait:
24829 return true;24896 return true;
2483024897
24831 case IrInstructionIdPhi:24898 case IrInstructionIdPhi:
src/ir_print.cpp+9
...@@ -1546,6 +1546,12 @@ static void ir_print_coro_resume(IrPrint *irp, IrInstructionCoroResume *instruct...@@ -1546,6 +1546,12 @@ static void ir_print_coro_resume(IrPrint *irp, IrInstructionCoroResume *instruct
1546 fprintf(irp->f, ")");1546 fprintf(irp->f, ")");
1547}1547}
15481548
1549static void ir_print_await(IrPrint *irp, IrInstructionAwait *instruction) {
1550 fprintf(irp->f, "@await(");
1551 ir_print_other_instruction(irp, instruction->frame);
1552 fprintf(irp->f, ")");
1553}
1554
1549static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1555static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1550 ir_print_prefix(irp, instruction);1556 ir_print_prefix(irp, instruction);
1551 switch (instruction->id) {1557 switch (instruction->id) {
...@@ -2025,6 +2031,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -2025,6 +2031,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
2025 case IrInstructionIdCoroResume:2031 case IrInstructionIdCoroResume:
2026 ir_print_coro_resume(irp, (IrInstructionCoroResume *)instruction);2032 ir_print_coro_resume(irp, (IrInstructionCoroResume *)instruction);
2027 break;2033 break;
2034 case IrInstructionIdAwait:
2035 ir_print_await(irp, (IrInstructionAwait *)instruction);
2036 break;
2028 }2037 }
2029 fprintf(irp->f, "\n");2038 fprintf(irp->f, "\n");
2030}2039}
test/stage1/behavior/coroutine_await_struct.zig+4-4
...@@ -6,12 +6,12 @@ const Foo = struct {...@@ -6,12 +6,12 @@ const Foo = struct {
6 x: i32,6 x: i32,
7};7};
88
9var await_a_promise: promise = undefined;9var await_a_promise: anyframe = undefined;
10var await_final_result = Foo{ .x = 0 };10var await_final_result = Foo{ .x = 0 };
1111
12test "coroutine await struct" {12test "coroutine await struct" {
13 await_seq('a');13 await_seq('a');
14 const p = async<std.heap.direct_allocator> await_amain() catch unreachable;14 const p = async await_amain();
15 await_seq('f');15 await_seq('f');
16 resume await_a_promise;16 resume await_a_promise;
17 await_seq('i');17 await_seq('i');
...@@ -20,7 +20,7 @@ test "coroutine await struct" {...@@ -20,7 +20,7 @@ test "coroutine await struct" {
20}20}
21async fn await_amain() void {21async fn await_amain() void {
22 await_seq('b');22 await_seq('b');
23 const p = async await_another() catch unreachable;23 const p = async await_another();
24 await_seq('e');24 await_seq('e');
25 await_final_result = await p;25 await_final_result = await p;
26 await_seq('h');26 await_seq('h');
...@@ -29,7 +29,7 @@ async fn await_another() Foo {...@@ -29,7 +29,7 @@ async fn await_another() Foo {
29 await_seq('c');29 await_seq('c');
30 suspend {30 suspend {
31 await_seq('d');31 await_seq('d');
32 await_a_promise = @handle();32 await_a_promise = @frame();
33 }33 }
34 await_seq('g');34 await_seq('g');
35 return Foo{ .x = 1234 };35 return Foo{ .x = 1234 };
test/stage1/behavior/coroutines.zig+97-112
...@@ -180,97 +180,85 @@ async fn testSuspendBlock() void {...@@ -180,97 +180,85 @@ async fn testSuspendBlock() void {
180 result = true;180 result = true;
181}181}
182182
183//var await_a_promise: anyframe = undefined;183var await_a_promise: anyframe = undefined;
184//var await_final_result: i32 = 0;184var await_final_result: i32 = 0;
185//185
186//test "coroutine await" {186test "coroutine await" {
187// await_seq('a');187 await_seq('a');
188// const p = async<allocator> await_amain() catch unreachable;188 const p = async await_amain();
189// await_seq('f');189 await_seq('f');
190// resume await_a_promise;190 resume await_a_promise;
191// await_seq('i');191 await_seq('i');
192// expect(await_final_result == 1234);192 expect(await_final_result == 1234);
193// expect(std.mem.eql(u8, await_points, "abcdefghi"));193 expect(std.mem.eql(u8, await_points, "abcdefghi"));
194//}194}
195//async fn await_amain() void {195async fn await_amain() void {
196// await_seq('b');196 await_seq('b');
197// const p = async await_another() catch unreachable;197 const p = async await_another();
198// await_seq('e');198 await_seq('e');
199// await_final_result = await p;199 await_final_result = await p;
200// await_seq('h');200 await_seq('h');
201//}201}
202//async fn await_another() i32 {202async fn await_another() i32 {
203// await_seq('c');203 await_seq('c');
204// suspend {204 suspend {
205// await_seq('d');205 await_seq('d');
206// await_a_promise = @frame();206 await_a_promise = @frame();
207// }207 }
208// await_seq('g');208 await_seq('g');
209// return 1234;209 return 1234;
210//}210}
211//211
212//var await_points = [_]u8{0} ** "abcdefghi".len;212var await_points = [_]u8{0} ** "abcdefghi".len;
213//var await_seq_index: usize = 0;213var await_seq_index: usize = 0;
214//214
215//fn await_seq(c: u8) void {215fn await_seq(c: u8) void {
216// await_points[await_seq_index] = c;216 await_points[await_seq_index] = c;
217// await_seq_index += 1;217 await_seq_index += 1;
218//}218}
219//219
220//var early_final_result: i32 = 0;220var early_final_result: i32 = 0;
221//221
222//test "coroutine await early return" {222test "coroutine await early return" {
223// early_seq('a');223 early_seq('a');
224// const p = async<allocator> early_amain() catch @panic("out of memory");224 const p = async early_amain();
225// early_seq('f');225 early_seq('f');
226// expect(early_final_result == 1234);226 expect(early_final_result == 1234);
227// expect(std.mem.eql(u8, early_points, "abcdef"));227 expect(std.mem.eql(u8, early_points, "abcdef"));
228//}228}
229//async fn early_amain() void {229async fn early_amain() void {
230// early_seq('b');230 early_seq('b');
231// const p = async early_another() catch @panic("out of memory");231 const p = async early_another();
232// early_seq('d');232 early_seq('d');
233// early_final_result = await p;233 early_final_result = await p;
234// early_seq('e');234 early_seq('e');
235//}235}
236//async fn early_another() i32 {236async fn early_another() i32 {
237// early_seq('c');237 early_seq('c');
238// return 1234;238 return 1234;
239//}239}
240//240
241//var early_points = [_]u8{0} ** "abcdef".len;241var early_points = [_]u8{0} ** "abcdef".len;
242//var early_seq_index: usize = 0;242var early_seq_index: usize = 0;
243//243
244//fn early_seq(c: u8) void {244fn early_seq(c: u8) void {
245// early_points[early_seq_index] = c;245 early_points[early_seq_index] = c;
246// early_seq_index += 1;246 early_seq_index += 1;
247//}247}
248//248
249//test "coro allocation failure" {249test "async function with dot syntax" {
250// var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0);250 const S = struct {
251// if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) {251 var y: i32 = 1;
252// @panic("expected allocation failure");252 async fn foo() void {
253// } else |err| switch (err) {253 y += 1;
254// error.OutOfMemory => {},254 suspend;
255// }255 }
256//}256 };
257//async fn asyncFuncThatNeverGetsRun() void {257 const p = async S.foo();
258// @panic("coro frame allocation should fail");258 // can't cancel in tests because they are non-async functions
259//}259 expect(S.y == 2);
260//260}
261//test "async function with dot syntax" {261
262// const S = struct {
263// var y: i32 = 1;
264// async fn foo() void {
265// y += 1;
266// suspend;
267// }
268// };
269// const p = try async<allocator> S.foo();
270// cancel p;
271// expect(S.y == 2);
272//}
273//
274//test "async fn pointer in a struct field" {262//test "async fn pointer in a struct field" {
275// var data: i32 = 1;263// var data: i32 = 1;
276// const Foo = struct {264// const Foo = struct {
...@@ -287,18 +275,17 @@ async fn testSuspendBlock() void {...@@ -287,18 +275,17 @@ async fn testSuspendBlock() void {
287// y.* += 1;275// y.* += 1;
288// suspend;276// suspend;
289//}277//}
290//278
291//test "async fn with inferred error set" {279//test "async fn with inferred error set" {
292// const p = (async<allocator> failing()) catch unreachable;280// const p = async failing();
293// resume p;281// resume p;
294// cancel p;
295//}282//}
296//283//
297//async fn failing() !void {284//async fn failing() !void {
298// suspend;285// suspend;
299// return error.Fail;286// return error.Fail;
300//}287//}
301//288
302//test "error return trace across suspend points - early return" {289//test "error return trace across suspend points - early return" {
303// const p = nonFailing();290// const p = nonFailing();
304// resume p;291// resume p;
...@@ -331,20 +318,18 @@ async fn testSuspendBlock() void {...@@ -331,20 +318,18 @@ async fn testSuspendBlock() void {
331// }318// }
332// };319// };
333//}320//}
334//321
335//test "break from suspend" {322test "break from suspend" {
336// var buf: [500]u8 = undefined;323 var my_result: i32 = 1;
337// var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;324 const p = async testBreakFromSuspend(&my_result);
338// var my_result: i32 = 1;325 // can't cancel here
339// const p = try async<a> testBreakFromSuspend(&my_result);326 std.testing.expect(my_result == 2);
340// cancel p;327}
341// std.testing.expect(my_result == 2);328async fn testBreakFromSuspend(my_result: *i32) void {
342//}329 suspend {
343//async fn testBreakFromSuspend(my_result: *i32) void {330 resume @frame();
344// suspend {331 }
345// resume @frame();332 my_result.* += 1;
346// }333 suspend;
347// my_result.* += 1;334 my_result.* += 1;
348// suspend;335}
349// my_result.* += 1;
350//}