| author | |
| committer | |
| log | 8429d4ceac4eb99fbe8aeca2ebe864dfd5b40470 |
| tree | 693a05c4e44a5a1148505df8bf599ab5dda99fca |
| parent | c6227661568a9e8cad9d28bd7a11cb76c4f9c1c1 |
8 files changed, 89 insertions(+), 4 deletions(-)
doc/langref.html.in+3-1| ... | @@ -5682,7 +5682,7 @@ ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression | ... | @@ -5682,7 +5682,7 @@ ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression |
| 5682 | 5682 | ||
| 5683 | BlockOrExpression = Block | Expression | 5683 | BlockOrExpression = Block | Expression |
| 5684 | 5684 | ||
| 5685 | Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | 5685 | Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | ResumeExpression |
| 5686 | 5686 | ||
| 5687 | AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")" | 5687 | AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")" |
| 5688 | 5688 | ||
| ... | @@ -5730,6 +5730,8 @@ BreakExpression = "break" option(":" Symbol) option(Expression) | ... | @@ -5730,6 +5730,8 @@ BreakExpression = "break" option(":" Symbol) option(Expression) |
| 5730 | 5730 | ||
| 5731 | CancelExpression = "cancel" Expression; | 5731 | CancelExpression = "cancel" Expression; |
| 5732 | 5732 | ||
| 5733 | ResumeExpression = "resume" Expression; | ||
| 5734 | |||
| 5733 | Defer(body) = ("defer" | "deferror") body | 5735 | Defer(body) = ("defer" | "deferror") body |
| 5734 | 5736 | ||
| 5735 | IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body)) | 5737 | IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body)) |
src/all_types.hpp+6| ... | @@ -403,6 +403,7 @@ enum NodeType { | ... | @@ -403,6 +403,7 @@ enum NodeType { |
| 403 | NodeTypeTestExpr, | 403 | NodeTypeTestExpr, |
| 404 | NodeTypeErrorSetDecl, | 404 | NodeTypeErrorSetDecl, |
| 405 | NodeTypeCancel, | 405 | NodeTypeCancel, |
| 406 | NodeTypeResume, | ||
| 406 | NodeTypeAwaitExpr, | 407 | NodeTypeAwaitExpr, |
| 407 | NodeTypeSuspend, | 408 | NodeTypeSuspend, |
| 408 | }; | 409 | }; |
| ... | @@ -849,6 +850,10 @@ struct AstNodeCancelExpr { | ... | @@ -849,6 +850,10 @@ struct AstNodeCancelExpr { |
| 849 | AstNode *expr; | 850 | AstNode *expr; |
| 850 | }; | 851 | }; |
| 851 | 852 | ||
| 853 | struct AstNodeResumeExpr { | ||
| 854 | AstNode *expr; | ||
| 855 | }; | ||
| 856 | |||
| 852 | struct AstNodeContinueExpr { | 857 | struct AstNodeContinueExpr { |
| 853 | Buf *name; | 858 | Buf *name; |
| 854 | }; | 859 | }; |
| ... | @@ -930,6 +935,7 @@ struct AstNode { | ... | @@ -930,6 +935,7 @@ struct AstNode { |
| 930 | AstNodeVarLiteral var_literal; | 935 | AstNodeVarLiteral var_literal; |
| 931 | AstNodeErrorSetDecl err_set_decl; | 936 | AstNodeErrorSetDecl err_set_decl; |
| 932 | AstNodeCancelExpr cancel_expr; | 937 | AstNodeCancelExpr cancel_expr; |
| 938 | AstNodeResumeExpr resume_expr; | ||
| 933 | AstNodeAwaitExpr await_expr; | 939 | AstNodeAwaitExpr await_expr; |
| 934 | AstNodeSuspend suspend; | 940 | AstNodeSuspend suspend; |
| 935 | } data; | 941 | } data; |
src/analyze.cpp+1| ... | @@ -3212,6 +3212,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { | ... | @@ -3212,6 +3212,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3212 | case NodeTypeTestExpr: | 3212 | case NodeTypeTestExpr: |
| 3213 | case NodeTypeErrorSetDecl: | 3213 | case NodeTypeErrorSetDecl: |
| 3214 | case NodeTypeCancel: | 3214 | case NodeTypeCancel: |
| 3215 | case NodeTypeResume: | ||
| 3215 | case NodeTypeAwaitExpr: | 3216 | case NodeTypeAwaitExpr: |
| 3216 | case NodeTypeSuspend: | 3217 | case NodeTypeSuspend: |
| 3217 | zig_unreachable(); | 3218 | zig_unreachable(); |
src/ast_render.cpp+8| ... | @@ -246,6 +246,8 @@ static const char *node_type_str(NodeType node_type) { | ... | @@ -246,6 +246,8 @@ static const char *node_type_str(NodeType node_type) { |
| 246 | return "ErrorSetDecl"; | 246 | return "ErrorSetDecl"; |
| 247 | case NodeTypeCancel: | 247 | case NodeTypeCancel: |
| 248 | return "Cancel"; | 248 | return "Cancel"; |
| 249 | case NodeTypeResume: | ||
| 250 | return "Resume"; | ||
| 249 | case NodeTypeAwaitExpr: | 251 | case NodeTypeAwaitExpr: |
| 250 | return "AwaitExpr"; | 252 | return "AwaitExpr"; |
| 251 | case NodeTypeSuspend: | 253 | case NodeTypeSuspend: |
| ... | @@ -1049,6 +1051,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -1049,6 +1051,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 1049 | render_node_grouped(ar, node->data.cancel_expr.expr); | 1051 | render_node_grouped(ar, node->data.cancel_expr.expr); |
| 1050 | break; | 1052 | break; |
| 1051 | } | 1053 | } |
| 1054 | case NodeTypeResume: | ||
| 1055 | { | ||
| 1056 | fprintf(ar->f, "resume "); | ||
| 1057 | render_node_grouped(ar, node->data.resume_expr.expr); | ||
| 1058 | break; | ||
| 1059 | } | ||
| 1052 | case NodeTypeAwaitExpr: | 1060 | case NodeTypeAwaitExpr: |
| 1053 | { | 1061 | { |
| 1054 | fprintf(ar->f, "await "); | 1062 | fprintf(ar->f, "await "); |
src/codegen.cpp+1-1| ... | @@ -4004,7 +4004,7 @@ static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, Ir | ... | @@ -4004,7 +4004,7 @@ static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, Ir |
| 4004 | 4004 | ||
| 4005 | static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) { | 4005 | static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) { |
| 4006 | if (g->coro_alloc_helper_fn_val != nullptr) | 4006 | if (g->coro_alloc_helper_fn_val != nullptr) |
| 4007 | return g->coro_alloc_fn_val; | 4007 | return g->coro_alloc_helper_fn_val; |
| 4008 | 4008 | ||
| 4009 | assert(fn_type->id == TypeTableEntryIdFn); | 4009 | assert(fn_type->id == TypeTableEntryIdFn); |
| 4010 | 4010 |
src/ir.cpp+17-1| ... | @@ -5927,6 +5927,16 @@ static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -5927,6 +5927,16 @@ static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode |
| 5927 | return ir_build_cancel(irb, parent_scope, node, target_inst); | 5927 | return ir_build_cancel(irb, parent_scope, node, target_inst); |
| 5928 | } | 5928 | } |
| 5929 | 5929 | ||
| 5930 | static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | ||
| 5931 | assert(node->type == NodeTypeResume); | ||
| 5932 | |||
| 5933 | IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, parent_scope); | ||
| 5934 | if (target_inst == irb->codegen->invalid_instruction) | ||
| 5935 | return irb->codegen->invalid_instruction; | ||
| 5936 | |||
| 5937 | return ir_build_coro_resume(irb, parent_scope, node, target_inst); | ||
| 5938 | } | ||
| 5939 | |||
| 5930 | static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | 5940 | static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| 5931 | assert(node->type == NodeTypeAwaitExpr); | 5941 | assert(node->type == NodeTypeAwaitExpr); |
| 5932 | 5942 | ||
| ... | @@ -6101,6 +6111,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop | ... | @@ -6101,6 +6111,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 6101 | return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval); | 6111 | return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval); |
| 6102 | case NodeTypeCancel: | 6112 | case NodeTypeCancel: |
| 6103 | return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval); | 6113 | return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval); |
| 6114 | case NodeTypeResume: | ||
| 6115 | return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval); | ||
| 6104 | case NodeTypeAwaitExpr: | 6116 | case NodeTypeAwaitExpr: |
| 6105 | return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval); | 6117 | return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval); |
| 6106 | case NodeTypeSuspend: | 6118 | case NodeTypeSuspend: |
| ... | @@ -17364,8 +17376,12 @@ static TypeTableEntry *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInst | ... | @@ -17364,8 +17376,12 @@ static TypeTableEntry *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInst |
| 17364 | if (type_is_invalid(awaiter_handle->value.type)) | 17376 | if (type_is_invalid(awaiter_handle->value.type)) |
| 17365 | return ira->codegen->builtin_types.entry_invalid; | 17377 | return ira->codegen->builtin_types.entry_invalid; |
| 17366 | 17378 | ||
| 17379 | IrInstruction *casted_target = ir_implicit_cast(ira, awaiter_handle, ira->codegen->builtin_types.entry_promise); | ||
| 17380 | if (type_is_invalid(casted_target->value.type)) | ||
| 17381 | return ira->codegen->builtin_types.entry_invalid; | ||
| 17382 | |||
| 17367 | IrInstruction *result = ir_build_coro_resume(&ira->new_irb, instruction->base.scope, | 17383 | IrInstruction *result = ir_build_coro_resume(&ira->new_irb, instruction->base.scope, |
| 17368 | instruction->base.source_node, awaiter_handle); | 17384 | instruction->base.source_node, casted_target); |
| 17369 | ir_link_new_instruction(result, &instruction->base); | 17385 | ir_link_new_instruction(result, &instruction->base); |
| 17370 | result->value.type = ira->codegen->builtin_types.entry_void; | 17386 | result->value.type = ira->codegen->builtin_types.entry_void; |
| 17371 | return result->value.type; | 17387 | return result->value.type; |
src/parser.cpp+26-1| ... | @@ -1638,6 +1638,24 @@ static AstNode *ast_parse_cancel_expr(ParseContext *pc, size_t *token_index) { | ... | @@ -1638,6 +1638,24 @@ static AstNode *ast_parse_cancel_expr(ParseContext *pc, size_t *token_index) { |
| 1638 | return node; | 1638 | return node; |
| 1639 | } | 1639 | } |
| 1640 | 1640 | ||
| 1641 | /* | ||
| 1642 | ResumeExpression = "resume" Expression; | ||
| 1643 | */ | ||
| 1644 | static AstNode *ast_parse_resume_expr(ParseContext *pc, size_t *token_index) { | ||
| 1645 | Token *token = &pc->tokens->at(*token_index); | ||
| 1646 | |||
| 1647 | if (token->id != TokenIdKeywordResume) { | ||
| 1648 | return nullptr; | ||
| 1649 | } | ||
| 1650 | *token_index += 1; | ||
| 1651 | |||
| 1652 | AstNode *node = ast_create_node(pc, NodeTypeResume, token); | ||
| 1653 | |||
| 1654 | node->data.resume_expr.expr = ast_parse_expression(pc, token_index, false); | ||
| 1655 | |||
| 1656 | return node; | ||
| 1657 | } | ||
| 1658 | |||
| 1641 | /* | 1659 | /* |
| 1642 | Defer(body) = ("defer" | "errdefer") body | 1660 | Defer(body) = ("defer" | "errdefer") body |
| 1643 | */ | 1661 | */ |
| ... | @@ -2266,7 +2284,7 @@ static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_in | ... | @@ -2266,7 +2284,7 @@ static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_in |
| 2266 | } | 2284 | } |
| 2267 | 2285 | ||
| 2268 | /* | 2286 | /* |
| 2269 | Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | 2287 | Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | ResumeExpression |
| 2270 | */ | 2288 | */ |
| 2271 | static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) { | 2289 | static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 2272 | Token *token = &pc->tokens->at(*token_index); | 2290 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -2287,6 +2305,10 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool | ... | @@ -2287,6 +2305,10 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool |
| 2287 | if (cancel_expr) | 2305 | if (cancel_expr) |
| 2288 | return cancel_expr; | 2306 | return cancel_expr; |
| 2289 | 2307 | ||
| 2308 | AstNode *resume_expr = ast_parse_resume_expr(pc, token_index); | ||
| 2309 | if (resume_expr) | ||
| 2310 | return resume_expr; | ||
| 2311 | |||
| 2290 | AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false); | 2312 | AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false); |
| 2291 | if (ass_expr) | 2313 | if (ass_expr) |
| 2292 | return ass_expr; | 2314 | return ass_expr; |
| ... | @@ -3060,6 +3082,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont | ... | @@ -3060,6 +3082,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 3060 | case NodeTypeCancel: | 3082 | case NodeTypeCancel: |
| 3061 | visit_field(&node->data.cancel_expr.expr, visit, context); | 3083 | visit_field(&node->data.cancel_expr.expr, visit, context); |
| 3062 | break; | 3084 | break; |
| 3085 | case NodeTypeResume: | ||
| 3086 | visit_field(&node->data.resume_expr.expr, visit, context); | ||
| 3087 | break; | ||
| 3063 | case NodeTypeAwaitExpr: | 3088 | case NodeTypeAwaitExpr: |
| 3064 | visit_field(&node->data.await_expr.expr, visit, context); | 3089 | visit_field(&node->data.await_expr.expr, visit, context); |
| 3065 | break; | 3090 | break; |
test/cases/coroutines.zig+27| ... | @@ -14,3 +14,30 @@ async fn simpleAsyncFn() void { | ... | @@ -14,3 +14,30 @@ async fn simpleAsyncFn() void { |
| 14 | suspend; | 14 | suspend; |
| 15 | x += 1; | 15 | x += 1; |
| 16 | } | 16 | } |
| 17 | |||
| 18 | test "coroutine suspend, resume, cancel" { | ||
| 19 | seq('a'); | ||
| 20 | const p = (async(std.debug.global_allocator) testAsyncSeq()) catch unreachable; | ||
| 21 | seq('c'); | ||
| 22 | resume p; | ||
| 23 | seq('f'); | ||
| 24 | cancel p; | ||
| 25 | seq('g'); | ||
| 26 | |||
| 27 | assert(std.mem.eql(u8, points, "abcdefg")); | ||
| 28 | } | ||
| 29 | |||
| 30 | async fn testAsyncSeq() void { | ||
| 31 | defer seq('e'); | ||
| 32 | |||
| 33 | seq('b'); | ||
| 34 | suspend; | ||
| 35 | seq('d'); | ||
| 36 | } | ||
| 37 | var points = []u8{0} ** "abcdefg".len; | ||
| 38 | var index: usize = 0; | ||
| 39 | |||
| 40 | fn seq(c: u8) void { | ||
| 41 | points[index] = c; | ||
| 42 | index += 1; | ||
| 43 | } |