Skip to content

Commit a06f3c7

Browse files
committed
parse async fn definitions
See #727
1 parent 3d58d72 commit a06f3c7

File tree

7 files changed

+53
-13
lines changed

7 files changed

+53
-13
lines changed

doc/langref.html.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5645,7 +5645,7 @@ UseDecl = "use" Expression ";"
56455645

56465646
ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
56475647

5648-
FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
5648+
FnProto = option("nakedcc" | "stdcallcc" | "extern" | "async") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
56495649

56505650
FnDef = option("inline" | "export") FnProto Block
56515651

src/all_types.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@ enum CallingConvention {
406406
CallingConventionCold,
407407
CallingConventionNaked,
408408
CallingConventionStdcall,
409+
CallingConventionAsync,
409410
};
410411

411412
struct AstNodeFnProto {
@@ -2152,6 +2153,8 @@ struct IrInstructionCall {
21522153
bool is_comptime;
21532154
LLVMValueRef tmp_ptr;
21542155
FnInline fn_inline;
2156+
bool is_async;
2157+
IrInstruction *async_allocator;
21552158
};
21562159

21572160
struct IrInstructionConst {

src/analyze.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,7 @@ static const char *calling_convention_name(CallingConvention cc) {
884884
case CallingConventionCold: return "coldcc";
885885
case CallingConventionNaked: return "nakedcc";
886886
case CallingConventionStdcall: return "stdcallcc";
887+
case CallingConventionAsync: return "async";
887888
}
888889
zig_unreachable();
889890
}
@@ -895,6 +896,7 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {
895896
case CallingConventionCold: return "coldcc ";
896897
case CallingConventionNaked: return "nakedcc ";
897898
case CallingConventionStdcall: return "stdcallcc ";
899+
case CallingConventionAsync: return "async ";
898900
}
899901
zig_unreachable();
900902
}

src/codegen.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,8 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
381381
} else {
382382
return LLVMCCallConv;
383383
}
384+
case CallingConventionAsync:
385+
return LLVMFastCallConv;
384386
}
385387
zig_unreachable();
386388
}

src/ir.cpp

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,7 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
986986

987987
static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
988988
FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
989-
bool is_comptime, FnInline fn_inline)
989+
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
990990
{
991991
IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
992992
call_instruction->fn_entry = fn_entry;
@@ -995,21 +995,25 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
995995
call_instruction->fn_inline = fn_inline;
996996
call_instruction->args = args;
997997
call_instruction->arg_count = arg_count;
998+
call_instruction->is_async = is_async;
999+
call_instruction->async_allocator = async_allocator;
9981000

9991001
if (fn_ref)
10001002
ir_ref_instruction(fn_ref, irb->current_basic_block);
10011003
for (size_t i = 0; i < arg_count; i += 1)
10021004
ir_ref_instruction(args[i], irb->current_basic_block);
1005+
if (async_allocator)
1006+
ir_ref_instruction(async_allocator, irb->current_basic_block);
10031007

10041008
return &call_instruction->base;
10051009
}
10061010

10071011
static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
10081012
FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1009-
bool is_comptime, FnInline fn_inline)
1013+
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
10101014
{
10111015
IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,
1012-
old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline);
1016+
old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator);
10131017
ir_link_new_instruction(new_instruction, old_instruction);
10141018
return new_instruction;
10151019
}
@@ -3754,7 +3758,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37543758
}
37553759
FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
37563760

3757-
return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline);
3761+
return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr);
37583762
}
37593763
case BuiltinFnIdTypeId:
37603764
{
@@ -3888,11 +3892,17 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
38883892
return args[i];
38893893
}
38903894

3891-
if (node->data.fn_call_expr.is_async) {
3892-
zig_panic("TODO ir_gen_fn_call for async fn calls");
3895+
bool is_async = node->data.fn_call_expr.is_async;
3896+
IrInstruction *async_allocator = nullptr;
3897+
if (is_async) {
3898+
if (node->data.fn_call_expr.async_allocator) {
3899+
async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope);
3900+
if (async_allocator == irb->codegen->invalid_instruction)
3901+
return async_allocator;
3902+
}
38933903
}
38943904

