authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-07 00:12:15-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-07 00:13:12-04:00
logd1a98ccff481183d7fc53e45a902ef273c3d6aeb
treeb03efbb135bae39fcf6968b505ad67e4c6a33bda
parent9ca8d9e21ad657b023c23db5c440fb79a3303771
signaturelock-open Commit is signed but in an unrecognized format.

implement spills when expressions used across suspend points

closes #3077

7 files changed, 218 insertions(+), 29 deletions(-)

src/all_types.hpp+23
...@@ -2124,6 +2124,7 @@ enum ScopeId {...@@ -2124,6 +2124,7 @@ enum ScopeId {
2124 ScopeIdCompTime,2124 ScopeIdCompTime,
2125 ScopeIdRuntime,2125 ScopeIdRuntime,
2126 ScopeIdTypeOf,2126 ScopeIdTypeOf,
2127 ScopeIdExpr,
2127};2128};
21282129
2129struct Scope {2130struct Scope {
...@@ -2271,6 +2272,24 @@ struct ScopeTypeOf {...@@ -2271,6 +2272,24 @@ struct ScopeTypeOf {
2271 Scope base;2272 Scope base;
2272};2273};
22732274
2275enum MemoizedBool {
2276 MemoizedBoolUnknown,
2277 MemoizedBoolFalse,
2278 MemoizedBoolTrue,
2279};
2280
2281// This scope is created for each expression.
2282// It's used to identify when an instruction needs to be spilled,
2283// so that it can be accessed after a suspend point.
2284struct ScopeExpr {
2285 Scope base;
2286
2287 ScopeExpr **children_ptr;
2288 size_t children_len;
2289
2290 MemoizedBool need_spill;
2291};
2292
2274// synchronized with code in define_builtin_compile_vars2293// synchronized with code in define_builtin_compile_vars
2275enum AtomicOrder {2294enum AtomicOrder {
2276 AtomicOrderUnordered,2295 AtomicOrderUnordered,
...@@ -2510,6 +2529,10 @@ struct IrInstruction {...@@ -2510,6 +2529,10 @@ struct IrInstruction {
2510 // with this child field.2529 // with this child field.
2511 IrInstruction *child;2530 IrInstruction *child;
2512 IrBasicBlock *owner_bb;2531 IrBasicBlock *owner_bb;
2532 // Nearly any instruction can have to be stored as a local variable before suspending
2533 // and then loaded after resuming, in case there is an expression with a suspend point
2534 // in it, such as: x + await y
2535 IrInstruction *spill;
2513 IrInstructionId id;2536 IrInstructionId id;
2514 // true if this instruction was generated by zig and not from user code2537 // true if this instruction was generated by zig and not from user code
2515 bool is_gen;2538 bool is_gen;
src/analyze.cpp+148-11
...@@ -96,6 +96,30 @@ static ScopeDecls **get_container_scope_ptr(ZigType *type_entry) {...@@ -96,6 +96,30 @@ static ScopeDecls **get_container_scope_ptr(ZigType *type_entry) {
96 zig_unreachable();96 zig_unreachable();
97}97}
9898
99static ScopeExpr *find_expr_scope(Scope *scope) {
100 for (;;) {
101 switch (scope->id) {
102 case ScopeIdExpr:
103 return reinterpret_cast<ScopeExpr *>(scope);
104 case ScopeIdDefer:
105 case ScopeIdDeferExpr:
106 case ScopeIdDecls:
107 case ScopeIdFnDef:
108 case ScopeIdCompTime:
109 case ScopeIdVarDecl:
110 case ScopeIdCImport:
111 case ScopeIdSuspend:
112 case ScopeIdTypeOf:
113 case ScopeIdBlock:
114 return nullptr;
115 case ScopeIdLoop:
116 case ScopeIdRuntime:
117 scope = scope->parent;
118 continue;
119 }
120 }
121}
122
99ScopeDecls *get_container_scope(ZigType *type_entry) {123ScopeDecls *get_container_scope(ZigType *type_entry) {
100 return *get_container_scope_ptr(type_entry);124 return *get_container_scope_ptr(type_entry);
101}125}
...@@ -203,6 +227,20 @@ Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent) {...@@ -203,6 +227,20 @@ Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent) {
203 return &scope->base;227 return &scope->base;
204}228}
205229
230Scope *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent) {
231 ScopeExpr *scope = allocate<ScopeExpr>(1);
232 init_scope(g, &scope->base, ScopeIdExpr, node, parent);
233 ScopeExpr *parent_expr = find_expr_scope(parent);
234 if (parent_expr != nullptr) {
235 size_t new_len = parent_expr->children_len + 1;
236 parent_expr->children_ptr = reallocate_nonzero<ScopeExpr *>(
237 parent_expr->children_ptr, parent_expr->children_len, new_len);
238 parent_expr->children_ptr[parent_expr->children_len] = scope;
239 parent_expr->children_len = new_len;
240 }
241 return &scope->base;
242}
243
206ZigType *get_scope_import(Scope *scope) {244ZigType *get_scope_import(Scope *scope) {
207 while (scope) {245 while (scope) {
208 if (scope->id == ScopeIdDecls) {246 if (scope->id == ScopeIdDecls) {
...@@ -5654,6 +5692,69 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) {...@@ -5654,6 +5692,69 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) {
5654 return fn_type;5692 return fn_type;
5655}5693}
56565694
5695// Traverse up to the very top ExprScope, which has children.
5696// We have just arrived at the top from a child. That child,
5697// and its next siblings, do not need to be marked. But the previous
5698// siblings do.
5699// x + (await y)
5700// vs
5701// (await y) + x
5702static void mark_suspension_point(Scope *scope) {
5703 ScopeExpr *child_expr_scope = (scope->id == ScopeIdExpr) ? reinterpret_cast<ScopeExpr *>(scope) : nullptr;
5704 for (;;) {
5705 scope = scope->parent;
5706 switch (scope->id) {
5707 case ScopeIdDefer:
5708 case ScopeIdDeferExpr:
5709 case ScopeIdDecls:
5710 case ScopeIdFnDef:
5711 case ScopeIdCompTime:
5712 case ScopeIdVarDecl:
5713 case ScopeIdCImport:
5714 case ScopeIdSuspend:
5715 case ScopeIdTypeOf:
5716 case ScopeIdBlock:
5717 return;
5718 case ScopeIdLoop:
5719 case ScopeIdRuntime:
5720 continue;
5721 case ScopeIdExpr: {
5722 ScopeExpr *parent_expr_scope = reinterpret_cast<ScopeExpr *>(scope);
5723 if (child_expr_scope != nullptr) {
5724 for (size_t i = 0; parent_expr_scope->children_ptr[i] != child_expr_scope; i += 1) {
5725 assert(i < parent_expr_scope->children_len);
5726 parent_expr_scope->children_ptr[i]->need_spill = MemoizedBoolTrue;
5727 }
5728 }
5729 parent_expr_scope->need_spill = MemoizedBoolTrue;
5730 child_expr_scope = parent_expr_scope;
5731 continue;
5732 }
5733 }
5734 }
5735}
5736
5737static bool scope_needs_spill(Scope *scope) {
5738 ScopeExpr *scope_expr = find_expr_scope(scope);
5739 if (scope_expr == nullptr) return false;
5740
5741 switch (scope_expr->need_spill) {
5742 case MemoizedBoolUnknown:
5743 if (scope_needs_spill(scope_expr->base.parent)) {
5744 scope_expr->need_spill = MemoizedBoolTrue;
5745 return true;
5746 } else {
5747 scope_expr->need_spill = MemoizedBoolFalse;
5748 return false;
5749 }
5750 case MemoizedBoolFalse:
5751 return false;
5752 case MemoizedBoolTrue:
5753 return true;
5754 }
5755 zig_unreachable();
5756}
5757
5657static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {5758static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5658 Error err;5759 Error err;
56595760
...@@ -5786,21 +5887,17 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {...@@ -5786,21 +5887,17 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5786 callee_frame_type, "");5887 callee_frame_type, "");
5787 }5888 }
5788 // Since this frame is async, an await might represent a suspend point, and5889 // Since this frame is async, an await might represent a suspend point, and
5789 // therefore need to spill.5890 // therefore need to spill. It also needs to mark expr scopes as having to spill.
5891 // For example: foo() + await z
5892 // The funtion call result of foo() must be spilled.
5790 for (size_t i = 0; i < fn->await_list.length; i += 1) {5893 for (size_t i = 0; i < fn->await_list.length; i += 1) {
5791 IrInstructionAwaitGen *await = fn->await_list.at(i);5894 IrInstructionAwaitGen *await = fn->await_list.at(i);
5792 // TODO If this is a noasync await, it doesn't need to spill5895 // TODO If this is a noasync await, it doesn't suspend
5793 // https://github.com/ziglang/zig/issues/31575896 // https://github.com/ziglang/zig/issues/3157
5794 if (await->result_loc != nullptr) {5897 if (await->base.value.special != ConstValSpecialRuntime) {
5795 // If there's a result location, that is the spill5898 // Known at comptime. No spill, no suspend.
5796 continue;5899 continue;
5797 }5900 }
5798 if (!type_has_bits(await->base.value.type))
5799 continue;
5800 if (await->base.value.special != ConstValSpecialRuntime)
5801 continue;
5802 if (await->base.ref_count == 0)
5803 continue;
5804 if (await->target_fn != nullptr) {5901 if (await->target_fn != nullptr) {
5805 // we might not need to suspend5902 // we might not need to suspend
5806 analyze_fn_async(g, await->target_fn, false);5903 analyze_fn_async(g, await->target_fn, false);
...@@ -5809,13 +5906,53 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {...@@ -5809,13 +5906,53 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5809 return ErrorSemanticAnalyzeFail;5906 return ErrorSemanticAnalyzeFail;
5810 }5907 }
5811 if (!fn_is_async(await->target_fn)) {5908 if (!fn_is_async(await->target_fn)) {
5812 // This await does not represent a suspend point. No spill needed.5909 // This await does not represent a suspend point. No spill needed,
5910 // and no need to mark ExprScope.
5813 continue;5911 continue;
5814 }5912 }
5815 }5913 }
5914 // This await is a suspend point, but it might not need a spill.
5915 // We do need to mark the ExprScope as having a suspend point in it.
5916 mark_suspension_point(await->base.scope);
5917
5918 if (await->result_loc != nullptr) {
5919 // If there's a result location, that is the spill
5920 continue;
5921 }
5922 if (await->base.ref_count == 0)
5923 continue;
5924 if (!type_has_bits(await->base.value.type))
5925 continue;
5816 await->result_loc = ir_create_alloca(g, await->base.scope, await->base.source_node, fn,5926 await->result_loc = ir_create_alloca(g, await->base.scope, await->base.source_node, fn,
5817 await->base.value.type, "");5927 await->base.value.type, "");
5818 }5928 }
5929 // Now that we've marked all the expr scopes that have to spill, we go over the instructions
5930 // and spill the relevant ones.
5931 for (size_t block_i = 0; block_i < fn->analyzed_executable.basic_block_list.length; block_i += 1) {
5932 IrBasicBlock *block = fn->analyzed_executable.basic_block_list.at(block_i);
5933 for (size_t instr_i = 0; instr_i < block->instruction_list.length; instr_i += 1) {
5934 IrInstruction *instruction = block->instruction_list.at(instr_i);
5935 if (instruction->id == IrInstructionIdAwaitGen ||
5936 instruction->id == IrInstructionIdVarPtr ||
5937 instruction->id == IrInstructionIdDeclRef ||
5938 instruction->id == IrInstructionIdAllocaGen)
5939 {
5940 // This instruction does its own spilling specially, or otherwise doesn't need it.
5941 continue;
5942 }
5943 if (instruction->value.special != ConstValSpecialRuntime)
5944 continue;
5945 if (instruction->ref_count == 0)
5946 continue;
5947 if (!type_has_bits(instruction->value.type))
5948 continue;
5949 if (scope_needs_spill(instruction->scope)) {
5950 instruction->spill = ir_create_alloca(g, instruction->scope, instruction->source_node,
5951 fn, instruction->value.type, "");
5952 }
5953 }
5954 }
5955
5819 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;5956 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
5820 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);5957 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);
58215958
src/analyze.hpp+1-1
...@@ -114,6 +114,7 @@ ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *...@@ -114,6 +114,7 @@ ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *
114Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);114Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
115Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);115Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);
116Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent);116Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent);
117Scope *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent);
117118
118void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);119void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
119ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);120ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);
...@@ -261,5 +262,4 @@ void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn);...@@ -261,5 +262,4 @@ void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn);
261IrInstruction *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn,262IrInstruction *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn,
262 ZigType *var_type, const char *name_hint);263 ZigType *var_type, const char *name_hint);
263264
264
265#endif265#endif
src/codegen.cpp+14-3
...@@ -649,6 +649,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -649,6 +649,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
649 case ScopeIdCompTime:649 case ScopeIdCompTime:
650 case ScopeIdRuntime:650 case ScopeIdRuntime:
651 case ScopeIdTypeOf:651 case ScopeIdTypeOf:
652 case ScopeIdExpr:
652 return get_di_scope(g, scope->parent);653 return get_di_scope(g, scope->parent);
653 }654 }
654 zig_unreachable();655 zig_unreachable();
...@@ -1644,7 +1645,6 @@ static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type,...@@ -1644,7 +1645,6 @@ static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type,
1644 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");1645 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");
16451646
1646 gen_store(g, ored_value, ptr, ptr_type);1647 gen_store(g, ored_value, ptr, ptr_type);
1647 return;
1648}1648}
16491649
1650static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {1650static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {
...@@ -1664,11 +1664,16 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {...@@ -1664,11 +1664,16 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
1664 if (instruction->id == IrInstructionIdAwaitGen) {1664 if (instruction->id == IrInstructionIdAwaitGen) {
1665 IrInstructionAwaitGen *await = reinterpret_cast<IrInstructionAwaitGen*>(instruction);1665 IrInstructionAwaitGen *await = reinterpret_cast<IrInstructionAwaitGen*>(instruction);
1666 if (await->result_loc != nullptr) {1666 if (await->result_loc != nullptr) {
1667 instruction->llvm_value = get_handle_value(g, ir_llvm_value(g, await->result_loc),1667 return get_handle_value(g, ir_llvm_value(g, await->result_loc),
1668 await->result_loc->value.type->data.pointer.child_type, await->result_loc->value.type);1668 await->result_loc->value.type->data.pointer.child_type, await->result_loc->value.type);
1669 return instruction->llvm_value;
1670 }1669 }
1671 }1670 }
1671 if (instruction->spill != nullptr) {
1672 ZigType *ptr_type = instruction->spill->value.type;
1673 src_assert(ptr_type->id == ZigTypeIdPointer, instruction->source_node);
1674 return get_handle_value(g, ir_llvm_value(g, instruction->spill),
1675 ptr_type->data.pointer.child_type, instruction->spill->value.type);
1676 }
1672 src_assert(instruction->value.special != ConstValSpecialRuntime, instruction->source_node);1677 src_assert(instruction->value.special != ConstValSpecialRuntime, instruction->source_node);
1673 assert(instruction->value.type);1678 assert(instruction->value.type);
1674 render_const_val(g, &instruction->value, "");1679 render_const_val(g, &instruction->value, "");
...@@ -3786,6 +3791,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) {...@@ -3786,6 +3791,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) {
3786 case ScopeIdCompTime:3791 case ScopeIdCompTime:
3787 case ScopeIdRuntime:3792 case ScopeIdRuntime:
3788 case ScopeIdTypeOf:3793 case ScopeIdTypeOf:
3794 case ScopeIdExpr:
3789 scope = scope->parent;3795 scope = scope->parent;
3790 continue;3796 continue;
3791 }3797 }
...@@ -6049,6 +6055,11 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {...@@ -6049,6 +6055,11 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
6049 set_debug_location(g, instruction);6055 set_debug_location(g, instruction);
6050 }6056 }
6051 instruction->llvm_value = ir_render_instruction(g, executable, instruction);6057 instruction->llvm_value = ir_render_instruction(g, executable, instruction);
6058 if (instruction->spill != nullptr) {
6059 LLVMValueRef spill_ptr = ir_llvm_value(g, instruction->spill);
6060 gen_assign_raw(g, spill_ptr, instruction->spill->value.type, instruction->llvm_value);
6061 instruction->llvm_value = nullptr;
6062 }
6052 }6063 }
6053 current_block->llvm_exit_block = LLVMGetInsertBlock(g->builder);6064 current_block->llvm_exit_block = LLVMGetInsertBlock(g->builder);
6054 }6065 }
src/ir.cpp+11-1
...@@ -3364,6 +3364,7 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco...@@ -3364,6 +3364,7 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco
3364 case ScopeIdCompTime:3364 case ScopeIdCompTime:
3365 case ScopeIdRuntime:3365 case ScopeIdRuntime:
3366 case ScopeIdTypeOf:3366 case ScopeIdTypeOf:
3367 case ScopeIdExpr:
3367 scope = scope->parent;3368 scope = scope->parent;
3368 continue;3369 continue;
3369 case ScopeIdDeferExpr:3370 case ScopeIdDeferExpr:
...@@ -3420,6 +3421,7 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o...@@ -3420,6 +3421,7 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
3420 case ScopeIdCompTime:3421 case ScopeIdCompTime:
3421 case ScopeIdRuntime:3422 case ScopeIdRuntime:
3422 case ScopeIdTypeOf:3423 case ScopeIdTypeOf:
3424 case ScopeIdExpr:
3423 scope = scope->parent;3425 scope = scope->parent;
3424 continue;3426 continue;
3425 case ScopeIdDeferExpr:3427 case ScopeIdDeferExpr:
...@@ -8158,7 +8160,15 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc...@@ -8158,7 +8160,15 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc
8158 result_loc = no_result_loc();8160 result_loc = no_result_loc();
8159 ir_build_reset_result(irb, scope, node, result_loc);8161 ir_build_reset_result(irb, scope, node, result_loc);
8160 }8162 }
8161 IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc);8163 Scope *child_scope;
8164 if (irb->exec->is_inline ||
8165 (irb->exec->fn_entry != nullptr && irb->exec->fn_entry->child_scope == scope))
8166 {
8167 child_scope = scope;
8168 } else {
8169 child_scope = create_expr_scope(irb->codegen, node, scope);
8170 }
8171 IrInstruction *result = ir_gen_node_raw(irb, node, child_scope, lval, result_loc);
8162 if (result == irb->codegen->invalid_instruction) {8172 if (result == irb->codegen->invalid_instruction) {
8163 if (irb->exec->first_err_trace_msg == nullptr) {8173 if (irb->exec->first_err_trace_msg == nullptr) {
8164 irb->exec->first_err_trace_msg = irb->codegen->trace_err;8174 irb->exec->first_err_trace_msg = irb->codegen->trace_err;
std/event/future.zig+1-5
...@@ -104,11 +104,7 @@ fn testFuture(loop: *Loop) void {...@@ -104,11 +104,7 @@ fn testFuture(loop: *Loop) void {
104 var b = async waitOnFuture(&future);104 var b = async waitOnFuture(&future);
105 resolveFuture(&future);105 resolveFuture(&future);
106106
107 // TODO https://github.com/ziglang/zig/issues/3077107 const result = (await a) + (await b);
108 //const result = (await a) + (await b);
109 const a_result = await a;
110 const b_result = await b;
111 const result = a_result + b_result;
112108
113 testing.expect(result == 12);109 testing.expect(result == 12);
114}110}
test/stage1/behavior/async_fn.zig+20-8
...@@ -921,12 +921,10 @@ fn recursiveAsyncFunctionTest(comptime suspending_implementation: bool) type {...@@ -921,12 +921,10 @@ fn recursiveAsyncFunctionTest(comptime suspending_implementation: bool) type {
921 var sum: u32 = 0;921 var sum: u32 = 0;
922922
923 f1_awaited = true;923 f1_awaited = true;
924 const result_f1 = await f1; // TODO https://github.com/ziglang/zig/issues/3077924 sum += try await f1;
925 sum += try result_f1;
926925
927 f2_awaited = true;926 f2_awaited = true;
928 const result_f2 = await f2; // TODO https://github.com/ziglang/zig/issues/3077927 sum += try await f2;
929 sum += try result_f2;
930928
931 return sum;929 return sum;
932 }930 }
...@@ -943,8 +941,7 @@ fn recursiveAsyncFunctionTest(comptime suspending_implementation: bool) type {...@@ -943,8 +941,7 @@ fn recursiveAsyncFunctionTest(comptime suspending_implementation: bool) type {
943941
944 fn amain(result: *u32) void {942 fn amain(result: *u32) void {
945 var x = async fib(std.heap.direct_allocator, 10);943 var x = async fib(std.heap.direct_allocator, 10);
946 const res = await x; // TODO https://github.com/ziglang/zig/issues/3077944 result.* = (await x) catch unreachable;
947 result.* = res catch unreachable;
948 }945 }
949 };946 };
950}947}
...@@ -1002,8 +999,7 @@ test "@asyncCall using the result location inside the frame" {...@@ -1002,8 +999,7 @@ test "@asyncCall using the result location inside the frame" {
1002 return 1234;999 return 1234;
1003 }1000 }
1004 fn getAnswer(f: anyframe->i32, out: *i32) void {1001 fn getAnswer(f: anyframe->i32, out: *i32) void {
1005 var res = await f; // TODO https://github.com/ziglang/zig/issues/30771002 out.* = await f;
1006 out.* = res;
1007 }1003 }
1008 };1004 };
1009 var data: i32 = 1;1005 var data: i32 = 1;
...@@ -1124,3 +1120,19 @@ test "await used in expression and awaiting fn with no suspend but async calling...@@ -1124,3 +1120,19 @@ test "await used in expression and awaiting fn with no suspend but async calling
1124 };1120 };
1125 _ = async S.atest();1121 _ = async S.atest();
1126}1122}
1123
1124test "await used in expression after a fn call" {
1125 const S = struct {
1126 fn atest() void {
1127 var f1 = async add(3, 4);
1128 var sum: i32 = 0;
1129 sum = foo() + await f1;
1130 expect(sum == 8);
1131 }
1132 async fn add(a: i32, b: i32) i32 {
1133 return a + b;
1134 }
1135 fn foo() i32 { return 1; }
1136 };
1137 _ = async S.atest();
1138}