Skip to content

Commit 0ce6934

Browse files
committedJul 10, 2018
allow var args calls to async functions
·
0.15.10.3.0
1 parent 696ef0b commit 0ce6934

File tree

2 files changed

+85
-20
lines changed

2 files changed

+85
-20
lines changed
 

‎src/ir.cpp‎

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12721,14 +12721,22 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1272112721
// for extern functions, the var args argument is not counted.
1272212722
// for zig functions, it is.
1272312723
size_t var_args_1_or_0;
12724-
if (fn_type_id->cc == CallingConventionUnspecified) {
12725-
var_args_1_or_0 = fn_type_id->is_var_args ? 1 : 0;
12726-
} else {
12724+
if (fn_type_id->cc == CallingConventionC) {
1272712725
var_args_1_or_0 = 0;
12726+
} else {
12727+
var_args_1_or_0 = fn_type_id->is_var_args ? 1 : 0;
1272812728
}
1272912729
size_t src_param_count = fn_type_id->param_count - var_args_1_or_0;
1273012730

1273112731
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+
}
1273212740
AstNode *source_node = call_instruction->base.source_node;
1273312741

1273412742
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
1290912917
buf_sprintf("calling a generic function requires compile-time known function value"));
1291012918
return ira->codegen->builtin_types.entry_invalid;
1291112919
}
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

1291812921
// Count the arguments of the function type id we are creating
1291912922
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
1298812991
if (type_is_invalid(arg->value.type))
1298912992
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-
1299912994
if (arg->value.type->id == TypeTableEntryIdArgTuple) {
1300012995
for (size_t arg_tuple_i = arg->value.data.x_arg_tuple.start_index;
1300112996
arg_tuple_i < arg->value.data.x_arg_tuple.end_index; arg_tuple_i += 1)
1300212997
{
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+
1300313006
VariableTableEntry *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
1300413007
if (arg_var == nullptr) {
1300513008
ir_add_error(ira, arg,
@@ -13020,10 +13023,20 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1302013023
return ira->codegen->builtin_types.entry_invalid;
1302113024
}
1302213025
}
13023-
} else if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope,
13024-
&next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn))
13025-
{
13026-
return ira->codegen->builtin_types.entry_invalid;
13026+
} else {
13027+
AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(next_proto_i);
13028+
assert(param_decl_node->type == NodeTypeParamDecl);
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+
}
1302713040
}
1302813041
}
1302913042

‎std/event/loop.zig‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,28 @@ pub const Loop = struct {
360360
}
361361
}
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+
363385
fn workerRun(self: *Loop) void {
364386
start_over: while (true) {
365387
if (@atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) == 0) {
@@ -575,3 +597,33 @@ test "std.event.Loop - basic" {
575597

576598
loop.run();
577599
}
600+
601+
test "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+
621+
async fn testEventLoop() i32 {
622+
return 1234;
623+
}
624+
625+
async fn testEventLoop2(h: promise->i32, did_it: *bool) void {
626+
const value = await h;
627+
assert(value == 1234);
628+
did_it.* = true;
629+
}

0 commit comments

Comments
 (0)
Please sign in to comment.