authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-30 20:06:02-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-30 20:06:02-04:00
log6ab8b2aab4b146a7d1d882686199eace19989011
tree8ef3d1b06c79982b3c8709d93b8b1db25be2eac2
parent2148943fff5af1e31f75b1e6651f0b7614e7e36a
signaturelock-open Commit is signed but in an unrecognized format.

support recursive async and non-async functions

which heap allocate their own frames related: #1006

9 files changed, 157 insertions(+), 23 deletions(-)

src/all_types.hpp+1-1
...@@ -627,7 +627,7 @@ struct AstNodeParamDecl {...@@ -627,7 +627,7 @@ struct AstNodeParamDecl {
627 AstNode *type;627 AstNode *type;
628 Token *var_token;628 Token *var_token;
629 bool is_noalias;629 bool is_noalias;
630 bool is_inline;630 bool is_comptime;
631 bool is_var_args;631 bool is_var_args;
632};632};
633633
src/analyze.cpp+5-2
...@@ -1556,7 +1556,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -1556,7 +1556,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
1556 AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index);1556 AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index);
1557 assert(param_node->type == NodeTypeParamDecl);1557 assert(param_node->type == NodeTypeParamDecl);
15581558
1559 bool param_is_comptime = param_node->data.param_decl.is_inline;1559 bool param_is_comptime = param_node->data.param_decl.is_comptime;
1560 bool param_is_var_args = param_node->data.param_decl.is_var_args;1560 bool param_is_var_args = param_node->data.param_decl.is_var_args;
15611561
1562 if (param_is_comptime) {1562 if (param_is_comptime) {
...@@ -8234,6 +8234,10 @@ static void resolve_llvm_types_anyerror(CodeGen *g) {...@@ -8234,6 +8234,10 @@ static void resolve_llvm_types_anyerror(CodeGen *g) {
8234}8234}
82358235
8236static void resolve_llvm_types_async_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) {8236static void resolve_llvm_types_async_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) {
8237 Error err;
8238 if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown)))
8239 zig_unreachable();
8240
8237 ZigType *passed_frame_type = fn_is_async(frame_type->data.frame.fn) ? frame_type : nullptr;8241 ZigType *passed_frame_type = fn_is_async(frame_type->data.frame.fn) ? frame_type : nullptr;
8238 resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, passed_frame_type);8242 resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, passed_frame_type);
8239 frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type;8243 frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type;
...@@ -8375,7 +8379,6 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re...@@ -8375,7 +8379,6 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re
8375}8379}
83768380
8377static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {8381static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {
8378 assert(type->id == ZigTypeIdOpaque || type_is_resolved(type, ResolveStatusSizeKnown));
8379 assert(wanted_resolve_status > ResolveStatusSizeKnown);8382 assert(wanted_resolve_status > ResolveStatusSizeKnown);
8380 switch (type->id) {8383 switch (type->id) {
8381 case ZigTypeIdInvalid:8384 case ZigTypeIdInvalid:
src/ast_render.cpp+1-1
...@@ -448,7 +448,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -448,7 +448,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
448 assert(param_decl->type == NodeTypeParamDecl);448 assert(param_decl->type == NodeTypeParamDecl);
449 if (param_decl->data.param_decl.name != nullptr) {449 if (param_decl->data.param_decl.name != nullptr) {
450 const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : "";450 const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : "";
451 const char *inline_str = param_decl->data.param_decl.is_inline ? "inline " : "";451 const char *inline_str = param_decl->data.param_decl.is_comptime ? "comptime " : "";
452 fprintf(ar->f, "%s%s", noalias_str, inline_str);452 fprintf(ar->f, "%s%s", noalias_str, inline_str);
453 print_symbol(ar, param_decl->data.param_decl.name);453 print_symbol(ar, param_decl->data.param_decl.name);
454 fprintf(ar->f, ": ");454 fprintf(ar->f, ": ");
src/codegen.cpp+5-2
...@@ -6340,9 +6340,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -6340,9 +6340,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6340 ZigType *type_entry = const_val->type;6340 ZigType *type_entry = const_val->type;
6341 assert(type_has_bits(type_entry));6341 assert(type_has_bits(type_entry));
63426342
6343 switch (const_val->special) {6343check: switch (const_val->special) {
6344 case ConstValSpecialLazy:6344 case ConstValSpecialLazy:
6345 zig_unreachable();6345 if ((err = ir_resolve_lazy(g, nullptr, const_val))) {
6346 report_errors_and_exit(g);
6347 }
6348 goto check;
6346 case ConstValSpecialRuntime:6349 case ConstValSpecialRuntime:
6347 zig_unreachable();6350 zig_unreachable();
6348 case ConstValSpecialUndef:6351 case ConstValSpecialUndef:
src/ir.cpp+68-15
...@@ -9012,7 +9012,42 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc...@@ -9012,7 +9012,42 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
9012 return false;9012 return false;
9013 }9013 }
90149014
9015 ConstExprValue *const_val = ir_resolve_const(ira, instruction, UndefBad);9015 ConstExprValue *const_val = ir_resolve_const(ira, instruction, LazyOkNoUndef);
9016 if (const_val == nullptr)
9017 return false;
9018
9019 if (const_val->special == ConstValSpecialLazy) {
9020 switch (const_val->data.x_lazy->id) {
9021 case LazyValueIdAlignOf: {
9022 // This is guaranteed to fit into a u29
9023 if (other_type->id == ZigTypeIdComptimeInt)
9024 return true;
9025 size_t align_bits = get_align_amt_type(ira->codegen)->data.integral.bit_count;
9026 if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed &&
9027 other_type->data.integral.bit_count >= align_bits)
9028 {
9029 return true;
9030 }
9031 break;
9032 }
9033 case LazyValueIdSizeOf: {
9034 // This is guaranteed to fit into a usize
9035 if (other_type->id == ZigTypeIdComptimeInt)
9036 return true;
9037 size_t usize_bits = ira->codegen->builtin_types.entry_usize->data.integral.bit_count;
9038 if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed &&
9039 other_type->data.integral.bit_count >= usize_bits)
9040 {
9041 return true;
9042 }
9043 break;
9044 }
9045 default:
9046 break;
9047 }
9048 }
9049
9050 const_val = ir_resolve_const(ira, instruction, UndefBad);
9016 if (const_val == nullptr)9051 if (const_val == nullptr)
9017 return false;9052 return false;
90189053
...@@ -10262,7 +10297,7 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_...@@ -10262,7 +10297,7 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_
10262 memcpy(dest, src, sizeof(ConstExprValue));10297 memcpy(dest, src, sizeof(ConstExprValue));
10263 if (!same_global_refs) {10298 if (!same_global_refs) {
10264 dest->global_refs = global_refs;10299 dest->global_refs = global_refs;
10265 if (src->special == ConstValSpecialUndef)10300 if (src->special != ConstValSpecialStatic)
10266 return;10301 return;
10267 if (dest->type->id == ZigTypeIdStruct) {10302 if (dest->type->id == ZigTypeIdStruct) {
10268 dest->data.x_struct.fields = create_const_vals(dest->type->data.structure.src_field_count);10303 dest->data.x_struct.fields = create_const_vals(dest->type->data.structure.src_field_count);
...@@ -11213,7 +11248,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi...@@ -11213,7 +11248,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
11213 return ira->codegen->invalid_instruction;11248 return ira->codegen->invalid_instruction;
1121411249
11215 if (instr_is_comptime(value)) {11250 if (instr_is_comptime(value)) {
11216 ConstExprValue *val = ir_resolve_const(ira, value, UndefOk);11251 ConstExprValue *val = ir_resolve_const(ira, value, LazyOk);
11217 if (!val)11252 if (!val)
11218 return ira->codegen->invalid_instruction;11253 return ira->codegen->invalid_instruction;
11219 return ir_get_const_ptr(ira, source_instruction, val, value->value.type,11254 return ir_get_const_ptr(ira, source_instruction, val, value->value.type,
...@@ -12125,7 +12160,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -12125,7 +12160,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
12125 if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) {12160 if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) {
12126 IrInstruction *result = ir_const(ira, source_instr, wanted_type);12161 IrInstruction *result = ir_const(ira, source_instr, wanted_type);
12127 if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) {12162 if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) {
12128 bigint_init_bigint(&result->value.data.x_bigint, &value->value.data.x_bigint);12163 copy_const_val(&result->value, &value->value, false);
12164 result->value.type = wanted_type;
12129 } else {12165 } else {
12130 float_init_bigint(&result->value.data.x_bigint, &value->value);12166 float_init_bigint(&result->value.data.x_bigint, &value->value);
12131 }12167 }
...@@ -15301,7 +15337,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod...@@ -15301,7 +15337,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
15301 }15337 }
15302 }15338 }
1530315339
15304 bool comptime_arg = param_decl_node->data.param_decl.is_inline ||15340 bool comptime_arg = param_decl_node->data.param_decl.is_comptime ||
15305 casted_arg->value.type->id == ZigTypeIdComptimeInt || casted_arg->value.type->id == ZigTypeIdComptimeFloat;15341 casted_arg->value.type->id == ZigTypeIdComptimeInt || casted_arg->value.type->id == ZigTypeIdComptimeFloat;
1530615342
15307 ConstExprValue *arg_val;15343 ConstExprValue *arg_val;
...@@ -17594,6 +17630,11 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc...@@ -17594,6 +17630,11 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
17594 ConstExprValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node);17630 ConstExprValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node);
17595 if (child_val == nullptr)17631 if (child_val == nullptr)
17596 return ira->codegen->invalid_instruction;17632 return ira->codegen->invalid_instruction;
17633 if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec,
17634 field_ptr_instruction->base.source_node, child_val, UndefBad)))
17635 {
17636 return ira->codegen->invalid_instruction;
17637 }
17597 ZigType *child_type = child_val->data.x_type;17638 ZigType *child_type = child_val->data.x_type;
1759817639
17599 if (type_is_invalid(child_type)) {17640 if (type_is_invalid(child_type)) {
...@@ -21293,8 +21334,10 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru...@@ -21293,8 +21334,10 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru
21293 src_ptr_align = get_abi_alignment(ira->codegen, target->value.type);21334 src_ptr_align = get_abi_alignment(ira->codegen, target->value.type);
21294 }21335 }
2129521336
21296 if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown)))21337 if (src_ptr_align != 0) {
21297 return ira->codegen->invalid_instruction;21338 if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusAlignmentKnown)))
21339 return ira->codegen->invalid_instruction;
21340 }
2129821341
21299 ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type,21342 ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type,
21300 src_ptr_const, src_ptr_volatile, PtrLenUnknown,21343 src_ptr_const, src_ptr_volatile, PtrLenUnknown,
...@@ -21337,6 +21380,8 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru...@@ -21337,6 +21380,8 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru
21337 }21380 }
2133821381
21339 if (have_known_len) {21382 if (have_known_len) {
21383 if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown)))
21384 return ira->codegen->invalid_instruction;
21340 uint64_t child_type_size = type_size(ira->codegen, dest_child_type);21385 uint64_t child_type_size = type_size(ira->codegen, dest_child_type);
21341 uint64_t remainder = known_len % child_type_size;21386 uint64_t remainder = known_len % child_type_size;
21342 if (remainder != 0) {21387 if (remainder != 0) {
...@@ -23963,15 +24008,23 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct...@@ -23963,15 +24008,23 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
23963}24008}
2396424009
23965static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) {24010static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) {
23966 uint32_t align_bytes;
23967 IrInstruction *align_bytes_inst = instruction->align_bytes->child;
23968 if (!ir_resolve_align(ira, align_bytes_inst, nullptr, &align_bytes))
23969 return ira->codegen->invalid_instruction;
23970
23971 IrInstruction *target = instruction->target->child;24011 IrInstruction *target = instruction->target->child;
23972 if (type_is_invalid(target->value.type))24012 if (type_is_invalid(target->value.type))
23973 return ira->codegen->invalid_instruction;24013 return ira->codegen->invalid_instruction;
2397424014
24015 ZigType *elem_type = nullptr;
24016 if (is_slice(target->value.type)) {
24017 ZigType *slice_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
24018 elem_type = slice_ptr_type->data.pointer.child_type;
24019 } else if (target->value.type->id == ZigTypeIdPointer) {
24020 elem_type = target->value.type->data.pointer.child_type;
24021 }
24022
24023 uint32_t align_bytes;
24024 IrInstruction *align_bytes_inst = instruction->align_bytes->child;
24025 if (!ir_resolve_align(ira, align_bytes_inst, elem_type, &align_bytes))
24026 return ira->codegen->invalid_instruction;
24027
23975 IrInstruction *result = ir_align_cast(ira, target, align_bytes, true);24028 IrInstruction *result = ir_align_cast(ira, target, align_bytes, true);
23976 if (type_is_invalid(result->value.type))24029 if (type_is_invalid(result->value.type))
23977 return ira->codegen->invalid_instruction;24030 return ira->codegen->invalid_instruction;
...@@ -25644,7 +25697,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {...@@ -25644,7 +25697,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
25644 }25697 }
2564525698
25646 val->special = ConstValSpecialStatic;25699 val->special = ConstValSpecialStatic;
25647 assert(val->type->id == ZigTypeIdComptimeInt);25700 assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);
25648 bigint_init_unsigned(&val->data.x_bigint, align_in_bytes);25701 bigint_init_unsigned(&val->data.x_bigint, align_in_bytes);
25649 return ErrorNone;25702 return ErrorNone;
25650 }25703 }
...@@ -25699,7 +25752,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {...@@ -25699,7 +25752,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
25699 }25752 }
2570025753
25701 val->special = ConstValSpecialStatic;25754 val->special = ConstValSpecialStatic;
25702 assert(val->type->id == ZigTypeIdComptimeInt);25755 assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);
25703 bigint_init_unsigned(&val->data.x_bigint, abi_size);25756 bigint_init_unsigned(&val->data.x_bigint, abi_size);
25704 return ErrorNone;25757 return ErrorNone;
25705 }25758 }
...@@ -25885,7 +25938,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {...@@ -25885,7 +25938,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
25885Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) {25938Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) {
25886 Error err;25939 Error err;
25887 if ((err = ir_resolve_lazy_raw(source_node, val))) {25940 if ((err = ir_resolve_lazy_raw(source_node, val))) {
25888 if (codegen->trace_err != nullptr && !source_node->already_traced_this_node) {25941 if (codegen->trace_err != nullptr && source_node != nullptr && !source_node->already_traced_this_node) {
25889 source_node->already_traced_this_node = true;25942 source_node->already_traced_this_node = true;
25890 codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node,25943 codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node,
25891 buf_create_from_str("referenced here"));25944 buf_create_from_str("referenced here"));
src/parser.cpp+1-1
...@@ -2075,7 +2075,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc) {...@@ -2075,7 +2075,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc) {
2075 res->column = first->start_column;2075 res->column = first->start_column;
2076 res->data.param_decl.name = token_buf(name);2076 res->data.param_decl.name = token_buf(name);
2077 res->data.param_decl.is_noalias = first->id == TokenIdKeywordNoAlias;2077 res->data.param_decl.is_noalias = first->id == TokenIdKeywordNoAlias;
2078 res->data.param_decl.is_inline = first->id == TokenIdKeywordCompTime;2078 res->data.param_decl.is_comptime = first->id == TokenIdKeywordCompTime;
2079 return res;2079 return res;
2080}2080}
20812081
std/mem.zig+9-1
...@@ -117,7 +117,15 @@ pub const Allocator = struct {...@@ -117,7 +117,15 @@ pub const Allocator = struct {
117 const byte_slice = try self.reallocFn(self, ([*]u8)(undefined)[0..0], undefined, byte_count, a);117 const byte_slice = try self.reallocFn(self, ([*]u8)(undefined)[0..0], undefined, byte_count, a);
118 assert(byte_slice.len == byte_count);118 assert(byte_slice.len == byte_count);
119 @memset(byte_slice.ptr, undefined, byte_slice.len);119 @memset(byte_slice.ptr, undefined, byte_slice.len);
120 return @bytesToSlice(T, @alignCast(a, byte_slice));120 if (alignment == null) {
121 // TODO This is a workaround for zig not being able to successfully do
122 // @bytesToSlice(T, @alignCast(a, byte_slice)) without resolving alignment of T,
123 // which causes a circular dependency in async functions which try to heap-allocate
124 // their own frame with @Frame(func).
125 return @intToPtr([*]T, @ptrToInt(byte_slice.ptr))[0..n];
126 } else {
127 return @bytesToSlice(T, @alignCast(a, byte_slice));
128 }
121 }129 }
122130
123 /// This function requests a new byte size for an existing allocation,131 /// This function requests a new byte size for an existing allocation,
test/compile_errors.zig+2
...@@ -1051,6 +1051,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1051,6 +1051,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1051 \\const Foo = struct {};1051 \\const Foo = struct {};
1052 \\export fn a() void {1052 \\export fn a() void {
1053 \\ const T = [*c]Foo;1053 \\ const T = [*c]Foo;
1054 \\ var t: T = undefined;
1054 \\}1055 \\}
1055 ,1056 ,
1056 "tmp.zig:3:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",1057 "tmp.zig:3:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",
...@@ -2290,6 +2291,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2290,6 +2291,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2290 "error union operator with non error set LHS",2291 "error union operator with non error set LHS",
2291 \\comptime {2292 \\comptime {
2292 \\ const z = i32!i32;2293 \\ const z = i32!i32;
2294 \\ var x: z = undefined;
2293 \\}2295 \\}
2294 ,2296 ,
2295 "tmp.zig:2:15: error: expected error set type, found type 'i32'",2297 "tmp.zig:2:15: error: expected error set type, found type 'i32'",
test/stage1/behavior/async_fn.zig+65
...@@ -854,3 +854,68 @@ test "await does not force async if callee is blocking" {...@@ -854,3 +854,68 @@ test "await does not force async if callee is blocking" {
854 var x = async S.simple();854 var x = async S.simple();
855 expect(await x == 1234);855 expect(await x == 1234);
856}856}
857
858test "recursive async function" {
859 expect(recursiveAsyncFunctionTest(false).doTheTest() == 55);
860 expect(recursiveAsyncFunctionTest(true).doTheTest() == 55);
861}
862
863fn recursiveAsyncFunctionTest(comptime suspending_implementation: bool) type {
864 return struct {
865 fn fib(allocator: *std.mem.Allocator, x: u32) error{OutOfMemory}!u32 {
866 if (x <= 1) return x;
867
868 if (suspending_implementation) {
869 suspend {
870 resume @frame();
871 }
872 }
873
874 const f1 = try allocator.create(@Frame(fib));
875 defer allocator.destroy(f1);
876
877 const f2 = try allocator.create(@Frame(fib));
878 defer allocator.destroy(f2);
879
880 f1.* = async fib(allocator, x - 1);
881 var f1_awaited = false;
882 errdefer if (!f1_awaited) {
883 _ = await f1;
884 };
885
886 f2.* = async fib(allocator, x - 2);
887 var f2_awaited = false;
888 errdefer if (!f2_awaited) {
889 _ = await f2;
890 };
891
892 var sum: u32 = 0;
893
894 f1_awaited = true;
895 const result_f1 = await f1; // TODO https://github.com/ziglang/zig/issues/3077
896 sum += try result_f1;
897
898 f2_awaited = true;
899 const result_f2 = await f2; // TODO https://github.com/ziglang/zig/issues/3077
900 sum += try result_f2;
901
902 return sum;
903 }
904
905 fn doTheTest() u32 {
906 if (suspending_implementation) {
907 var result: u32 = undefined;
908 _ = async amain(&result);
909 return result;
910 } else {
911 return fib(std.heap.direct_allocator, 10) catch unreachable;
912 }
913 }
914
915 fn amain(result: *u32) void {
916 var x = async fib(std.heap.direct_allocator, 10);
917 const res = await x; // TODO https://github.com/ziglang/zig/issues/3077
918 result.* = res catch unreachable;
919 }
920 };
921}