authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-01 03:28:13-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-01 03:28:13-05:00
log253d988e7c00f7ad0cc1b5f913562cb5c1712c91
treef4514b6232bfcfb7bee5e5274bcca7409da09906
parent834e992a7c4ca0f0e1935e01e23410bc1d95cc52

implementation of await

but it has bugs

7 files changed, 266 insertions(+), 23 deletions(-)

src/all_types.hpp+23
......@@ -1192,6 +1192,7 @@ struct TypeTableEntry {
11921192 TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]
11931193 TypeTableEntry *maybe_parent;
11941194 TypeTableEntry *promise_parent;
1195 TypeTableEntry *promise_frame_parent;
11951196 // If we generate a constant name value for this type, we memoize it here.
11961197 // The type of this is array
11971198 ConstExprValue *cached_const_name_val;
......@@ -1641,6 +1642,7 @@ struct CodeGen {
16411642 LLVMValueRef coro_free_fn_val;
16421643 LLVMValueRef coro_resume_fn_val;
16431644 LLVMValueRef coro_save_fn_val;
1645 LLVMValueRef coro_promise_fn_val;
16441646 LLVMValueRef coro_alloc_helper_fn_val;
16451647 bool error_during_imports;
16461648
......@@ -2025,8 +2027,10 @@ enum IrInstructionId {
20252027 IrInstructionIdCoroFree,
20262028 IrInstructionIdCoroResume,
20272029 IrInstructionIdCoroSave,
2030 IrInstructionIdCoroPromise,
20282031 IrInstructionIdCoroAllocHelper,
20292032 IrInstructionIdAtomicRmw,
2033 IrInstructionIdPromiseResultType,
20302034};
20312035
20322036struct IrInstruction {
......@@ -2943,6 +2947,12 @@ struct IrInstructionCoroSave {
29432947 IrInstruction *coro_handle;
29442948};
29452949
2950struct IrInstructionCoroPromise {
2951 IrInstruction base;
2952
2953 IrInstruction *coro_handle;
2954};
2955
29462956struct IrInstructionCoroAllocHelper {
29472957 IrInstruction base;
29482958
......@@ -2962,6 +2972,12 @@ struct IrInstructionAtomicRmw {
29622972 AtomicOrder resolved_ordering;
29632973};
29642974
2975struct IrInstructionPromiseResultType {
2976 IrInstruction base;
2977
2978 IrInstruction *promise_type;
2979};
2980
29652981static const size_t slice_ptr_index = 0;
29662982static const size_t slice_len_index = 1;
29672983
......@@ -2971,6 +2987,13 @@ static const size_t maybe_null_index = 1;
29712987static const size_t err_union_err_index = 0;
29722988static const size_t err_union_payload_index = 1;
29732989
2990#define ASYNC_ALLOC_FIELD_NAME "allocFn"
2991#define ASYNC_FREE_FIELD_NAME "freeFn"
2992#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"
2993#define RESULT_FIELD_NAME "result"
2994#define RESULT_PTR_FIELD_NAME "result_ptr"
2995
2996
29742997enum FloatMode {
29752998 FloatModeOptimized,
29762999 FloatModeStrict,
src/analyze.cpp+18
......@@ -457,6 +457,23 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
457457 return get_pointer_to_type_extra(g, child_type, is_const, false, get_abi_alignment(g, child_type), 0, 0);
458458}
459459
460TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type) {
461 if (return_type->promise_frame_parent != nullptr) {
462 return return_type->promise_frame_parent;
463 }
464
465 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);
466 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);
467 const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME};
468 TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type};
469 size_t field_count = type_has_bits(result_ptr_type) ? 3 : 1;
470 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));
471 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names, field_types, field_count);
472
473 return_type->promise_frame_parent = entry;
474 return entry;
475}
476
460477TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
461478 if (child_type->maybe_parent) {
462479 TypeTableEntry *entry = child_type->maybe_parent;
......@@ -5800,3 +5817,4 @@ bool fn_type_can_fail(FnTypeId *fn_type_id) {
58005817 return return_type->id == TypeTableEntryIdErrorUnion || return_type->id == TypeTableEntryIdErrorSet ||
58015818 fn_type_id->cc == CallingConventionAsync;
58025819}
5820
src/analyze.hpp+1
......@@ -36,6 +36,7 @@ TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node,
3636TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
3737 TypeTableEntry *field_types[], size_t field_count);
3838TypeTableEntry *get_promise_type(CodeGen *g, TypeTableEntry *result_type);
39TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type);
3940TypeTableEntry *get_test_fn_type(CodeGen *g);
4041bool handle_is_ptr(TypeTableEntry *type_entry);
4142void find_libc_include_path(CodeGen *g);
src/codegen.cpp+31-1
......@@ -1081,6 +1081,23 @@ static LLVMValueRef get_coro_save_fn_val(CodeGen *g) {
10811081 return g->coro_save_fn_val;
10821082}
10831083
1084static LLVMValueRef get_coro_promise_fn_val(CodeGen *g) {
1085 if (g->coro_promise_fn_val)
1086 return g->coro_promise_fn_val;
1087
1088 LLVMTypeRef param_types[] = {
1089 LLVMPointerType(LLVMInt8Type(), 0),
1090 LLVMInt32Type(),
1091 LLVMInt1Type(),
1092 };
1093 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 3, false);
1094 Buf *name = buf_sprintf("llvm.coro.promise");
1095 g->coro_promise_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1096 assert(LLVMGetIntrinsicID(g->coro_promise_fn_val));
1097
1098 return g->coro_promise_fn_val;
1099}
1100
10841101static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
10851102 if (g->return_address_fn_val)
10861103 return g->return_address_fn_val;
......@@ -4002,6 +4019,16 @@ static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, Ir
40024019 return LLVMBuildCall(g->builder, get_coro_save_fn_val(g), &coro_handle, 1, "");
40034020}
40044021
4022static LLVMValueRef ir_render_coro_promise(CodeGen *g, IrExecutable *executable, IrInstructionCoroPromise *instruction) {
4023 LLVMValueRef coro_handle = ir_llvm_value(g, instruction->coro_handle);
4024 LLVMValueRef params[] = {
4025 coro_handle,
4026 LLVMConstInt(LLVMInt32Type(), get_coro_frame_align_bytes(g), false),
4027 LLVMConstNull(LLVMInt1Type()),
4028 };
4029 return LLVMBuildCall(g->builder, get_coro_promise_fn_val(g), params, 3, "");
4030}
4031
40054032static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) {
40064033 if (g->coro_alloc_helper_fn_val != nullptr)
40074034 return g->coro_alloc_helper_fn_val;
......@@ -4064,7 +4091,7 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
40644091 LLVMValueRef coro_size = LLVMGetParam(fn_val, next_arg);
40654092 next_arg += 1;
40664093 LLVMValueRef alignment_val = LLVMConstInt(g->builtin_types.entry_u29->type_ref,
4067 2 * g->pointer_size_bytes, false);
4094 get_coro_frame_align_bytes(g), false);
40684095
40694096 ZigList<LLVMValueRef> args = {};
40704097 args.append(sret_ptr);
......@@ -4218,6 +4245,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
42184245 case IrInstructionIdTagType:
42194246 case IrInstructionIdExport:
42204247 case IrInstructionIdErrorUnion:
4248 case IrInstructionIdPromiseResultType:
42214249 zig_unreachable();
42224250
42234251 case IrInstructionIdReturn:
......@@ -4360,6 +4388,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
43604388 return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction);
43614389 case IrInstructionIdCoroSave:
43624390 return ir_render_coro_save(g, executable, (IrInstructionCoroSave *)instruction);
4391 case IrInstructionIdCoroPromise:
4392 return ir_render_coro_promise(g, executable, (IrInstructionCoroPromise *)instruction);
43634393 case IrInstructionIdCoroAllocHelper:
43644394 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
43654395 case IrInstructionIdAtomicRmw:
src/ir.cpp+167-18
......@@ -45,12 +45,6 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) {
4545 return { true, is_const, is_volatile };
4646}
4747
48static const char * ASYNC_ALLOC_FIELD_NAME = "allocFn";
49static const char * ASYNC_FREE_FIELD_NAME = "freeFn";
50static const char * AWAITER_HANDLE_FIELD_NAME = "awaiter_handle";
51static const char * RESULT_FIELD_NAME = "result";
52static const char * RESULT_PTR_FIELD_NAME = "result_ptr";
53
5448enum ConstCastResultId {
5549 ConstCastResultIdOk,
5650 ConstCastResultIdErrSet,
......@@ -697,6 +691,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSave *) {
697691 return IrInstructionIdCoroSave;
698692}
699693
694static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroPromise *) {
695 return IrInstructionIdCoroPromise;
696}
697
700698static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocHelper *) {
701699 return IrInstructionIdCoroAllocHelper;
702700}
......@@ -705,6 +703,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {
705703 return IrInstructionIdAtomicRmw;
706704}
707705
706static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) {
707 return IrInstructionIdPromiseResultType;
708}
709
708710template<typename T>
709711static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
710712 T *special_instruction = allocate<T>(1);
......@@ -937,25 +939,19 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast
937939static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
938940 TypeTableEntry *return_type)
939941{
940 TypeTableEntry *awaiter_handle_type = get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise);
941 TypeTableEntry *result_ptr_type = get_pointer_to_type(irb->codegen, return_type, false);
942 const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME};
943 TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type};
944 size_t field_count = type_has_bits(result_ptr_type) ? 3 : 1;
945 TypeTableEntry *struct_type = get_struct_type(irb->codegen, "AsyncFramePromise", field_names, field_types,
946 field_count);
942 TypeTableEntry *struct_type = get_promise_frame_type(irb->codegen, return_type);
947943
948944 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
949945 const_instruction->base.value.type = struct_type;
950946 const_instruction->base.value.special = ConstValSpecialStatic;
951 const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(field_count);
952 const_instruction->base.value.data.x_struct.fields[0].type = awaiter_handle_type;
947 const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(struct_type->data.structure.src_field_count);
948 const_instruction->base.value.data.x_struct.fields[0].type = struct_type->data.structure.fields[0].type_entry;
953949 const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic;
954950 const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr;
955 if (field_count == 3) {
951 if (struct_type->data.structure.src_field_count > 1) {
956952 const_instruction->base.value.data.x_struct.fields[1].type = return_type;
957953 const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef;
958 const_instruction->base.value.data.x_struct.fields[2].type = result_ptr_type;
954 const_instruction->base.value.data.x_struct.fields[2].type = struct_type->data.structure.fields[2].type_entry;
959955 const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef;
960956 }
961957 return &const_instruction->base;
......@@ -2605,6 +2601,17 @@ static IrInstruction *ir_build_coro_save(IrBuilder *irb, Scope *scope, AstNode *
26052601 return &instruction->base;
26062602}
26072603
2604static IrInstruction *ir_build_coro_promise(IrBuilder *irb, Scope *scope, AstNode *source_node,
2605 IrInstruction *coro_handle)
2606{
2607 IrInstructionCoroPromise *instruction = ir_build_instruction<IrInstructionCoroPromise>(irb, scope, source_node);
2608 instruction->coro_handle = coro_handle;
2609
2610 ir_ref_instruction(coro_handle, irb->current_basic_block);
2611
2612 return &instruction->base;
2613}
2614
26082615static IrInstruction *ir_build_coro_alloc_helper(IrBuilder *irb, Scope *scope, AstNode *source_node,
26092616 IrInstruction *alloc_fn, IrInstruction *coro_size)
26102617{
......@@ -2640,6 +2647,17 @@ static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode
26402647 return &instruction->base;
26412648}
26422649
2650static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
2651 IrInstruction *promise_type)
2652{
2653 IrInstructionPromiseResultType *instruction = ir_build_instruction<IrInstructionPromiseResultType>(irb, scope, source_node);
2654 instruction->promise_type = promise_type;
2655
2656 ir_ref_instruction(promise_type, irb->current_basic_block);
2657
2658 return &instruction->base;
2659}
2660
26432661static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
26442662 results[ReturnKindUnconditional] = 0;
26452663 results[ReturnKindError] = 0;
......@@ -5944,7 +5962,93 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
59445962 if (target_inst == irb->codegen->invalid_instruction)
59455963 return irb->codegen->invalid_instruction;
59465964
5947 zig_panic("TODO: generate await expr");
5965 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
5966 if (!fn_entry) {
5967 add_node_error(irb->codegen, node, buf_sprintf("await outside function definition"));
5968 return irb->codegen->invalid_instruction;
5969 }
5970 if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) {
5971 add_node_error(irb->codegen, node, buf_sprintf("await in non-async function"));
5972 return irb->codegen->invalid_instruction;
5973 }
5974
5975 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope);
5976 if (scope_defer_expr) {
5977 if (!scope_defer_expr->reported_err) {
5978 add_node_error(irb->codegen, node, buf_sprintf("cannot await inside defer expression"));
5979 scope_defer_expr->reported_err = true;
5980 }
5981 return irb->codegen->invalid_instruction;
5982 }
5983
5984 Scope *outer_scope = irb->exec->begin_scope;
5985
5986 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, parent_scope, node, target_inst);
5987 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
5988 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name);
5989
5990 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
5991 IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,
5992 awaiter_handle_field_name);
5993
5994 IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false);
5995 VariableTableEntry *result_var = ir_create_var(irb, node, parent_scope, nullptr,
5996 false, false, true, const_bool_false);
5997 IrInstruction *undefined_value = ir_build_const_undefined(irb, parent_scope, node);
5998 IrInstruction *target_promise_type = ir_build_typeof(irb, parent_scope, node, target_inst);
5999 IrInstruction *promise_result_type = ir_build_promise_result_type(irb, parent_scope, node, target_promise_type);
6000 ir_build_var_decl(irb, parent_scope, node, result_var, promise_result_type, nullptr, undefined_value);
6001 IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, parent_scope, node, result_var, false, false);
6002 ir_build_store_ptr(irb, parent_scope, node, result_ptr_field_ptr, my_result_var_ptr);
6003 IrInstruction *save_token = ir_build_coro_save(irb, parent_scope, node, irb->exec->coro_handle);
6004 IrInstruction *promise_type_val = ir_build_const_type(irb, parent_scope, node,
6005 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
6006 IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, parent_scope, node,
6007 promise_type_val, awaiter_field_ptr, nullptr, irb->exec->coro_handle, nullptr,
6008 AtomicRmwOp_xchg, AtomicOrderSeqCst);
6009 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);
6010 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");
6011 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");
6012 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "Merge");
6013 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
6014
6015 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
6016 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6017 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);
6018 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);
6019 ir_build_cancel(irb, parent_scope, node, target_inst);
6020 ir_build_br(irb, parent_scope, node, merge_block, const_bool_false);
6021
6022 ir_set_cursor_at_end_and_append_block(irb, yes_suspend_block);
6023 ir_build_coro_resume(irb, parent_scope, node, target_inst);
6024 IrInstruction *suspend_code = ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false);
6025 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup");
6026 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
6027
6028 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
6029 cases[0].value = ir_build_const_u8(irb, parent_scope, node, 0);
6030 cases[0].block = resume_block;
6031 cases[1].value = ir_build_const_u8(irb, parent_scope, node, 1);
6032 cases[1].block = cleanup_block;
6033 ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block,
6034 2, cases, const_bool_false);
6035
6036 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6037 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6038 ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false);
6039
6040 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6041 IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr);
6042 ir_build_br(irb, parent_scope, node, merge_block, const_bool_false);
6043
6044 ir_set_cursor_at_end_and_append_block(irb, merge_block);
6045 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
6046 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
6047 incoming_blocks[0] = resume_block;
6048 incoming_values[0] = yes_suspend_result;
6049 incoming_blocks[1] = no_suspend_block;
6050 incoming_values[1] = no_suspend_result;
6051 return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
59486052}
59496053
59506054static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
......@@ -17399,6 +17503,29 @@ static TypeTableEntry *ir_analyze_instruction_coro_save(IrAnalyze *ira, IrInstru
1739917503 return result->value.type;
1740017504}
1740117505
17506static TypeTableEntry *ir_analyze_instruction_coro_promise(IrAnalyze *ira, IrInstructionCoroPromise *instruction) {
17507 IrInstruction *coro_handle = instruction->coro_handle->other;
17508 if (type_is_invalid(coro_handle->value.type))
17509 return ira->codegen->builtin_types.entry_invalid;
17510
17511 if (coro_handle->value.type->id != TypeTableEntryIdPromise ||
17512 coro_handle->value.type->data.promise.result_type == nullptr)
17513 {
17514 ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'",
17515 buf_ptr(&coro_handle->value.type->name)));
17516 return ira->codegen->builtin_types.entry_invalid;
17517 }
17518
17519 TypeTableEntry *coro_frame_type = get_promise_frame_type(ira->codegen,
17520 coro_handle->value.type->data.promise.result_type);
17521
17522 IrInstruction *result = ir_build_coro_promise(&ira->new_irb, instruction->base.scope,
17523 instruction->base.source_node, coro_handle);
17524 ir_link_new_instruction(result, &instruction->base);
17525 result->value.type = get_pointer_to_type(ira->codegen, coro_frame_type, false);
17526 return result->value.type;
17527}
17528
1740217529static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, IrInstructionCoroAllocHelper *instruction) {
1740317530 IrInstruction *alloc_fn = instruction->alloc_fn->other;
1740417531 if (type_is_invalid(alloc_fn->value.type))
......@@ -17492,6 +17619,22 @@ static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstr
1749217619 return result->value.type;
1749317620}
1749417621
17622static TypeTableEntry *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) {
17623 TypeTableEntry *promise_type = ir_resolve_type(ira, instruction->promise_type->other);
17624 if (type_is_invalid(promise_type))
17625 return ira->codegen->builtin_types.entry_invalid;
17626
17627 if (promise_type->id != TypeTableEntryIdPromise || promise_type->data.promise.result_type == nullptr) {
17628 ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'",
17629 buf_ptr(&promise_type->name)));
17630 return ira->codegen->builtin_types.entry_invalid;
17631 }
17632
17633 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17634 out_val->data.x_type = promise_type->data.promise.result_type;
17635 return ira->codegen->builtin_types.entry_type;
17636}
17637
1749517638
1749617639static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
1749717640 switch (instruction->id) {
......@@ -17719,10 +17862,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1771917862 return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction);
1772017863 case IrInstructionIdCoroSave:
1772117864 return ir_analyze_instruction_coro_save(ira, (IrInstructionCoroSave *)instruction);
17865 case IrInstructionIdCoroPromise:
17866 return ir_analyze_instruction_coro_promise(ira, (IrInstructionCoroPromise *)instruction);
1772217867 case IrInstructionIdCoroAllocHelper:
1772317868 return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction);
1772417869 case IrInstructionIdAtomicRmw:
1772517870 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);
17871 case IrInstructionIdPromiseResultType:
17872 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
1772617873 }
1772717874 zig_unreachable();
1772817875}
......@@ -17927,6 +18074,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1792718074 case IrInstructionIdCoroSuspend:
1792818075 case IrInstructionIdCoroFree:
1792918076 case IrInstructionIdAtomicRmw:
18077 case IrInstructionIdCoroPromise:
18078 case IrInstructionIdPromiseResultType:
1793018079 return false;
1793118080
1793218081 case IrInstructionIdAsm:
src/ir_print.cpp+23-1
......@@ -839,7 +839,11 @@ static void ir_print_ptr_to_int(IrPrint *irp, IrInstructionPtrToInt *instruction
839839
840840static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction) {
841841 fprintf(irp->f, "@intToPtr(");
842 ir_print_other_instruction(irp, instruction->dest_type);
842 if (instruction->dest_type == nullptr) {
843 fprintf(irp->f, "(null)");
844 } else {
845 ir_print_other_instruction(irp, instruction->dest_type);
846 }
843847 fprintf(irp->f, ",");
844848 ir_print_other_instruction(irp, instruction->target);
845849 fprintf(irp->f, ")");
......@@ -1105,6 +1109,18 @@ static void ir_print_coro_save(IrPrint *irp, IrInstructionCoroSave *instruction)
11051109 fprintf(irp->f, ")");
11061110}
11071111
1112static void ir_print_coro_promise(IrPrint *irp, IrInstructionCoroPromise *instruction) {
1113 fprintf(irp->f, "@coroPromise(");
1114 ir_print_other_instruction(irp, instruction->coro_handle);
1115 fprintf(irp->f, ")");
1116}
1117
1118static void ir_print_promise_result_type(IrPrint *irp, IrInstructionPromiseResultType *instruction) {
1119 fprintf(irp->f, "@PromiseResultType(");
1120 ir_print_other_instruction(irp, instruction->promise_type);
1121 fprintf(irp->f, ")");
1122}
1123
11081124static void ir_print_coro_alloc_helper(IrPrint *irp, IrInstructionCoroAllocHelper *instruction) {
11091125 fprintf(irp->f, "@coroAllocHelper(");
11101126 ir_print_other_instruction(irp, instruction->alloc_fn);
......@@ -1501,6 +1517,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15011517 case IrInstructionIdAtomicRmw:
15021518 ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction);
15031519 break;
1520 case IrInstructionIdCoroPromise:
1521 ir_print_coro_promise(irp, (IrInstructionCoroPromise *)instruction);
1522 break;
1523 case IrInstructionIdPromiseResultType:
1524 ir_print_promise_result_type(irp, (IrInstructionPromiseResultType *)instruction);
1525 break;
15041526 }
15051527 fprintf(irp->f, "\n");
15061528}
test/cases/coroutines.zig+3-3
......@@ -4,7 +4,7 @@ const assert = std.debug.assert;
44var x: i32 = 1;
55
66test "create a coroutine and cancel it" {
7 const p = try (async(std.debug.global_allocator) simpleAsyncFn());
7 const p = try async(std.debug.global_allocator) simpleAsyncFn();
88 cancel p;
99 assert(x == 2);
1010}
......@@ -17,7 +17,7 @@ async fn simpleAsyncFn() void {
1717
1818test "coroutine suspend, resume, cancel" {
1919 seq('a');
20 const p = (async(std.debug.global_allocator) testAsyncSeq()) catch unreachable;
20 const p = try async(std.debug.global_allocator) testAsyncSeq();
2121 seq('c');
2222 resume p;
2323 seq('f');
......@@ -43,7 +43,7 @@ fn seq(c: u8) void {
4343}
4444
4545test "coroutine suspend with block" {
46 const p = (async(std.debug.global_allocator) testSuspendBlock()) catch unreachable;
46 const p = try async(std.debug.global_allocator) testSuspendBlock();
4747 std.debug.assert(!result);
4848 resume a_promise;
4949 std.debug.assert(result);