authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-10 11:44:47-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-10 11:44:47-04:00
log0ce6934e2631eb3beca817d3bce12ecb13aafa13
tree52c4d0a9e9f5d227859e8691f7a165500c90e3fd
parent696ef0bc03ccbe61dff5b09a257c2de7b227290a

allow var args calls to async functions


2 files changed, 85 insertions(+), 20 deletions(-)

src/ir.cpp+33-20
...@@ -12721,14 +12721,22 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12721,14 +12721,22 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
12721 // for extern functions, the var args argument is not counted.12721 // for extern functions, the var args argument is not counted.
12722 // for zig functions, it is.12722 // for zig functions, it is.
12723 size_t var_args_1_or_0;12723 size_t var_args_1_or_0;
12724 if (fn_type_id->cc == CallingConventionUnspecified) {12724 if (fn_type_id->cc == CallingConventionC) {
12725 var_args_1_or_0 = fn_type_id->is_var_args ? 1 : 0;
12726 } else {
12727 var_args_1_or_0 = 0;12725 var_args_1_or_0 = 0;
12726 } else {
12727 var_args_1_or_0 = fn_type_id->is_var_args ? 1 : 0;
12728 }12728 }
12729 size_t src_param_count = fn_type_id->param_count - var_args_1_or_0;12729 size_t src_param_count = fn_type_id->param_count - var_args_1_or_0;
1273012730
12731 size_t call_param_count = call_instruction->arg_count + first_arg_1_or_0;12731 size_t call_param_count = call_instruction->arg_count + first_arg_1_or_0;
12732 for (size_t i = 0; i < call_instruction->arg_count; i += 1) {
12733 ConstExprValue *arg_tuple_value = &call_instruction->args[i]->other->value;
12734 if (arg_tuple_value->type->id == TypeTableEntryIdArgTuple) {
12735 call_param_count -= 1;
12736 call_param_count += arg_tuple_value->data.x_arg_tuple.end_index -
12737 arg_tuple_value->data.x_arg_tuple.start_index;
12738 }
12739 }
12732 AstNode *source_node = call_instruction->base.source_node;12740 AstNode *source_node = call_instruction->base.source_node;
1273312741
12734 AstNode *fn_proto_node = fn_entry ? fn_entry->proto_node : nullptr;;12742 AstNode *fn_proto_node = fn_entry ? fn_entry->proto_node : nullptr;;
...@@ -12909,11 +12917,6 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12909,11 +12917,6 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
12909 buf_sprintf("calling a generic function requires compile-time known function value"));12917 buf_sprintf("calling a generic function requires compile-time known function value"));
12910 return ira->codegen->builtin_types.entry_invalid;12918 return ira->codegen->builtin_types.entry_invalid;
12911 }12919 }
12912 if (call_instruction->is_async && fn_type_id->is_var_args) {
12913 ir_add_error(ira, call_instruction->fn_ref,
12914 buf_sprintf("compiler bug: TODO: implement var args async functions. https://github.com/ziglang/zig/issues/557"));
12915 return ira->codegen->builtin_types.entry_invalid;
12916 }
1291712920
12918 // Count the arguments of the function type id we are creating12921 // Count the arguments of the function type id we are creating
12919 size_t new_fn_arg_count = first_arg_1_or_0;12922 size_t new_fn_arg_count = first_arg_1_or_0;
...@@ -12988,18 +12991,18 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12988,18 +12991,18 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
12988 if (type_is_invalid(arg->value.type))12991 if (type_is_invalid(arg->value.type))
12989 return ira->codegen->builtin_types.entry_invalid;12992 return ira->codegen->builtin_types.entry_invalid;
1299012993
12991 AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(next_proto_i);
12992 assert(param_decl_node->type == NodeTypeParamDecl);
12993 bool is_var_args = param_decl_node->data.param_decl.is_var_args;
12994 if (is_var_args && !found_first_var_arg) {
12995 first_var_arg = inst_fn_type_id.param_count;
12996 found_first_var_arg = true;
12997 }
12998
12999 if (arg->value.type->id == TypeTableEntryIdArgTuple) {12994 if (arg->value.type->id == TypeTableEntryIdArgTuple) {
13000 for (size_t arg_tuple_i = arg->value.data.x_arg_tuple.start_index;12995 for (size_t arg_tuple_i = arg->value.data.x_arg_tuple.start_index;
13001 arg_tuple_i < arg->value.data.x_arg_tuple.end_index; arg_tuple_i += 1)12996 arg_tuple_i < arg->value.data.x_arg_tuple.end_index; arg_tuple_i += 1)
13002 {12997 {
12998 AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(next_proto_i);
12999 assert(param_decl_node->type == NodeTypeParamDecl);
13000 bool is_var_args = param_decl_node->data.param_decl.is_var_args;
13001 if (is_var_args && !found_first_var_arg) {
13002 first_var_arg = inst_fn_type_id.param_count;
13003 found_first_var_arg = true;
13004 }
13005
13003 VariableTableEntry *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);13006 VariableTableEntry *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
13004 if (arg_var == nullptr) {13007 if (arg_var == nullptr) {
13005 ir_add_error(ira, arg,13008 ir_add_error(ira, arg,
...@@ -13020,10 +13023,20 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -13020,10 +13023,20 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
13020 return ira->codegen->builtin_types.entry_invalid;13023 return ira->codegen->builtin_types.entry_invalid;
13021 }13024 }
13022 }13025 }
13023 } else if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope,13026 } else {
13024 &next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn))13027 AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(next_proto_i);
13025 {13028 assert(param_decl_node->type == NodeTypeParamDecl);
13026 return ira->codegen->builtin_types.entry_invalid;13029 bool is_var_args = param_decl_node->data.param_decl.is_var_args;
13030 if (is_var_args && !found_first_var_arg) {
13031 first_var_arg = inst_fn_type_id.param_count;
13032 found_first_var_arg = true;
13033 }
13034
13035 if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope,
13036 &next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn))
13037 {
13038 return ira->codegen->builtin_types.entry_invalid;
13039 }
13027 }13040 }
13028 }13041 }
1302913042
std/event/loop.zig+52
...@@ -360,6 +360,28 @@ pub const Loop = struct {...@@ -360,6 +360,28 @@ pub const Loop = struct {
360 }360 }
361 }361 }
362362
363 /// This is equivalent to an async call, except instead of beginning execution of the async function,
364 /// it immediately returns to the caller, and the async function is queued in the event loop. It still
365 /// returns a promise to be awaited.
366 pub fn call(self: *Loop, comptime func: var, args: ...) !(promise->@typeOf(func).ReturnType) {
367 const S = struct {
368 async fn asyncFunc(loop: *Loop, handle: *promise->@typeOf(func).ReturnType, args2: ...) @typeOf(func).ReturnType {
369 suspend |p| {
370 handle.* = p;
371 var my_tick_node = Loop.NextTickNode{
372 .next = undefined,
373 .data = p,
374 };
375 loop.onNextTick(&my_tick_node);
376 }
377 // TODO guaranteed allocation elision for await in same func as async
378 return await (async func(args2) catch unreachable);
379 }
380 };
381 var handle: promise->@typeOf(func).ReturnType = undefined;
382 return async<self.allocator> S.asyncFunc(self, &handle, args);
383 }
384
363 fn workerRun(self: *Loop) void {385 fn workerRun(self: *Loop) void {
364 start_over: while (true) {386 start_over: while (true) {
365 if (@atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) == 0) {387 if (@atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) == 0) {
...@@ -575,3 +597,33 @@ test "std.event.Loop - basic" {...@@ -575,3 +597,33 @@ test "std.event.Loop - basic" {
575597
576 loop.run();598 loop.run();
577}599}
600
601test "std.event.Loop - call" {
602 var da = std.heap.DirectAllocator.init();
603 defer da.deinit();
604
605 const allocator = &da.allocator;
606
607 var loop: Loop = undefined;
608 try loop.initMultiThreaded(allocator);
609 defer loop.deinit();
610
611 var did_it = false;
612 const handle = try loop.call(testEventLoop);
613 const handle2 = try loop.call(testEventLoop2, handle, &did_it);
614 defer cancel handle2;
615
616 loop.run();
617
618 assert(did_it);
619}
620
621async fn testEventLoop() i32 {
622 return 1234;
623}
624
625async fn testEventLoop2(h: promise->i32, did_it: *bool) void {
626 const value = await h;
627 assert(value == 1234);
628 did_it.* = true;
629}