diff --git a/doc/langref.html.in b/doc/langref.html.in index 5165a7bb91..d227936f82 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5845,7 +5845,7 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%" PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression -SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) +SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) FieldAccessExpression = "." Symbol diff --git a/src/parser.cpp b/src/parser.cpp index c7675ad67d..0c9b7e326a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -956,7 +956,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde } /* -SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) +SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) ArrayAccessExpression : token(LBracket) Expression token(RBracket) SliceExpression = "[" Expression ".." option(Expression) "]" @@ -972,19 +972,20 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, AstNode *allocator_expr_node = nullptr; Token *async_lparen_tok = &pc->tokens->at(*token_index); - if (async_lparen_tok->id == TokenIdLParen) { + if (async_lparen_tok->id == TokenIdCmpLessThan) { *token_index += 1; - allocator_expr_node = ast_parse_expression(pc, token_index, true); - ast_eat_token(pc, token_index, TokenIdRParen); + allocator_expr_node = ast_parse_prefix_op_expr(pc, token_index, true); + ast_eat_token(pc, token_index, TokenIdCmpGreaterThan); } - AstNode *fn_ref_expr_node = ast_parse_primary_expr(pc, token_index, true); - Token *lparen_tok = ast_eat_token(pc, token_index, TokenIdLParen); - AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, lparen_tok); + Token *fncall_token = &pc->tokens->at(*token_index); + 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)); + } node->data.fn_call_expr.is_async = true; node->data.fn_call_expr.async_allocator = allocator_expr_node; - node->data.fn_call_expr.fn_ref_expr = fn_ref_expr_node; - ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); + assert(node->data.fn_call_expr.fn_ref_expr != nullptr); primary_expr = node; } else { diff --git a/test/cases/coroutines.zig b/test/cases/coroutines.zig index 12235cf40b..9e98276e0c 100644 --- a/test/cases/coroutines.zig +++ b/test/cases/coroutines.zig @@ -4,7 +4,7 @@ const assert = std.debug.assert; var x: i32 = 1; test "create a coroutine and cancel it" { - const p = try async(std.debug.global_allocator) simpleAsyncFn(); + const p = try async simpleAsyncFn(); cancel p; assert(x == 2); } @@ -17,7 +17,7 @@ async fn simpleAsyncFn() void { test "coroutine suspend, resume, cancel" { seq('a'); - const p = try async(std.debug.global_allocator) testAsyncSeq(); + const p = try async testAsyncSeq(); seq('c'); resume p; seq('f'); @@ -43,7 +43,7 @@ fn seq(c: u8) void { } test "coroutine suspend with block" { - const p = try async(std.debug.global_allocator) testSuspendBlock(); + const p = try async testSuspendBlock(); std.debug.assert(!result); resume a_promise; std.debug.assert(result); @@ -65,7 +65,7 @@ var await_final_result: i32 = 0; test "coroutine await" { await_seq('a'); - const p = async(std.debug.global_allocator) await_amain() catch unreachable; + const p = async await_amain() catch unreachable; await_seq('f'); resume await_a_promise; await_seq('i'); @@ -104,7 +104,7 @@ var early_final_result: i32 = 0; test "coroutine await early return" { early_seq('a'); - const p = async(std.debug.global_allocator) early_amain() catch unreachable; + const p = async early_amain() catch unreachable; early_seq('f'); assert(early_final_result == 1234); assert(std.mem.eql(u8, early_points, "abcdef")); @@ -133,7 +133,7 @@ fn early_seq(c: u8) void { test "coro allocation failure" { var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0); - if (async(&failing_allocator.allocator) asyncFuncThatNeverGetsRun()) { + if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) { @panic("expected allocation failure"); } else |err| switch (err) { error.OutOfMemory => {}, @@ -143,3 +143,16 @@ test "coro allocation failure" { async fn asyncFuncThatNeverGetsRun() void { @panic("coro frame allocation should fail"); } + +test "async function with dot syntax" { + const S = struct { + var y: i32 = 1; + async fn foo() void { + y += 1; + suspend; + } + }; + const p = try async S.foo(); + cancel p; + assert(S.y == 2); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 68737eee1a..ddf5286335 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -17,7 +17,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { cases.add("returning error from void async function", \\const std = @import("std"); \\export fn entry() void { - \\ const p = async(std.debug.global_allocator) amain() catch unreachable; + \\ const p = async amain() catch unreachable; \\} \\async fn amain() void { \\ return error.ShouldBeCompileError;