mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 00:08:56 +00:00
parent
53588f4f12
commit
7a99d63c76
@ -5739,7 +5739,7 @@ UseDecl = "use" Expression ";"
|
||||
|
||||
ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
|
||||
|
||||
FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("(" Expression ")"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var")
|
||||
FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("<" Expression ">"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var")
|
||||
|
||||
FnDef = option("inline" | "export") FnProto Block
|
||||
|
||||
|
||||
@ -2673,6 +2673,7 @@ struct IrInstructionFnProto {
|
||||
IrInstruction **param_types;
|
||||
IrInstruction *align_value;
|
||||
IrInstruction *return_type;
|
||||
IrInstruction *async_allocator_type_value;
|
||||
bool is_var_args;
|
||||
};
|
||||
|
||||
|
||||
@ -985,7 +985,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
|
||||
// populate the name of the type
|
||||
buf_resize(&fn_type->name, 0);
|
||||
if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
|
||||
buf_appendf(&fn_type->name, "async(%s) ", buf_ptr(&fn_type_id->async_allocator_type->name));
|
||||
assert(fn_type_id->async_allocator_type != nullptr);
|
||||
buf_appendf(&fn_type->name, "async<%s> ", buf_ptr(&fn_type_id->async_allocator_type->name));
|
||||
} else {
|
||||
const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
|
||||
buf_appendf(&fn_type->name, "%s", cc_str);
|
||||
|
||||
22
src/ir.cpp
22
src/ir.cpp
@ -2141,12 +2141,14 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type, bool is_var_args)
|
||||
IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type,
|
||||
IrInstruction *async_allocator_type_value, bool is_var_args)
|
||||
{
|
||||
IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
|
||||
instruction->param_types = param_types;
|
||||
instruction->align_value = align_value;
|
||||
instruction->return_type = return_type;
|
||||
instruction->async_allocator_type_value = async_allocator_type_value;
|
||||
instruction->is_var_args = is_var_args;
|
||||
|
||||
assert(source_node->type == NodeTypeFnProto);
|
||||
@ -2156,6 +2158,7 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s
|
||||
if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);
|
||||
}
|
||||
if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);
|
||||
if (async_allocator_type_value != nullptr) ir_ref_instruction(async_allocator_type_value, irb->current_basic_block);
|
||||
ir_ref_instruction(return_type, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
@ -5989,7 +5992,15 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
|
||||
return_type = nullptr;
|
||||
}
|
||||
|
||||
return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args);
|
||||
IrInstruction *async_allocator_type_value = nullptr;
|
||||
if (node->data.fn_proto.async_allocator_type != nullptr) {
|
||||
async_allocator_type_value = ir_gen_node(irb, node->data.fn_proto.async_allocator_type, parent_scope);
|
||||
if (async_allocator_type_value == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type,
|
||||
async_allocator_type_value, is_var_args);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
|
||||
@ -16561,6 +16572,13 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
|
||||
if (type_is_invalid(fn_type_id.return_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (fn_type_id.cc == CallingConventionAsync) {
|
||||
IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->other;
|
||||
fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);
|
||||
if (type_is_invalid(fn_type_id.async_allocator_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_type = get_fn_type(ira->codegen, &fn_type_id);
|
||||
return ira->codegen->builtin_types.entry_type;
|
||||
|
||||
126
src/parser.cpp
126
src/parser.cpp
@ -955,6 +955,66 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde
|
||||
}
|
||||
}
|
||||
|
||||
static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index, Token *fn_token,
|
||||
AstNode *async_allocator_type_node, CallingConvention cc, bool is_extern, VisibMod visib_mod)
|
||||
{
|
||||
AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);
|
||||
node->data.fn_proto.visib_mod = visib_mod;
|
||||
node->data.fn_proto.cc = cc;
|
||||
node->data.fn_proto.is_extern = is_extern;
|
||||
node->data.fn_proto.async_allocator_type = async_allocator_type_node;
|
||||
|
||||
Token *fn_name = &pc->tokens->at(*token_index);
|
||||
|
||||
if (fn_name->id == TokenIdSymbol) {
|
||||
*token_index += 1;
|
||||
node->data.fn_proto.name = token_buf(fn_name);
|
||||
} else {
|
||||
node->data.fn_proto.name = nullptr;
|
||||
}
|
||||
|
||||
ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
|
||||
|
||||
Token *next_token = &pc->tokens->at(*token_index);
|
||||
if (next_token->id == TokenIdKeywordAlign) {
|
||||
*token_index += 1;
|
||||
ast_eat_token(pc, token_index, TokenIdLParen);
|
||||
|
||||
node->data.fn_proto.align_expr = ast_parse_expression(pc, token_index, true);
|
||||
ast_eat_token(pc, token_index, TokenIdRParen);
|
||||
next_token = &pc->tokens->at(*token_index);
|
||||
}
|
||||
if (next_token->id == TokenIdKeywordSection) {
|
||||
*token_index += 1;
|
||||
ast_eat_token(pc, token_index, TokenIdLParen);
|
||||
|
||||
node->data.fn_proto.section_expr = ast_parse_expression(pc, token_index, true);
|
||||
ast_eat_token(pc, token_index, TokenIdRParen);
|
||||
next_token = &pc->tokens->at(*token_index);
|
||||
}
|
||||
if (next_token->id == TokenIdKeywordVar) {
|
||||
node->data.fn_proto.return_var_token = next_token;
|
||||
*token_index += 1;
|
||||
next_token = &pc->tokens->at(*token_index);
|
||||
} else {
|
||||
if (next_token->id == TokenIdKeywordError) {
|
||||
Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1);
|
||||
if (maybe_lbrace_tok->id == TokenIdLBrace) {
|
||||
*token_index += 1;
|
||||
node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token);
|
||||
return node;
|
||||
}
|
||||
} else if (next_token->id == TokenIdBang) {
|
||||
*token_index += 1;
|
||||
node->data.fn_proto.auto_err_set = true;
|
||||
next_token = &pc->tokens->at(*token_index);
|
||||
}
|
||||
node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
|
||||
FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
|
||||
@ -979,6 +1039,11 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
|
||||
}
|
||||
|
||||
Token *fncall_token = &pc->tokens->at(*token_index);
|
||||
if (fncall_token->id == TokenIdKeywordFn) {
|
||||
*token_index += 1;
|
||||
return ast_parse_fn_proto_partial(pc, token_index, fncall_token, allocator_expr_node, CallingConventionAsync,
|
||||
false, VisibModPrivate);
|
||||
}
|
||||
AstNode *node = ast_parse_suffix_op_expr(pc, token_index, true);
|
||||
if (node->type != NodeTypeFnCallExpr) {
|
||||
ast_error(pc, fncall_token, "expected function call, found '%s'", token_name(fncall_token->id));
|
||||
@ -2434,9 +2499,10 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
|
||||
} else if (first_token->id == TokenIdKeywordAsync) {
|
||||
*token_index += 1;
|
||||
Token *next_token = &pc->tokens->at(*token_index);
|
||||
if (next_token->id == TokenIdLParen) {
|
||||
if (next_token->id == TokenIdCmpLessThan) {
|
||||
*token_index += 1;
|
||||
async_allocator_type_node = ast_parse_type_expr(pc, token_index, true);
|
||||
ast_eat_token(pc, token_index, TokenIdRParen);
|
||||
ast_eat_token(pc, token_index, TokenIdCmpGreaterThan);
|
||||
}
|
||||
fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
|
||||
cc = CallingConventionAsync;
|
||||
@ -2470,61 +2536,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);
|
||||
node->data.fn_proto.visib_mod = visib_mod;
|
||||
node->data.fn_proto.cc = cc;
|
||||
node->data.fn_proto.is_extern = is_extern;
|
||||
node->data.fn_proto.async_allocator_type = async_allocator_type_node;
|
||||
|
||||
Token *fn_name = &pc->tokens->at(*token_index);
|
||||
|
||||
if (fn_name->id == TokenIdSymbol) {
|
||||
*token_index += 1;
|
||||
node->data.fn_proto.name = token_buf(fn_name);
|
||||
} else {
|
||||
node->data.fn_proto.name = nullptr;
|
||||
}
|
||||
|
||||
ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
|
||||
|
||||
Token *next_token = &pc->tokens->at(*token_index);
|
||||
if (next_token->id == TokenIdKeywordAlign) {
|
||||
*token_index += 1;
|
||||
ast_eat_token(pc, token_index, TokenIdLParen);
|
||||
|
||||
node->data.fn_proto.align_expr = ast_parse_expression(pc, token_index, true);
|
||||
ast_eat_token(pc, token_index, TokenIdRParen);
|
||||
next_token = &pc->tokens->at(*token_index);
|
||||
}
|
||||
if (next_token->id == TokenIdKeywordSection) {
|
||||
*token_index += 1;
|
||||
ast_eat_token(pc, token_index, TokenIdLParen);
|
||||
|
||||
node->data.fn_proto.section_expr = ast_parse_expression(pc, token_index, true);
|
||||
ast_eat_token(pc, token_index, TokenIdRParen);
|
||||
next_token = &pc->tokens->at(*token_index);
|
||||
}
|
||||
if (next_token->id == TokenIdKeywordVar) {
|
||||
node->data.fn_proto.return_var_token = next_token;
|
||||
*token_index += 1;
|
||||
next_token = &pc->tokens->at(*token_index);
|
||||
} else {
|
||||
if (next_token->id == TokenIdKeywordError) {
|
||||
Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1);
|
||||
if (maybe_lbrace_tok->id == TokenIdLBrace) {
|
||||
*token_index += 1;
|
||||
node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token);
|
||||
return node;
|
||||
}
|
||||
} else if (next_token->id == TokenIdBang) {
|
||||
*token_index += 1;
|
||||
node->data.fn_proto.auto_err_set = true;
|
||||
next_token = &pc->tokens->at(*token_index);
|
||||
}
|
||||
node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true);
|
||||
}
|
||||
|
||||
return node;
|
||||
return ast_parse_fn_proto_partial(pc, token_index, fn_token, async_allocator_type_node, cc, is_extern, visib_mod);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -156,3 +156,23 @@ test "async function with dot syntax" {
|
||||
cancel p;
|
||||
assert(S.y == 2);
|
||||
}
|
||||
|
||||
test "async fn pointer in a struct field" {
|
||||
var data: i32 = 1;
|
||||
const Foo = struct {
|
||||
bar: async<&std.mem.Allocator> fn(&i32) void,
|
||||
};
|
||||
var foo = Foo {
|
||||
.bar = simpleAsyncFn2,
|
||||
};
|
||||
const p = (async<std.debug.global_allocator> foo.bar(&data)) catch unreachable;
|
||||
assert(data == 2);
|
||||
cancel p;
|
||||
assert(data == 4);
|
||||
}
|
||||
|
||||
async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void {
|
||||
defer *y += 2;
|
||||
*y += 1;
|
||||
suspend;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user