authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-08 11:37:49-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-08 11:37:49-04:00
log34bfdf193aee4cb4fc931c6cc4ee82ef0a3a506f
tree37d3c11a0b2cc5a2520428c912e53c2b868ffe85
parente11cafbd4f11fa5eae0cbdf03854291834b4cd77
signature Commit is signed but in an unrecognized format.

cancel, defer, errdefer all working as intended now


7 files changed, 243 insertions(+), 62 deletions(-)

BRANCH_TODO+1-2
...@@ -2,8 +2,7 @@...@@ -2,8 +2,7 @@
2 * compile error for error: expected anyframe->T, found 'i32'2 * compile error for error: expected anyframe->T, found 'i32'
3 * await of a non async function3 * await of a non async function
4 * async call on a non async function4 * async call on a non async function
5 * cancel5 * a test where an async function destroys its own frame in a defer
6 * defer and errdefer
7 * implicit cast of normal function to async function should be allowed when it is inferred to be async6 * implicit cast of normal function to async function should be allowed when it is inferred to be async
8 * revive std.event.Loop7 * revive std.event.Loop
9 * @typeInfo for @Frame(func)8 * @typeInfo for @Frame(func)
src/all_types.hpp+7
...@@ -2363,6 +2363,7 @@ enum IrInstructionId {...@@ -2363,6 +2363,7 @@ enum IrInstructionId {
2363 IrInstructionIdAwaitSrc,2363 IrInstructionIdAwaitSrc,
2364 IrInstructionIdAwaitGen,2364 IrInstructionIdAwaitGen,
2365 IrInstructionIdCoroResume,2365 IrInstructionIdCoroResume,
2366 IrInstructionIdTestCancelRequested,
2366};2367};
23672368
2368struct IrInstruction {2369struct IrInstruction {
...@@ -3636,6 +3637,12 @@ struct IrInstructionCoroResume {...@@ -3636,6 +3637,12 @@ struct IrInstructionCoroResume {
3636 IrInstruction *frame;3637 IrInstruction *frame;
3637};3638};
36383639
3640struct IrInstructionTestCancelRequested {
3641 IrInstruction base;
3642
3643 bool use_return_begin_prev_value;
3644};
3645
3639enum ResultLocId {3646enum ResultLocId {
3640 ResultLocIdInvalid,3647 ResultLocIdInvalid,
3641 ResultLocIdNone,3648 ResultLocIdNone,
src/codegen.cpp+14
...@@ -5557,6 +5557,18 @@ static LLVMValueRef ir_render_frame_size(CodeGen *g, IrExecutable *executable,...@@ -5557,6 +5557,18 @@ static LLVMValueRef ir_render_frame_size(CodeGen *g, IrExecutable *executable,
5557 return gen_frame_size(g, fn_val);5557 return gen_frame_size(g, fn_val);
5558}5558}
55595559
5560static LLVMValueRef ir_render_test_cancel_requested(CodeGen *g, IrExecutable *executable,
5561 IrInstructionTestCancelRequested *instruction)
5562{
5563 if (!fn_is_async(g->cur_fn))
5564 return LLVMConstInt(LLVMInt1Type(), 0, false);
5565 if (instruction->use_return_begin_prev_value) {
5566 return LLVMBuildTrunc(g->builder, g->cur_async_prev_val, LLVMInt1Type(), "");
5567 } else {
5568 zig_panic("TODO");
5569 }
5570}
5571
5560static void set_debug_location(CodeGen *g, IrInstruction *instruction) {5572static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
5561 AstNode *source_node = instruction->source_node;5573 AstNode *source_node = instruction->source_node;
5562 Scope *scope = instruction->scope;5574 Scope *scope = instruction->scope;
...@@ -5810,6 +5822,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5810,6 +5822,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5810 return ir_render_frame_size(g, executable, (IrInstructionFrameSizeGen *)instruction);5822 return ir_render_frame_size(g, executable, (IrInstructionFrameSizeGen *)instruction);
5811 case IrInstructionIdAwaitGen:5823 case IrInstructionIdAwaitGen:
5812 return ir_render_await(g, executable, (IrInstructionAwaitGen *)instruction);5824 return ir_render_await(g, executable, (IrInstructionAwaitGen *)instruction);
5825 case IrInstructionIdTestCancelRequested:
5826 return ir_render_test_cancel_requested(g, executable, (IrInstructionTestCancelRequested *)instruction);
5813 }5827 }
5814 zig_unreachable();5828 zig_unreachable();
5815}5829}
src/ir.cpp+122-35
...@@ -26,6 +26,7 @@ struct IrBuilder {...@@ -26,6 +26,7 @@ struct IrBuilder {
26 CodeGen *codegen;26 CodeGen *codegen;
27 IrExecutable *exec;27 IrExecutable *exec;
28 IrBasicBlock *current_basic_block;28 IrBasicBlock *current_basic_block;
29 AstNode *main_block_node;
29};30};
3031
31struct IrAnalyze {32struct IrAnalyze {
...@@ -1061,6 +1062,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) {...@@ -1061,6 +1062,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) {
1061 return IrInstructionIdCoroResume;1062 return IrInstructionIdCoroResume;
1062}1063}
10631064
1065static constexpr IrInstructionId ir_instruction_id(IrInstructionTestCancelRequested *) {
1066 return IrInstructionIdTestCancelRequested;
1067}
1068
1064template<typename T>1069template<typename T>
1065static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {1070static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
1066 T *special_instruction = allocate<T>(1);1071 T *special_instruction = allocate<T>(1);
...@@ -3320,6 +3325,16 @@ static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode...@@ -3320,6 +3325,16 @@ static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode
3320 return &instruction->base;3325 return &instruction->base;
3321}3326}
33223327
3328static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scope, AstNode *source_node,
3329 bool use_return_begin_prev_value)
3330{
3331 IrInstructionTestCancelRequested *instruction = ir_build_instruction<IrInstructionTestCancelRequested>(irb, scope, source_node);
3332 instruction->base.value.type = irb->codegen->builtin_types.entry_bool;
3333 instruction->use_return_begin_prev_value = use_return_begin_prev_value;
3334
3335 return &instruction->base;
3336}
3337
3323static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {3338static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
3324 results[ReturnKindUnconditional] = 0;3339 results[ReturnKindUnconditional] = 0;
3325 results[ReturnKindError] = 0;3340 results[ReturnKindError] = 0;
...@@ -3494,45 +3509,62 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3494,45 +3509,62 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3494 size_t defer_counts[2];3509 size_t defer_counts[2];
3495 ir_count_defers(irb, scope, outer_scope, defer_counts);3510 ir_count_defers(irb, scope, outer_scope, defer_counts);
3496 bool have_err_defers = defer_counts[ReturnKindError] > 0;3511 bool have_err_defers = defer_counts[ReturnKindError] > 0;
3497 if (have_err_defers || irb->codegen->have_err_ret_tracing) {3512 if (!have_err_defers && !irb->codegen->have_err_ret_tracing) {
3498 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");3513 // only generate unconditional defers
3499 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");3514 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3515 IrInstruction *result = ir_build_return(irb, scope, node, return_value);
3516 result_loc_ret->base.source_instruction = result;
3517 return result;
3518 }
3519 bool should_inline = ir_should_inline(irb->exec, scope);
3520 bool need_test_cancel = !should_inline && have_err_defers;
35003521
3501 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true);3522 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");
3523 IrBasicBlock *normal_defers_block = ir_create_basic_block(irb, scope, "Defers");
3524 IrBasicBlock *ok_block = need_test_cancel ?
3525 ir_create_basic_block(irb, scope, "ErrRetOk") : normal_defers_block;
3526 IrBasicBlock *all_defers_block = have_err_defers ? ir_create_basic_block(irb, scope, "ErrDefers") : normal_defers_block;
35023527
3503 bool should_inline = ir_should_inline(irb->exec, scope);3528 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true);
3504 IrInstruction *is_comptime;
3505 if (should_inline) {
3506 is_comptime = ir_build_const_bool(irb, scope, node, true);
3507 } else {
3508 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
3509 }
35103529
3511 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));3530 IrInstruction *force_comptime = ir_build_const_bool(irb, scope, node, should_inline);
3512 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");3531 IrInstruction *err_is_comptime;
3532 if (should_inline) {
3533 err_is_comptime = force_comptime;
3534 } else {
3535 err_is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
3536 }
35133537
3514 ir_set_cursor_at_end_and_append_block(irb, err_block);3538 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, err_is_comptime));
3515 if (irb->codegen->have_err_ret_tracing && !should_inline) {3539 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
3516 ir_build_save_err_ret_addr(irb, scope, node);
3517 }
3518 ir_gen_defers_for_block(irb, scope, outer_scope, true);
3519 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
35203540
3541 ir_set_cursor_at_end_and_append_block(irb, err_block);
3542 if (irb->codegen->have_err_ret_tracing && !should_inline) {
3543 ir_build_save_err_ret_addr(irb, scope, node);
3544 }
3545 ir_build_br(irb, scope, node, all_defers_block, err_is_comptime);
3546
3547 if (need_test_cancel) {
3521 ir_set_cursor_at_end_and_append_block(irb, ok_block);3548 ir_set_cursor_at_end_and_append_block(irb, ok_block);
3522 ir_gen_defers_for_block(irb, scope, outer_scope, false);3549 IrInstruction *is_canceled = ir_build_test_cancel_requested(irb, scope, node, true);
3523 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);3550 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_canceled,
3551 all_defers_block, normal_defers_block, force_comptime));
3552 }
35243553
3525 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);3554 if (all_defers_block != normal_defers_block) {
3526 IrInstruction *result = ir_build_return(irb, scope, node, return_value);3555 ir_set_cursor_at_end_and_append_block(irb, all_defers_block);
3527 result_loc_ret->base.source_instruction = result;3556 ir_gen_defers_for_block(irb, scope, outer_scope, true);
3528 return result;3557 ir_build_br(irb, scope, node, ret_stmt_block, force_comptime);
3529 } else {
3530 // generate unconditional defers
3531 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3532 IrInstruction *result = ir_build_return(irb, scope, node, return_value);
3533 result_loc_ret->base.source_instruction = result;
3534 return result;
3535 }3558 }
3559
3560 ir_set_cursor_at_end_and_append_block(irb, normal_defers_block);
3561 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3562 ir_build_br(irb, scope, node, ret_stmt_block, force_comptime);
3563
3564 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);
3565 IrInstruction *result = ir_build_return(irb, scope, node, return_value);
3566 result_loc_ret->base.source_instruction = result;
3567 return result;
3536 }3568 }
3537 case ReturnKindError:3569 case ReturnKindError:
3538 {3570 {
...@@ -3765,18 +3797,59 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -3765,18 +3797,59 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
3765 incoming_values.append(else_expr_result);3797 incoming_values.append(else_expr_result);
3766 }3798 }
37673799
3768 if (block_node->data.block.name != nullptr) {3800 bool is_return_from_fn = block_node == irb->main_block_node;
3801 if (!is_return_from_fn) {
3769 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);3802 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3803 }
3804
3805 IrInstruction *result;
3806 if (block_node->data.block.name != nullptr) {
3770 ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));3807 ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
3771 ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);3808 ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
3772 IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,3809 IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,
3773 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);3810 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
3774 return ir_expr_wrap(irb, parent_scope, phi, result_loc);3811 result = ir_expr_wrap(irb, parent_scope, phi, result_loc);
3775 } else {3812 } else {
3776 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3777 IrInstruction *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));3813 IrInstruction *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
3778 return ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc);3814 result = ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc);
3779 }3815 }
3816 if (!is_return_from_fn)
3817 return result;
3818
3819 // no need for save_err_ret_addr because this cannot return error
3820 // but if it is a canceled async function we do need to run the errdefers
3821
3822 ir_mark_gen(ir_build_add_implicit_return_type(irb, child_scope, block_node, result));
3823 result = ir_mark_gen(ir_build_return_begin(irb, child_scope, block_node, result));
3824
3825 size_t defer_counts[2];
3826 ir_count_defers(irb, child_scope, outer_block_scope, defer_counts);
3827 bool have_err_defers = defer_counts[ReturnKindError] > 0;
3828 if (!have_err_defers) {
3829 // only generate unconditional defers
3830 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3831 return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result));
3832 }
3833 IrInstruction *is_canceled = ir_build_test_cancel_requested(irb, child_scope, block_node, true);
3834 IrBasicBlock *all_defers_block = ir_create_basic_block(irb, child_scope, "ErrDefers");
3835 IrBasicBlock *normal_defers_block = ir_create_basic_block(irb, child_scope, "Defers");
3836 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, child_scope, "RetStmt");
3837 bool should_inline = ir_should_inline(irb->exec, child_scope);
3838 IrInstruction *errdefers_is_comptime = ir_build_const_bool(irb, child_scope, block_node,
3839 should_inline || !have_err_defers);
3840 ir_mark_gen(ir_build_cond_br(irb, child_scope, block_node, is_canceled,
3841 all_defers_block, normal_defers_block, errdefers_is_comptime));
3842
3843 ir_set_cursor_at_end_and_append_block(irb, all_defers_block);
3844 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, true);
3845 ir_build_br(irb, child_scope, block_node, ret_stmt_block, errdefers_is_comptime);
3846
3847 ir_set_cursor_at_end_and_append_block(irb, normal_defers_block);
3848 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3849 ir_build_br(irb, child_scope, block_node, ret_stmt_block, errdefers_is_comptime);
3850
3851 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);
3852 return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result));
3780}3853}
37813854
3782static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {3855static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
...@@ -8111,6 +8184,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -8111,6 +8184,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
81118184
8112 irb->codegen = codegen;8185 irb->codegen = codegen;
8113 irb->exec = ir_executable;8186 irb->exec = ir_executable;
8187 irb->main_block_node = node;
81148188
8115 IrBasicBlock *entry_block = ir_create_basic_block(irb, scope, "Entry");8189 IrBasicBlock *entry_block = ir_create_basic_block(irb, scope, "Entry");
8116 ir_set_cursor_at_end_and_append_block(irb, entry_block);8190 ir_set_cursor_at_end_and_append_block(irb, entry_block);
...@@ -24603,6 +24677,16 @@ static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstr...@@ -24603,6 +24677,16 @@ static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstr
24603 return ir_build_coro_resume(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_frame);24677 return ir_build_coro_resume(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_frame);
24604}24678}
2460524679
24680static IrInstruction *ir_analyze_instruction_test_cancel_requested(IrAnalyze *ira,
24681 IrInstructionTestCancelRequested *instruction)
24682{
24683 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) {
24684 return ir_const_bool(ira, &instruction->base, false);
24685 }
24686 return ir_build_test_cancel_requested(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
24687 instruction->use_return_begin_prev_value);
24688}
24689
24606static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {24690static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {
24607 switch (instruction->id) {24691 switch (instruction->id) {
24608 case IrInstructionIdInvalid:24692 case IrInstructionIdInvalid:
...@@ -24900,6 +24984,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -24900,6 +24984,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
24900 return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction);24984 return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction);
24901 case IrInstructionIdAwaitSrc:24985 case IrInstructionIdAwaitSrc:
24902 return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction);24986 return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction);
24987 case IrInstructionIdTestCancelRequested:
24988 return ir_analyze_instruction_test_cancel_requested(ira, (IrInstructionTestCancelRequested *)instruction);
24903 }24989 }
24904 zig_unreachable();24990 zig_unreachable();
24905}24991}
...@@ -25134,6 +25220,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25134,6 +25220,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25134 case IrInstructionIdHasDecl:25220 case IrInstructionIdHasDecl:
25135 case IrInstructionIdAllocaSrc:25221 case IrInstructionIdAllocaSrc:
25136 case IrInstructionIdAllocaGen:25222 case IrInstructionIdAllocaGen:
25223 case IrInstructionIdTestCancelRequested:
25137 return false;25224 return false;
2513825225
25139 case IrInstructionIdAsm:25226 case IrInstructionIdAsm:
src/ir_print.cpp+8
...@@ -1550,6 +1550,11 @@ static void ir_print_await_gen(IrPrint *irp, IrInstructionAwaitGen *instruction)...@@ -1550,6 +1550,11 @@ static void ir_print_await_gen(IrPrint *irp, IrInstructionAwaitGen *instruction)
1550 fprintf(irp->f, ")");1550 fprintf(irp->f, ")");
1551}1551}
15521552
1553static void ir_print_test_cancel_requested(IrPrint *irp, IrInstructionTestCancelRequested *instruction) {
1554 const char *arg = instruction->use_return_begin_prev_value ? "UseReturnBeginPrevValue" : "AdditionalCheck";
1555 fprintf(irp->f, "@testCancelRequested(%s)", arg);
1556}
1557
1553static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1558static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1554 ir_print_prefix(irp, instruction);1559 ir_print_prefix(irp, instruction);
1555 switch (instruction->id) {1560 switch (instruction->id) {
...@@ -2032,6 +2037,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -2032,6 +2037,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
2032 case IrInstructionIdAwaitGen:2037 case IrInstructionIdAwaitGen:
2033 ir_print_await_gen(irp, (IrInstructionAwaitGen *)instruction);2038 ir_print_await_gen(irp, (IrInstructionAwaitGen *)instruction);
2034 break;2039 break;
2040 case IrInstructionIdTestCancelRequested:
2041 ir_print_test_cancel_requested(irp, (IrInstructionTestCancelRequested *)instruction);
2042 break;
2035 }2043 }
2036 fprintf(irp->f, "\n");2044 fprintf(irp->f, "\n");
2037}2045}
test/stage1/behavior/cancel.zig+7-2
...@@ -48,8 +48,9 @@ var defer_b3: bool = false;...@@ -48,8 +48,9 @@ var defer_b3: bool = false;
48var defer_b4: bool = false;48var defer_b4: bool = false;
4949
50test "cancel backwards" {50test "cancel backwards" {
51 _ = async b1();51 var b1_frame = async b1();
52 resume b4_handle;52 resume b4_handle;
53 _ = async awaitAFrame(&b1_frame);
53 expect(defer_b1);54 expect(defer_b1);
54 expect(defer_b2);55 expect(defer_b2);
55 expect(defer_b3);56 expect(defer_b3);
...@@ -63,7 +64,7 @@ async fn b1() void {...@@ -63,7 +64,7 @@ async fn b1() void {
63 b2();64 b2();
64}65}
6566
66var b4_handle: anyframe = undefined;67var b4_handle: anyframe->void = undefined;
6768
68async fn b2() void {69async fn b2() void {
69 const b3_handle = async b3();70 const b3_handle = async b3();
...@@ -93,6 +94,10 @@ async fn b4() void {...@@ -93,6 +94,10 @@ async fn b4() void {
93 suspend;94 suspend;
94}95}
9596
97fn awaitAFrame(f: anyframe->void) void {
98 await f;
99}
100
96test "cancel on a non-pointer" {101test "cancel on a non-pointer" {
97 const S = struct {102 const S = struct {
98 fn doTheTest() void {103 fn doTheTest() void {
test/stage1/behavior/coroutines.zig+84-23
...@@ -134,29 +134,44 @@ test "@frameSize" {...@@ -134,29 +134,44 @@ test "@frameSize" {
134}134}
135135
136test "coroutine suspend, resume" {136test "coroutine suspend, resume" {
137 seq('a');137 const S = struct {
138 const p = async testAsyncSeq();138 var frame: anyframe = undefined;
139 seq('c');
140 resume p;
141 seq('f');
142 // `cancel` is now a suspend point so it cannot be done here
143 seq('g');
144139
145 expect(std.mem.eql(u8, points, "abcdefg"));140 fn doTheTest() void {
146}141 _ = async amain();
147async fn testAsyncSeq() void {142 seq('d');
148 defer seq('e');143 resume frame;
144 seq('h');
149145
150 seq('b');146 expect(std.mem.eql(u8, points, "abcdefgh"));
151 suspend;147 }
152 seq('d');148
153}149 fn amain() void {
154var points = [_]u8{0} ** "abcdefg".len;150 seq('a');
155var index: usize = 0;151 var f = async testAsyncSeq();
152 seq('c');
153 cancel f;
154 seq('g');
155 }
156
157 fn testAsyncSeq() void {
158 defer seq('f');
156159
157fn seq(c: u8) void {160 seq('b');
158 points[index] = c;161 suspend {
159 index += 1;162 frame = @frame();
163 }
164 seq('e');
165 }
166 var points = [_]u8{'x'} ** "abcdefgh".len;
167 var index: usize = 0;
168
169 fn seq(c: u8) void {
170 points[index] = c;
171 index += 1;
172 }
173 };
174 S.doTheTest();
160}175}
161176
162test "coroutine suspend with block" {177test "coroutine suspend with block" {
...@@ -267,12 +282,19 @@ test "async fn pointer in a struct field" {...@@ -267,12 +282,19 @@ test "async fn pointer in a struct field" {
267 };282 };
268 var foo = Foo{ .bar = simpleAsyncFn2 };283 var foo = Foo{ .bar = simpleAsyncFn2 };
269 var bytes: [64]u8 = undefined;284 var bytes: [64]u8 = undefined;
270 const p = @asyncCall(&bytes, {}, foo.bar, &data);285 const f = @asyncCall(&bytes, {}, foo.bar, &data);
271 comptime expect(@typeOf(p) == anyframe->void);286 comptime expect(@typeOf(f) == anyframe->void);
272 expect(data == 2);287 expect(data == 2);
273 resume p;288 resume f;
289 expect(data == 2);
290 _ = async doTheAwait(f);
274 expect(data == 4);291 expect(data == 4);
275}292}
293
294fn doTheAwait(f: anyframe->void) void {
295 await f;
296}
297
276async fn simpleAsyncFn2(y: *i32) void {298async fn simpleAsyncFn2(y: *i32) void {
277 defer y.* += 2;299 defer y.* += 2;
278 y.* += 1;300 y.* += 1;
...@@ -507,3 +529,42 @@ test "call async function which has struct return type" {...@@ -507,3 +529,42 @@ test "call async function which has struct return type" {
507 };529 };
508 S.doTheTest();530 S.doTheTest();
509}531}
532
533test "errdefers in scope get run when canceling async fn call" {
534 const S = struct {
535 var frame: anyframe = undefined;
536 var x: u32 = 0;
537
538 fn doTheTest() void {
539 x = 9;
540 _ = async cancelIt();
541 resume frame;
542 expect(x == 6);
543
544 x = 9;
545 _ = async awaitIt();
546 resume frame;
547 expect(x == 11);
548 }
549
550 fn cancelIt() void {
551 var f = async func();
552 cancel f;
553 }
554
555 fn awaitIt() void {
556 var f = async func();
557 await f;
558 }
559
560 fn func() void {
561 defer x += 1;
562 errdefer x /= 2;
563 defer x += 1;
564 suspend {
565 frame = @frame();
566 }
567 }
568 };
569 S.doTheTest();
570}