3895-
return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto);
3905+
return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator);
38963906
}
38973907

38983908
static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -10584,6 +10594,11 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
1058410594
buf_sprintf("exported function must specify calling convention"));
1058510595
add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here"));
1058610596
} break;
10597+
case CallingConventionAsync: {
10598+
ErrorMsg *msg = ir_add_error(ira, target,
10599+
buf_sprintf("exported function cannot be async"));
10600+
add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here"));
10601+
} break;
1058710602
case CallingConventionC:
1058810603
case CallingConventionNaked:
1058910604
case CallingConventionCold:
@@ -10963,6 +10978,13 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1096310978
}
1096410979
return ira->codegen->builtin_types.entry_invalid;
1096510980
}
10981+
if (fn_type_id->cc == CallingConventionAsync && !call_instruction->is_async) {
10982+
ErrorMsg *msg = ir_add_error(ira, fn_ref, buf_sprintf("must use async keyword to call async function"));
10983+
if (fn_proto_node) {
10984+
add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("declared here"));
10985+
}
10986+
return ira->codegen->builtin_types.entry_invalid;
10987+
}
1096610988

1096710989

1096810990
if (fn_type_id->is_var_args) {
@@ -11258,7 +11280,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1125811280

1125911281
size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;
1126011282
IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
11261-
impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline);
11283+
impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline, false, nullptr);
1126211284

1126311285
TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
1126411286
ir_add_alloca(ira, new_call_instruction, return_type);
@@ -11324,12 +11346,16 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1132411346

1132511347
assert(next_arg_index == call_param_count);
1132611348

11349+
if (call_instruction->is_async) {
11350+
zig_panic("TODO handle async fn call");
11351+
}
11352+
1132711353
TypeTableEntry *return_type = fn_type_id->return_type;
1132811354
if (type_is_invalid(return_type))
1132911355
return ira->codegen->builtin_types.entry_invalid;
1133011356

1133111357
IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
11332-
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline);
11358+
fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr);
1133311359

1133411360
ir_add_alloca(ira, new_call_instruction, return_type);
1133511361
return ir_finish_anal(ira, return_type);
@@ -16491,7 +16517,10 @@ static TypeTableEntry *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruc
1649116517
}
1649216518

1649316519
static TypeTableEntry *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructionCancel *instruction) {
16494-
IrInstruction *casted_target = ir_implicit_cast(ira, instruction->target->other, ira->codegen->builtin_types.entry_promise);
16520+
IrInstruction *target_inst = instruction->target->other;
16521+
if (type_is_invalid(target_inst->value.type))
16522+
return ira->codegen->builtin_types.entry_invalid;
16523+
IrInstruction *casted_target = ir_implicit_cast(ira, target_inst, ira->codegen->builtin_types.entry_promise);
1649516524
if (type_is_invalid(casted_target->value.type))
1649616525
return ira->codegen->builtin_types.entry_invalid;
1649716526

src/parser.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2333,7 +2333,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
23332333
}
23342334

23352335
/*
2336-
FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
2336+
FnProto = option("nakedcc" | "stdcallcc" | "extern" | "async") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
23372337
*/
23382338
static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
23392339
Token *first_token = &pc->tokens->at(*token_index);
@@ -2345,6 +2345,10 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
23452345
*token_index += 1;
23462346
fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
23472347
cc = CallingConventionNaked;
2348+
} else if (first_token->id == TokenIdKeywordAsync) {
2349+
*token_index += 1;
2350+
fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
2351+
cc = CallingConventionAsync;
23482352
} else if (first_token->id == TokenIdKeywordStdcallCC) {
23492353
*token_index += 1;
23502354
fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);

std/mem.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ pub const Allocator = struct {
124124
return self.allocator.allocFn(self.allocator, byte_count, alignment);
125125
}
126126

127-
fn free(self: &const AsyncAllocator, old_mem: []u8) {
127+
fn free(self: &const AsyncAllocator, old_mem: []u8) void {
128128
return self.allocator.freeFn(self.allocator, old_mem);
129129
}
130130
};

0 commit comments

Comments
 (0)