From 40d11cc25a469dc6bb0f9fbba4d05e7210a23b3f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 7 Jul 2025 11:22:28 -0700 Subject: [PATCH] remove `async` and `await` keywords Also remove `@frameSize`, closing #3654. While the other machinery might remain depending on #23446, it is settled that there will not be `async`/ `await` keywords in the language. --- doc/langref.html.in | 46 +- lib/compiler/reduce/Walk.zig | 5 - lib/docs/wasm/Walk.zig | 9 - lib/docs/wasm/html_render.zig | 2 - lib/std/builtin.zig | 13 +- lib/std/zig/Ast.zig | 71 +- lib/std/zig/AstGen.zig | 70 +- lib/std/zig/AstRlAnnotate.zig | 18 - lib/std/zig/BuiltinFn.zig | 16 - lib/std/zig/Parse.zig | 54 +- lib/std/zig/Zir.zig | 26 - lib/std/zig/ZonGen.zig | 5 - lib/std/zig/parser_test.zig | 76 - lib/std/zig/render.zig | 8 - lib/std/zig/tokenizer.zig | 6 - src/Sema.zig | 57 +- src/Zcu.zig | 4 - src/codegen/llvm.zig | 4 +- src/print_zir.zig | 17 - test/behavior.zig | 2 - test/behavior/align.zig | 24 - test/behavior/async_fn.zig | 1911 ----------------- test/behavior/await_struct.zig | 47 - test/behavior/call.zig | 6 +- ...sync_function_depends_on_its_own_frame.zig | 13 - ...on_indirectly_depends_on_its_own_frame.zig | 17 - .../async/const_frame_cast_to_anyframe.zig | 19 - ..._ccc_indirectly_calling_async_function.zig | 18 - ..._recursion_of_async_functions_detected.zig | 36 - .../invalid_suspend_in_exported_function.zig | 15 - ...turning_error_from_void_async_function.zig | 12 - .../runtime-known_async_function_called.zig | 15 - ...own_function_called_with_async_keyword.zig | 13 - .../wrong_frame_type_used_for_async_call.zig | 16 - ...wrong_type_for_result_ptr_to_asyncCall.zig | 16 - .../combination_of_nosuspend_and_async.zig | 15 - .../suspend_inside_suspend_block.zig | 15 - .../@asyncCall with too small a frame.zig | 26 - test/cases/safety/awaiting twice.zig | 29 - ...ror return trace across suspend points.zig | 38 - .../invalid resume of async function.zig | 19 - ...ng a function which is awaiting a call.zig | 21 - ...g a function which is awaiting a frame.zig | 22 - ...n which has been suspended and resumed.zig | 32 - ...ed function which never been suspended.zig | 27 - tools/docgen.zig | 2 - tools/doctest.zig | 2 - tools/lldb_pretty_printers.py | 2 - 48 files changed, 24 insertions(+), 2913 deletions(-) delete mode 100644 test/behavior/async_fn.zig delete mode 100644 test/behavior/await_struct.zig delete mode 100644 test/cases/compile_errors/async/async_function_depends_on_its_own_frame.zig delete mode 100644 test/cases/compile_errors/async/async_function_indirectly_depends_on_its_own_frame.zig delete mode 100644 test/cases/compile_errors/async/const_frame_cast_to_anyframe.zig delete mode 100644 test/cases/compile_errors/async/function_with_ccc_indirectly_calling_async_function.zig delete mode 100644 test/cases/compile_errors/async/indirect_recursion_of_async_functions_detected.zig delete mode 100644 test/cases/compile_errors/async/invalid_suspend_in_exported_function.zig delete mode 100644 test/cases/compile_errors/async/returning_error_from_void_async_function.zig delete mode 100644 test/cases/compile_errors/async/runtime-known_async_function_called.zig delete mode 100644 test/cases/compile_errors/async/runtime-known_function_called_with_async_keyword.zig delete mode 100644 test/cases/compile_errors/async/wrong_frame_type_used_for_async_call.zig delete mode 100644 test/cases/compile_errors/async/wrong_type_for_result_ptr_to_asyncCall.zig delete mode 100644 test/cases/compile_errors/combination_of_nosuspend_and_async.zig delete mode 100644 test/cases/compile_errors/suspend_inside_suspend_block.zig delete mode 100644 test/cases/safety/@asyncCall with too small a frame.zig delete mode 100644 test/cases/safety/awaiting twice.zig delete mode 100644 test/cases/safety/error return trace across suspend points.zig delete mode 100644 test/cases/safety/invalid resume of async function.zig delete mode 100644 test/cases/safety/resuming a function which is awaiting a call.zig delete mode 100644 test/cases/safety/resuming a function which is awaiting a frame.zig delete mode 100644 test/cases/safety/resuming a non-suspended function which has been suspended and resumed.zig delete mode 100644 test/cases/safety/resuming a non-suspended function which never been suspended.zig diff --git a/doc/langref.html.in b/doc/langref.html.in index 78f5c32384..6b0e1cb68e 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -4279,16 +4279,9 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void { {#header_close#} {#header_open|Async Functions#} -

Async functions regressed with the release of 0.11.0. Their future in - the Zig language is unclear due to multiple unsolved problems:

- -

These problems are surmountable, but it will take time. The Zig team - is currently focused on other priorities.

+

Async functions regressed with the release of 0.11.0. The current plan is to + reintroduce them as a lower level primitive that powers I/O implementations.

+

Tracking issue: Proposal: stackless coroutines as low-level primitives

{#header_close#} {#header_open|Builtin Functions|2col#} @@ -7372,29 +7365,6 @@ fn readU32Be() u32 {} - - -
{#syntax#}async{#endsyntax#}
- - - {#syntax#}async{#endsyntax#} can be used before a function call to get a pointer to the function's frame when it suspends. - - - - - -
{#syntax#}await{#endsyntax#}
- - - {#syntax#}await{#endsyntax#} can be used to suspend the current function until the frame provided after the {#syntax#}await{#endsyntax#} completes. - {#syntax#}await{#endsyntax#} copies the value returned from the target function's frame to the caller. - - -
{#syntax#}break{#endsyntax#}
@@ -8006,8 +7976,7 @@ TypeExpr <- PrefixTypeOp* ErrorUnionExpr ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? SuffixExpr - <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments - / PrimaryTypeExpr (SuffixOp / FnCallArguments)* + <- PrimaryTypeExpr (SuffixOp / FnCallArguments)* PrimaryTypeExpr <- BUILTINIDENTIFIER FnCallArguments @@ -8183,7 +8152,6 @@ PrefixOp / MINUSPERCENT / AMPERSAND / KEYWORD_try - / KEYWORD_await PrefixTypeOp <- QUESTIONMARK @@ -8404,8 +8372,6 @@ KEYWORD_and <- 'and' end_of_word KEYWORD_anyframe <- 'anyframe' end_of_word KEYWORD_anytype <- 'anytype' end_of_word KEYWORD_asm <- 'asm' end_of_word -KEYWORD_async <- 'async' end_of_word -KEYWORD_await <- 'await' end_of_word KEYWORD_break <- 'break' end_of_word KEYWORD_callconv <- 'callconv' end_of_word KEYWORD_catch <- 'catch' end_of_word @@ -8448,8 +8414,8 @@ KEYWORD_volatile <- 'volatile' end_of_word KEYWORD_while <- 'while' end_of_word keyword <- KEYWORD_addrspace / KEYWORD_align / KEYWORD_allowzero / KEYWORD_and - / KEYWORD_anyframe / KEYWORD_anytype / KEYWORD_asm / KEYWORD_async - / KEYWORD_await / KEYWORD_break / KEYWORD_callconv / KEYWORD_catch + / KEYWORD_anyframe / KEYWORD_anytype / KEYWORD_asm + / KEYWORD_break / KEYWORD_callconv / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_fn / KEYWORD_for / KEYWORD_if diff --git a/lib/compiler/reduce/Walk.zig b/lib/compiler/reduce/Walk.zig index 48bd55fd63..360fcd7fd1 100644 --- a/lib/compiler/reduce/Walk.zig +++ b/lib/compiler/reduce/Walk.zig @@ -335,7 +335,6 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { .address_of, .@"try", .@"resume", - .@"await", .deref, => { return walkExpression(w, ast.nodeData(node).node); @@ -379,12 +378,8 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .call, .call_comma, - .async_call, - .async_call_comma, => { var buf: [1]Ast.Node.Index = undefined; return walkCall(w, ast.fullCall(&buf, node).?); diff --git a/lib/docs/wasm/Walk.zig b/lib/docs/wasm/Walk.zig index e3884f6271..9b979e1488 100644 --- a/lib/docs/wasm/Walk.zig +++ b/lib/docs/wasm/Walk.zig @@ -238,12 +238,8 @@ pub const File = struct { .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .call, .call_comma, - .async_call, - .async_call_comma, => { var buf: [1]Ast.Node.Index = undefined; return categorize_call(file_index, node, ast.fullCall(&buf, node).?); @@ -743,7 +739,6 @@ fn expr(w: *Walk, scope: *Scope, parent_decl: Decl.Index, node: Ast.Node.Index) .@"comptime", .@"nosuspend", .@"suspend", - .@"await", .@"resume", .@"try", => try expr(w, scope, parent_decl, ast.nodeData(node).node), @@ -806,12 +801,8 @@ fn expr(w: *Walk, scope: *Scope, parent_decl: Decl.Index, node: Ast.Node.Index) .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .call, .call_comma, - .async_call, - .async_call_comma, => { var buf: [1]Ast.Node.Index = undefined; const full = ast.fullCall(&buf, node).?; diff --git a/lib/docs/wasm/html_render.zig b/lib/docs/wasm/html_render.zig index b7e79e5732..13c972a936 100644 --- a/lib/docs/wasm/html_render.zig +++ b/lib/docs/wasm/html_render.zig @@ -101,8 +101,6 @@ pub fn fileSourceHtml( .keyword_align, .keyword_and, .keyword_asm, - .keyword_async, - .keyword_await, .keyword_break, .keyword_catch, .keyword_comptime, diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 9df042f86f..527fc141c6 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -199,8 +199,6 @@ pub const CallingConvention = union(enum(u8)) { pub const C: CallingConvention = .c; /// Deprecated; use `.naked`. pub const Naked: CallingConvention = .naked; - /// Deprecated; use `.@"async"`. - pub const Async: CallingConvention = .@"async"; /// Deprecated; use `.@"inline"`. pub const Inline: CallingConvention = .@"inline"; /// Deprecated; use `.x86_64_interrupt`, `.x86_interrupt`, or `.avr_interrupt`. @@ -866,32 +864,23 @@ pub const WasiExecModel = enum { pub const CallModifier = enum { /// Equivalent to function call syntax. auto, - - /// Equivalent to async keyword used with function call syntax. - async_kw, - /// Prevents tail call optimization. This guarantees that the return /// address will point to the callsite, as opposed to the callsite's /// callsite. If the call is otherwise required to be tail-called /// or inlined, a compile error is emitted instead. never_tail, - /// Guarantees that the call will not be inlined. If the call is /// otherwise required to be inlined, a compile error is emitted instead. never_inline, - /// Asserts that the function call will not suspend. This allows a /// non-async function to call an async function. - no_async, - + no_suspend, /// Guarantees that the call will be generated with tail call optimization. /// If this is not possible, a compile error is emitted instead. always_tail, - /// Guarantees that the call will be inlined at the callsite. /// If this is not possible, a compile error is emitted instead. always_inline, - /// Evaluates the call at compile-time. If the call cannot be completed at /// compile-time, a compile error is emitted instead. compile_time, diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index d0e819e943..f7a79c0896 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -606,7 +606,6 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex { .negation_wrap, .address_of, .@"try", - .@"await", .optional_type, .@"switch", .switch_comma, @@ -763,20 +762,6 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex { return main_token - end_offset; }, - .async_call_one, - .async_call_one_comma, - => { - end_offset += 1; // async token - n = tree.nodeData(n).node_and_opt_node[0]; - }, - - .async_call, - .async_call_comma, - => { - end_offset += 1; // async token - n = tree.nodeData(n).node_and_extra[0]; - }, - .container_field_init, .container_field_align, .container_field, @@ -903,7 +888,6 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex { .negation_wrap, .address_of, .@"try", - .@"await", .optional_type, .@"suspend", .@"resume", @@ -1022,7 +1006,7 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex { }; }, - .call, .async_call => { + .call => { _, const extra_index = tree.nodeData(n).node_and_extra; const params = tree.extraData(extra_index, Node.SubRange); assert(params.start != params.end); @@ -1041,7 +1025,6 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex { } }, .call_comma, - .async_call_comma, .tagged_union_enum_tag_trailing, => { _, const extra_index = tree.nodeData(n).node_and_extra; @@ -1122,7 +1105,6 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex { n = @enumFromInt(tree.extra_data[@intFromEnum(range.end) - 1]); // last member }, .call_one, - .async_call_one, => { _, const first_param = tree.nodeData(n).node_and_opt_node; end_offset += 1; // for the rparen @@ -1271,7 +1253,6 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex { n = first_element; }, .call_one_comma, - .async_call_one_comma, .struct_init_one_comma, => { _, const first_field = tree.nodeData(n).node_and_opt_node; @@ -1988,21 +1969,21 @@ pub fn forFull(tree: Ast, node: Node.Index) full.For { pub fn callOne(tree: Ast, buffer: *[1]Node.Index, node: Node.Index) full.Call { const fn_expr, const first_param = tree.nodeData(node).node_and_opt_node; const params = loadOptionalNodesIntoBuffer(1, buffer, .{first_param}); - return tree.fullCallComponents(.{ + return .{ .ast = .{ .lparen = tree.nodeMainToken(node), .fn_expr = fn_expr, .params = params, - }); + } }; } pub fn callFull(tree: Ast, node: Node.Index) full.Call { const fn_expr, const extra_index = tree.nodeData(node).node_and_extra; const params = tree.extraDataSlice(tree.extraData(extra_index, Node.SubRange), Node.Index); - return tree.fullCallComponents(.{ + return .{ .ast = .{ .lparen = tree.nodeMainToken(node), .fn_expr = fn_expr, .params = params, - }); + } }; } fn fullVarDeclComponents(tree: Ast, info: full.VarDecl.Components) full.VarDecl { @@ -2336,18 +2317,6 @@ fn fullForComponents(tree: Ast, info: full.For.Components) full.For { return result; } -fn fullCallComponents(tree: Ast, info: full.Call.Components) full.Call { - var result: full.Call = .{ - .ast = info, - .async_token = null, - }; - const first_token = tree.firstToken(info.fn_expr); - if (tree.isTokenPrecededByTags(first_token, &.{.keyword_async})) { - result.async_token = first_token - 1; - } - return result; -} - pub fn fullVarDecl(tree: Ast, node: Node.Index) ?full.VarDecl { return switch (tree.nodeTag(node)) { .global_var_decl => tree.globalVarDecl(node), @@ -2488,8 +2457,8 @@ pub fn fullAsm(tree: Ast, node: Node.Index) ?full.Asm { pub fn fullCall(tree: Ast, buffer: *[1]Ast.Node.Index, node: Node.Index) ?full.Call { return switch (tree.nodeTag(node)) { - .call, .call_comma, .async_call, .async_call_comma => tree.callFull(node), - .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => tree.callOne(buffer, node), + .call, .call_comma => tree.callFull(node), + .call_one, .call_one_comma => tree.callOne(buffer, node), else => null, }; } @@ -2882,7 +2851,6 @@ pub const full = struct { pub const Call = struct { ast: Components, - async_token: ?TokenIndex, pub const Components = struct { lparen: TokenIndex, @@ -3301,8 +3269,6 @@ pub const Node = struct { address_of, /// `try expr`. The `main_token` field is the `try` token. @"try", - /// `await expr`. The `main_token` field is the `await` token. - @"await", /// `?expr`. The `main_token` field is the `?` token. optional_type, /// `[lhs]rhs`. The `main_token` field is the `[` token. @@ -3498,17 +3464,6 @@ pub const Node = struct { /// Same as `call_one` except there is known to be a trailing comma /// before the final rparen. call_one_comma, - /// `async a(b)`, `async a()`. - /// - /// The `data` field is a `.node_and_opt_node`: - /// 1. a `Node.Index` to the function expression. - /// 2. a `Node.OptionalIndex` to the first argument, if any. - /// - /// The `main_token` field is the `(` token. - async_call_one, - /// Same as `async_call_one` except there is known to be a trailing - /// comma before the final rparen. - async_call_one_comma, /// `a(b, c, d)`. /// /// The `data` field is a `.node_and_extra`: @@ -3521,18 +3476,6 @@ pub const Node = struct { /// Same as `call` except there is known to be a trailing comma before /// the final rparen. call_comma, - /// `async a(b, c, d)`. - /// - /// The `data` field is a `.node_and_extra`: - /// 1. a `Node.Index` to the function expression. - /// 2. a `ExtraIndex` to a `SubRange` that stores a `Node.Index` for - /// each argument. - /// - /// The `main_token` field is the `(` token. - async_call, - /// Same as `async_call` except there is known to be a trailing comma - /// before the final rparen. - async_call_comma, /// `switch(a) {}`. /// /// The `data` field is a `.node_and_extra`: diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index e253729c3e..8cb2d34354 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -510,12 +510,8 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins .number_literal, .call, .call_comma, - .async_call, - .async_call_comma, .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .unreachable_literal, .@"return", .@"if", @@ -547,7 +543,6 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins .merge_error_sets, .switch_range, .for_range, - .@"await", .bit_not, .negation, .negation_wrap, @@ -836,12 +831,8 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .call, .call_comma, - .async_call, - .async_call_comma, => { var buf: [1]Ast.Node.Index = undefined; return callExpr(gz, scope, ri, .none, node, tree.fullCall(&buf, node).?); @@ -1114,7 +1105,6 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE .@"nosuspend" => return nosuspendExpr(gz, scope, ri, node), .@"suspend" => return suspendExpr(gz, scope, node), - .@"await" => return awaitExpr(gz, scope, ri, node), .@"resume" => return resumeExpr(gz, scope, ri, node), .@"try" => return tryExpr(gz, scope, ri, node, tree.nodeData(node).node), @@ -1259,33 +1249,6 @@ fn suspendExpr( return suspend_inst.toRef(); } -fn awaitExpr( - gz: *GenZir, - scope: *Scope, - ri: ResultInfo, - node: Ast.Node.Index, -) InnerError!Zir.Inst.Ref { - const astgen = gz.astgen; - const tree = astgen.tree; - const rhs_node = tree.nodeData(node).node; - - if (gz.suspend_node.unwrap()) |suspend_node| { - return astgen.failNodeNotes(node, "cannot await inside suspend block", .{}, &[_]u32{ - try astgen.errNoteNode(suspend_node, "suspend block here", .{}), - }); - } - const operand = try expr(gz, scope, .{ .rl = .ref }, rhs_node); - const result = if (gz.nosuspend_node != .none) - try gz.addExtendedPayload(.await_nosuspend, Zir.Inst.UnNode{ - .node = gz.nodeIndexToRelative(node), - .operand = operand, - }) - else - try gz.addUnNode(.@"await", operand, node); - - return rvalue(gz, ri, result, node); -} - fn resumeExpr( gz: *GenZir, scope: *Scope, @@ -2853,7 +2816,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .tag_name, .type_name, .frame_type, - .frame_size, .int_from_float, .float_from_int, .ptr_from_int, @@ -2887,7 +2849,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .min, .c_import, .@"resume", - .@"await", .ret_err_value_code, .ret_ptr, .ret_type, @@ -9501,7 +9462,6 @@ fn builtinCall( .tag_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .tag_name), .type_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .type_name), .Frame => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .frame_type), - .frame_size => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .frame_size), .int_from_float => return typeCast(gz, scope, ri, node, params[0], .int_from_float, builtin_name), .float_from_int => return typeCast(gz, scope, ri, node, params[0], .float_from_int, builtin_name), @@ -9767,16 +9727,6 @@ fn builtinCall( }); return rvalue(gz, ri, result, node); }, - .async_call => { - const result = try gz.addExtendedPayload(.builtin_async_call, Zir.Inst.AsyncCall{ - .node = gz.nodeIndexToRelative(node), - .frame_buffer = try expr(gz, scope, .{ .rl = .none }, params[0]), - .result_ptr = try expr(gz, scope, .{ .rl = .none }, params[1]), - .fn_ptr = try expr(gz, scope, .{ .rl = .none }, params[2]), - .args = try expr(gz, scope, .{ .rl = .none }, params[3]), - }); - return rvalue(gz, ri, result, node); - }, .Vector => { const result = try gz.addPlNode(.vector_type, node, Zir.Inst.Bin{ .lhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .type), @@ -10175,11 +10125,8 @@ fn callExpr( const callee = try calleeExpr(gz, scope, ri.rl, override_decl_literal_type, call.ast.fn_expr); const modifier: std.builtin.CallModifier = blk: { - if (call.async_token != null) { - break :blk .async_kw; - } if (gz.nosuspend_node != .none) { - break :blk .no_async; + break :blk .no_suspend; } break :blk .auto; }; @@ -10483,12 +10430,8 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev .switch_comma, .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .call, .call_comma, - .async_call, - .async_call_comma, => return .maybe, .@"return", @@ -10613,7 +10556,6 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev // Forward the question to the LHS sub-expression. .@"try", - .@"await", .@"comptime", .@"nosuspend", => node = tree.nodeData(node).node, @@ -10803,12 +10745,8 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In .switch_comma, .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .call, .call_comma, - .async_call, - .async_call_comma, .block_two, .block_two_semicolon, .block, @@ -10826,7 +10764,6 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In // Forward the question to the LHS sub-expression. .@"try", - .@"await", .@"comptime", .@"nosuspend", => node = tree.nodeData(node).node, @@ -11047,12 +10984,8 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool { .switch_comma, .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .call, .call_comma, - .async_call, - .async_call_comma, .block_two, .block_two_semicolon, .block, @@ -11079,7 +11012,6 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool { // Forward the question to the LHS sub-expression. .@"try", - .@"await", .@"comptime", .@"nosuspend", => node = tree.nodeData(node).node, diff --git a/lib/std/zig/AstRlAnnotate.zig b/lib/std/zig/AstRlAnnotate.zig index 628574349b..aeb7c82f77 100644 --- a/lib/std/zig/AstRlAnnotate.zig +++ b/lib/std/zig/AstRlAnnotate.zig @@ -334,12 +334,8 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .call, .call_comma, - .async_call, - .async_call_comma, => { var buf: [1]Ast.Node.Index = undefined; const full = tree.fullCall(&buf, node).?; @@ -353,11 +349,6 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI .call, .call_comma, => false, // TODO: once function calls are passed result locations this will change - .async_call_one, - .async_call_one_comma, - .async_call, - .async_call_comma, - => ri.have_ptr, // always use result ptr for frames else => unreachable, }; }, @@ -503,7 +494,6 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI return false; }, .@"try", - .@"await", .@"nosuspend", => return astrl.expr(tree.nodeData(node).node, block, ri), .grouped_expression, @@ -948,7 +938,6 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast. .tag_name, .type_name, .Frame, - .frame_size, .int_from_float, .float_from_int, .ptr_from_int, @@ -1079,13 +1068,6 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast. _ = try astrl.expr(args[3], block, ResultInfo.none); return false; }, - .async_call => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - _ = try astrl.expr(args[1], block, ResultInfo.none); - _ = try astrl.expr(args[2], block, ResultInfo.none); - _ = try astrl.expr(args[3], block, ResultInfo.none); - return false; // buffer passed as arg for frame data - }, .Vector => { _ = try astrl.expr(args[0], block, ResultInfo.type_only); _ = try astrl.expr(args[1], block, ResultInfo.type_only); diff --git a/lib/std/zig/BuiltinFn.zig b/lib/std/zig/BuiltinFn.zig index 818362a371..5ef28fdfaf 100644 --- a/lib/std/zig/BuiltinFn.zig +++ b/lib/std/zig/BuiltinFn.zig @@ -4,7 +4,6 @@ pub const Tag = enum { align_cast, align_of, as, - async_call, atomic_load, atomic_rmw, atomic_store, @@ -55,7 +54,6 @@ pub const Tag = enum { frame, Frame, frame_address, - frame_size, has_decl, has_field, import, @@ -184,13 +182,6 @@ pub const list = list: { .param_count = 2, }, }, - .{ - "@asyncCall", - .{ - .tag = .async_call, - .param_count = 4, - }, - }, .{ "@atomicLoad", .{ @@ -550,13 +541,6 @@ pub const list = list: { .illegal_outside_function = true, }, }, - .{ - "@frameSize", - .{ - .tag = .frame_size, - .param_count = 1, - }, - }, .{ "@hasDecl", .{ diff --git a/lib/std/zig/Parse.zig b/lib/std/zig/Parse.zig index 34f8de9191..8d6ea5afac 100644 --- a/lib/std/zig/Parse.zig +++ b/lib/std/zig/Parse.zig @@ -1688,7 +1688,6 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!?Node.Index { /// / MINUSPERCENT /// / AMPERSAND /// / KEYWORD_try -/// / KEYWORD_await fn parsePrefixExpr(p: *Parse) Error!?Node.Index { const tag: Node.Tag = switch (p.tokenTag(p.tok_i)) { .bang => .bool_not, @@ -1697,7 +1696,6 @@ fn parsePrefixExpr(p: *Parse) Error!?Node.Index { .minus_percent => .negation_wrap, .ampersand => .address_of, .keyword_try => .@"try", - .keyword_await => .@"await", else => return p.parsePrimaryExpr(), }; return try p.addNode(.{ @@ -2385,62 +2383,12 @@ fn parseErrorUnionExpr(p: *Parse) !?Node.Index { } /// SuffixExpr -/// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments -/// / PrimaryTypeExpr (SuffixOp / FnCallArguments)* +/// <- PrimaryTypeExpr (SuffixOp / FnCallArguments)* /// /// FnCallArguments <- LPAREN ExprList RPAREN /// /// ExprList <- (Expr COMMA)* Expr? fn parseSuffixExpr(p: *Parse) !?Node.Index { - if (p.eatToken(.keyword_async)) |_| { - var res = try p.expectPrimaryTypeExpr(); - while (true) { - res = try p.parseSuffixOp(res) orelse break; - } - const lparen = p.eatToken(.l_paren) orelse { - try p.warn(.expected_param_list); - return res; - }; - const scratch_top = p.scratch.items.len; - defer p.scratch.shrinkRetainingCapacity(scratch_top); - while (true) { - if (p.eatToken(.r_paren)) |_| break; - const param = try p.expectExpr(); - try p.scratch.append(p.gpa, param); - switch (p.tokenTag(p.tok_i)) { - .comma => p.tok_i += 1, - .r_paren => { - p.tok_i += 1; - break; - }, - .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), - // Likely just a missing comma; give error but continue parsing. - else => try p.warn(.expected_comma_after_arg), - } - } - const comma = (p.tokenTag(p.tok_i - 2)) == .comma; - const params = p.scratch.items[scratch_top..]; - if (params.len <= 1) { - return try p.addNode(.{ - .tag = if (comma) .async_call_one_comma else .async_call_one, - .main_token = lparen, - .data = .{ .node_and_opt_node = .{ - res, - if (params.len >= 1) params[0].toOptional() else .none, - } }, - }); - } else { - return try p.addNode(.{ - .tag = if (comma) .async_call_comma else .async_call, - .main_token = lparen, - .data = .{ .node_and_extra = .{ - res, - try p.addExtra(try p.listToSpan(params)), - } }, - }); - } - } - var res = try p.parsePrimaryTypeExpr() orelse return null; while (true) { const opt_suffix_op = try p.parseSuffixOp(res); diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index 17643e6f1e..80eb3ec890 100644 --- a/lib/std/zig/Zir.zig +++ b/lib/std/zig/Zir.zig @@ -899,8 +899,6 @@ pub const Inst = struct { type_name, /// Implement builtin `@Frame`. Uses `un_node`. frame_type, - /// Implement builtin `@frameSize`. Uses `un_node`. - frame_size, /// Implements the `@intFromFloat` builtin. /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. @@ -1044,7 +1042,6 @@ pub const Inst = struct { /// Implements `resume` syntax. Uses `un_node` field. @"resume", - @"await", /// A defer statement. /// Uses the `defer` union field. @@ -1241,7 +1238,6 @@ pub const Inst = struct { .tag_name, .type_name, .frame_type, - .frame_size, .int_from_float, .float_from_int, .ptr_from_int, @@ -1279,7 +1275,6 @@ pub const Inst = struct { .min, .c_import, .@"resume", - .@"await", .ret_err_value_code, .extended, .ret_ptr, @@ -1526,7 +1521,6 @@ pub const Inst = struct { .tag_name, .type_name, .frame_type, - .frame_size, .int_from_float, .float_from_int, .ptr_from_int, @@ -1560,7 +1554,6 @@ pub const Inst = struct { .min, .c_import, .@"resume", - .@"await", .ret_err_value_code, .@"break", .break_inline, @@ -1791,7 +1784,6 @@ pub const Inst = struct { .tag_name = .un_node, .type_name = .un_node, .frame_type = .un_node, - .frame_size = .un_node, .int_from_float = .pl_node, .float_from_int = .pl_node, @@ -1852,7 +1844,6 @@ pub const Inst = struct { .make_ptr_const = .un_node, .@"resume" = .un_node, - .@"await" = .un_node, .@"defer" = .@"defer", .defer_err_code = .defer_err_code, @@ -2016,8 +2007,6 @@ pub const Inst = struct { /// Implements the `@errorCast` builtin. /// `operand` is payload index to `BinNode`. `lhs` is dest type, `rhs` is operand. error_cast, - /// `operand` is payload index to `UnNode`. - await_nosuspend, /// Implements `@breakpoint`. /// `operand` is `src_node: Ast.Node.Offset`. breakpoint, @@ -2038,9 +2027,6 @@ pub const Inst = struct { /// `operand` is payload index to `Reify`. /// `small` contains `NameStrategy`. reify, - /// Implements the `@asyncCall` builtin. - /// `operand` is payload index to `AsyncCall`. - builtin_async_call, /// Implements the `@cmpxchgStrong` and `@cmpxchgWeak` builtins. /// `small` 0=>weak 1=>strong /// `operand` is payload index to `Cmpxchg`. @@ -3771,14 +3757,6 @@ pub const Inst = struct { b: Ref, }; - pub const AsyncCall = struct { - node: Ast.Node.Offset, - frame_buffer: Ref, - result_ptr: Ref, - fn_ptr: Ref, - args: Ref, - }; - /// Trailing: inst: Index // for every body_len pub const Param = struct { /// Null-terminated string index. @@ -4297,7 +4275,6 @@ fn findTrackableInner( .tag_name, .type_name, .frame_type, - .frame_size, .int_from_float, .float_from_int, .ptr_from_int, @@ -4337,7 +4314,6 @@ fn findTrackableInner( .resolve_inferred_alloc, .make_ptr_const, .@"resume", - .@"await", .save_err_ret_index, .restore_err_ret_index_unconditional, .restore_err_ret_index_fn_entry, @@ -4380,14 +4356,12 @@ fn findTrackableInner( .prefetch, .set_float_mode, .error_cast, - .await_nosuspend, .breakpoint, .disable_instrumentation, .disable_intrinsics, .select, .int_from_error, .error_from_int, - .builtin_async_call, .cmpxchg, .c_va_arg, .c_va_copy, diff --git a/lib/std/zig/ZonGen.zig b/lib/std/zig/ZonGen.zig index 2114260e84..47fd52ca2a 100644 --- a/lib/std/zig/ZonGen.zig +++ b/lib/std/zig/ZonGen.zig @@ -204,12 +204,8 @@ fn expr(zg: *ZonGen, node: Ast.Node.Index, dest_node: Zoir.Node.Index) Allocator .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .call, .call_comma, - .async_call, - .async_call_comma, .@"return", .if_simple, .@"if", @@ -226,7 +222,6 @@ fn expr(zg: *ZonGen, node: Ast.Node.Index, dest_node: Zoir.Node.Index) Allocator .switch_comma, .@"nosuspend", .@"suspend", - .@"await", .@"resume", .@"try", .unreachable_literal, diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 267459b4cf..c1cc3da2d9 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -341,15 +341,6 @@ test "zig fmt: nosuspend block" { ); } -test "zig fmt: nosuspend await" { - try testCanonical( - \\fn foo() void { - \\ x = nosuspend await y; - \\} - \\ - ); -} - test "zig fmt: container declaration, single line" { try testCanonical( \\const X = struct { foo: i32 }; @@ -1093,18 +1084,6 @@ test "zig fmt: block in slice expression" { ); } -test "zig fmt: async function" { - try testCanonical( - \\pub const Server = struct { - \\ handleRequestFn: fn (*Server, *const std.net.Address, File) callconv(.@"async") void, - \\}; - \\test "hi" { - \\ var ptr: fn (i32) callconv(.@"async") void = @ptrCast(other); - \\} - \\ - ); -} - test "zig fmt: whitespace fixes" { try testTransform("test \"\" {\r\n\tconst hi = x;\r\n}\n// zig fmt: off\ntest \"\"{\r\n\tconst a = b;}\r\n", \\test "" { @@ -1549,17 +1528,6 @@ test "zig fmt: spaces around slice operator" { ); } -test "zig fmt: async call in if condition" { - try testCanonical( - \\comptime { - \\ if (async b()) { - \\ a(); - \\ } - \\} - \\ - ); -} - test "zig fmt: 2nd arg multiline string" { try testCanonical( \\comptime { @@ -3946,27 +3914,6 @@ test "zig fmt: inline asm" { ); } -test "zig fmt: async functions" { - try testCanonical( - \\fn simpleAsyncFn() void { - \\ const a = async a.b(); - \\ x += 1; - \\ suspend {} - \\ x += 1; - \\ suspend {} - \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable; - \\ await p; - \\} - \\ - \\test "suspend, resume, await" { - \\ const p: anyframe = async testAsyncSeq(); - \\ resume p; - \\ await p; - \\} - \\ - ); -} - test "zig fmt: nosuspend" { try testCanonical( \\const a = nosuspend foo(); @@ -6181,29 +6128,6 @@ test "recovery: missing return type" { }); } -test "recovery: continue after invalid decl" { - try testError( - \\fn foo { - \\ inline; - \\} - \\pub test "" { - \\ async a & b; - \\} - , &[_]Error{ - .expected_token, - .expected_pub_item, - .expected_param_list, - }); - try testError( - \\threadlocal test "" { - \\ @a & b; - \\} - , &[_]Error{ - .expected_var_decl, - .expected_param_list, - }); -} - test "recovery: invalid extern/inline" { try testError( \\inline test "" { a & b; } diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 994c6aa2cd..dc6a9a275c 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -591,7 +591,6 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { .@"try", .@"resume", - .@"await", => { try renderToken(r, tree.nodeMainToken(node), .space); return renderExpression(r, tree.nodeData(node).node, space); @@ -635,12 +634,8 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .call, .call_comma, - .async_call, - .async_call_comma, => { var buf: [1]Ast.Node.Index = undefined; return renderCall(r, tree.fullCall(&buf, node).?, space); @@ -2551,9 +2546,6 @@ fn renderCall( call: Ast.full.Call, space: Space, ) Error!void { - if (call.async_token) |async_token| { - try renderToken(r, async_token, .space); - } try renderExpression(r, call.ast.fn_expr, .none); try renderParamList(r, call.ast.lparen, call.ast.params, space); } diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index 09c79d3562..4b2f7f0915 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -17,8 +17,6 @@ pub const Token = struct { .{ "anyframe", .keyword_anyframe }, .{ "anytype", .keyword_anytype }, .{ "asm", .keyword_asm }, - .{ "async", .keyword_async }, - .{ "await", .keyword_await }, .{ "break", .keyword_break }, .{ "callconv", .keyword_callconv }, .{ "catch", .keyword_catch }, @@ -146,8 +144,6 @@ pub const Token = struct { keyword_anyframe, keyword_anytype, keyword_asm, - keyword_async, - keyword_await, keyword_break, keyword_callconv, keyword_catch, @@ -273,8 +269,6 @@ pub const Token = struct { .keyword_anyframe => "anyframe", .keyword_anytype => "anytype", .keyword_asm => "asm", - .keyword_async => "async", - .keyword_await => "await", .keyword_break => "break", .keyword_callconv => "callconv", .keyword_catch => "catch", diff --git a/src/Sema.zig b/src/Sema.zig index c9ca2941da..bcb5dbe085 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1280,7 +1280,6 @@ fn analyzeBodyInner( .tag_name => try sema.zirTagName(block, inst), .type_name => try sema.zirTypeName(block, inst), .frame_type => try sema.zirFrameType(block, inst), - .frame_size => try sema.zirFrameSize(block, inst), .int_from_float => try sema.zirIntFromFloat(block, inst), .float_from_int => try sema.zirFloatFromInt(block, inst), .ptr_from_int => try sema.zirPtrFromInt(block, inst), @@ -1302,7 +1301,6 @@ fn analyzeBodyInner( .mul_add => try sema.zirMulAdd(block, inst), .builtin_call => try sema.zirBuiltinCall(block, inst), .@"resume" => try sema.zirResume(block, inst), - .@"await" => try sema.zirAwait(block, inst), .for_len => try sema.zirForLen(block, inst), .validate_array_init_ref_ty => try sema.zirValidateArrayInitRefTy(block, inst), .opt_eu_base_ptr_init => try sema.zirOptEuBasePtrInit(block, inst), @@ -1410,12 +1408,10 @@ fn analyzeBodyInner( .wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended), .prefetch => try sema.zirPrefetch( block, extended), .error_cast => try sema.zirErrorCast( block, extended), - .await_nosuspend => try sema.zirAwaitNosuspend( block, extended), .select => try sema.zirSelect( block, extended), .int_from_error => try sema.zirIntFromError( block, extended), .error_from_int => try sema.zirErrorFromInt( block, extended), .reify => try sema.zirReify( block, extended, inst), - .builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended), .cmpxchg => try sema.zirCmpxchg( block, extended), .c_va_arg => try sema.zirCVaArg( block, extended), .c_va_copy => try sema.zirCVaCopy( block, extended), @@ -7653,10 +7649,6 @@ fn analyzeCall( const ip = &zcu.intern_pool; const arena = sema.arena; - if (modifier == .async_kw) { - return sema.failWithUseOfAsync(block, call_src); - } - const maybe_func_inst = try sema.funcDeclSrcInst(callee); const func_ret_ty_src: LazySrcLoc = if (maybe_func_inst) |fn_decl_inst| .{ .base_node_inst = fn_decl_inst, @@ -8048,14 +8040,13 @@ fn analyzeCall( } const call_tag: Air.Inst.Tag = switch (modifier) { - .auto, .no_async => .call, + .auto, .no_suspend => .call, .never_tail => .call_never_tail, .never_inline => .call_never_inline, .always_tail => .call_always_tail, .always_inline, .compile_time, - .async_kw, => unreachable, }; @@ -22133,12 +22124,6 @@ fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A return sema.failWithUseOfAsync(block, src); } -fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; - const src = block.nodeOffset(inst_data.src_node); - return sema.failWithUseOfAsync(block, src); -} - fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const pt = sema.pt; const zcu = pt.zcu; @@ -24776,14 +24761,14 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError var modifier = try sema.interpretBuiltinType(block, modifier_src, modifier_val, std.builtin.CallModifier); switch (modifier) { // These can be upgraded to comptime or nosuspend calls. - .auto, .never_tail, .no_async => { + .auto, .never_tail, .no_suspend => { if (block.isComptime()) { if (modifier == .never_tail) { return sema.fail(block, modifier_src, "unable to perform 'never_tail' call at compile-time", .{}); } modifier = .compile_time; } else if (extra.flags.is_nosuspend) { - modifier = .no_async; + modifier = .no_suspend; } }, // These can be upgraded to comptime. nosuspend bit can be safely ignored. @@ -24801,14 +24786,6 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError modifier = .compile_time; } }, - .async_kw => { - if (extra.flags.is_nosuspend) { - return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{}); - } - if (block.isComptime()) { - return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{}); - } - }, .never_inline => { if (block.isComptime()) { return sema.fail(block, modifier_src, "unable to perform 'never_inline' call at compile-time", .{}); @@ -25797,40 +25774,12 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void }); } -fn zirBuiltinAsyncCall(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { - const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; - const src = block.nodeOffset(extra.node); - return sema.failWithUseOfAsync(block, src); -} - fn zirResume(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); return sema.failWithUseOfAsync(block, src); } -fn zirAwait( - sema: *Sema, - block: *Block, - inst: Zir.Inst.Index, -) CompileError!Air.Inst.Ref { - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; - const src = block.nodeOffset(inst_data.src_node); - - return sema.failWithUseOfAsync(block, src); -} - -fn zirAwaitNosuspend( - sema: *Sema, - block: *Block, - extended: Zir.Inst.Extended.InstData, -) CompileError!Air.Inst.Ref { - const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; - const src = block.nodeOffset(extra.node); - - return sema.failWithUseOfAsync(block, src); -} - fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const tracy = trace(@src()); defer tracy.end(); diff --git a/src/Zcu.zig b/src/Zcu.zig index e69a66353f..24e7213753 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -1443,12 +1443,8 @@ pub const SrcLoc = struct { .field_access => tree.nodeData(node).node_and_token[1], .call_one, .call_one_comma, - .async_call_one, - .async_call_one_comma, .call, .call_comma, - .async_call, - .async_call_comma, => blk: { const full = tree.fullCall(&buf, node).?; break :blk tree.lastToken(full.ast.fn_expr); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index db628eab5d..d2d6f431d7 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -5273,7 +5273,7 @@ pub const FuncGen = struct { switch (modifier) { .auto, .always_tail => {}, .never_tail, .never_inline => try attributes.addFnAttr(.@"noinline", &o.builder), - .async_kw, .no_async, .always_inline, .compile_time => unreachable, + .no_suspend, .always_inline, .compile_time => unreachable, } const ret_ptr = if (!sret) null else blk: { @@ -5488,7 +5488,7 @@ pub const FuncGen = struct { .auto, .never_inline => .normal, .never_tail => .notail, .always_tail => .musttail, - .async_kw, .no_async, .always_inline, .compile_time => unreachable, + .no_suspend, .always_inline, .compile_time => unreachable, }, toLlvmCallConvTag(fn_info.cc, target).?, try attributes.finish(&o.builder), diff --git a/src/print_zir.zig b/src/print_zir.zig index a4a141fc4e..1b4d2a89b8 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -261,14 +261,12 @@ const Writer = struct { .tag_name, .type_name, .frame_type, - .frame_size, .clz, .ctz, .pop_count, .byte_swap, .bit_reverse, .@"resume", - .@"await", .make_ptr_const, .validate_deref, .validate_const, @@ -565,7 +563,6 @@ const Writer = struct { .tuple_decl => try self.writeTupleDecl(stream, extended), - .await_nosuspend, .c_undef, .c_include, .set_float_mode, @@ -611,7 +608,6 @@ const Writer = struct { try self.writeSrcNode(stream, inst_data.node); }, - .builtin_async_call => try self.writeBuiltinAsyncCall(stream, extended), .cmpxchg => try self.writeCmpxchg(stream, extended), .ptr_cast_full => try self.writePtrCastFull(stream, extended), .ptr_cast_no_dest => try self.writePtrCastNoDest(stream, extended), @@ -932,19 +928,6 @@ const Writer = struct { try self.writeSrcNode(stream, extra.src_node); } - fn writeBuiltinAsyncCall(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { - const extra = self.code.extraData(Zir.Inst.AsyncCall, extended.operand).data; - try self.writeInstRef(stream, extra.frame_buffer); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.result_ptr); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.fn_ptr); - try stream.writeAll(", "); - try self.writeInstRef(stream, extra.args); - try stream.writeAll(") "); - try self.writeSrcNode(stream, extra.node); - } - fn writeParam(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok; const extra = self.code.extraData(Zir.Inst.Param, inst_data.payload_index); diff --git a/test/behavior.zig b/test/behavior.zig index 049278a69f..e339a0b016 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -5,9 +5,7 @@ test { _ = @import("behavior/align.zig"); _ = @import("behavior/alignof.zig"); _ = @import("behavior/array.zig"); - _ = @import("behavior/async_fn.zig"); _ = @import("behavior/atomics.zig"); - _ = @import("behavior/await_struct.zig"); _ = @import("behavior/basic.zig"); _ = @import("behavior/bit_shifting.zig"); _ = @import("behavior/bitcast.zig"); diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 2921986cba..b3750c9d3d 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -425,30 +425,6 @@ test "struct field explicit alignment" { try expect(@intFromPtr(&node.massive_byte) % 64 == 0); } -test "align(@alignOf(T)) T does not force resolution of T" { - if (true) return error.SkipZigTest; // TODO - - const S = struct { - const A = struct { - a: *align(@alignOf(A)) A, - }; - fn doTheTest() void { - suspend { - resume @frame(); - } - _ = bar(@Frame(doTheTest)); - } - fn bar(comptime T: type) *align(@alignOf(T)) T { - ok = true; - return undefined; - } - - var ok = false; - }; - _ = async S.doTheTest(); - try expect(S.ok); -} - test "align(N) on functions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/async_fn.zig b/test/behavior/async_fn.zig deleted file mode 100644 index e66ecd52db..0000000000 --- a/test/behavior/async_fn.zig +++ /dev/null @@ -1,1911 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const assert = std.debug.assert; -const expect = std.testing.expect; -const expectEqual = std.testing.expectEqual; -const expectEqualStrings = std.testing.expectEqualStrings; -const expectError = std.testing.expectError; - -var global_x: i32 = 1; - -test "simple coroutine suspend and resume" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - var frame = async simpleAsyncFn(); - try expect(global_x == 2); - resume frame; - try expect(global_x == 3); - const af: anyframe->void = &frame; - _ = af; - resume frame; - try expect(global_x == 4); -} -fn simpleAsyncFn() void { - global_x += 1; - suspend {} - global_x += 1; - suspend {} - global_x += 1; -} - -var global_y: i32 = 1; - -test "pass parameter to coroutine" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - var p = async simpleAsyncFnWithArg(2); - try expect(global_y == 3); - resume p; - try expect(global_y == 5); -} -fn simpleAsyncFnWithArg(delta: i32) void { - global_y += delta; - suspend {} - global_y += delta; -} - -test "suspend at end of function" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var x: i32 = 1; - - fn doTheTest() !void { - try expect(x == 1); - const p = async suspendAtEnd(); - _ = p; - try expect(x == 2); - } - - fn suspendAtEnd() void { - x += 1; - suspend {} - } - }; - try S.doTheTest(); -} - -test "local variable in async function" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var x: i32 = 0; - - fn doTheTest() !void { - try expect(x == 0); - var p = async add(1, 2); - try expect(x == 0); - resume p; - try expect(x == 0); - resume p; - try expect(x == 0); - resume p; - try expect(x == 3); - } - - fn add(a: i32, b: i32) void { - var accum: i32 = 0; - suspend {} - accum += a; - suspend {} - accum += b; - suspend {} - x = accum; - } - }; - try S.doTheTest(); -} - -test "calling an inferred async function" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var x: i32 = 1; - var other_frame: *@Frame(other) = undefined; - - fn doTheTest() !void { - _ = async first(); - try expect(x == 1); - resume other_frame.*; - try expect(x == 2); - } - - fn first() void { - other(); - } - fn other() void { - other_frame = @frame(); - suspend {} - x += 1; - } - }; - try S.doTheTest(); -} - -test "@frameSize" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - if (builtin.target.cpu.arch == .thumb or builtin.target.cpu.arch == .thumbeb) - return error.SkipZigTest; - - const S = struct { - fn doTheTest() !void { - { - var ptr = @as(fn (i32) callconv(.@"async") void, @ptrCast(other)); - _ = &ptr; - const size = @frameSize(ptr); - try expect(size == @sizeOf(@Frame(other))); - } - { - var ptr = @as(fn () callconv(.@"async") void, @ptrCast(first)); - _ = &ptr; - const size = @frameSize(ptr); - try expect(size == @sizeOf(@Frame(first))); - } - } - - fn first() void { - other(1); - } - fn other(param: i32) void { - _ = param; - var local: i32 = undefined; - _ = &local; - suspend {} - } - }; - try S.doTheTest(); -} - -test "coroutine suspend, resume" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var frame: anyframe = undefined; - - fn doTheTest() !void { - _ = async amain(); - seq('d'); - resume frame; - seq('h'); - - try expect(std.mem.eql(u8, &points, "abcdefgh")); - } - - fn amain() void { - seq('a'); - var f = async testAsyncSeq(); - seq('c'); - await f; - seq('g'); - } - - fn testAsyncSeq() void { - defer seq('f'); - - seq('b'); - suspend { - frame = @frame(); - } - seq('e'); - } - var points = [_]u8{'x'} ** "abcdefgh".len; - var index: usize = 0; - - fn seq(c: u8) void { - points[index] = c; - index += 1; - } - }; - try S.doTheTest(); -} - -test "coroutine suspend with block" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const p = async testSuspendBlock(); - _ = p; - try expect(!global_result); - resume a_promise; - try expect(global_result); -} - -var a_promise: anyframe = undefined; -var global_result = false; -fn testSuspendBlock() callconv(.@"async") void { - suspend { - comptime assert(@TypeOf(@frame()) == *@Frame(testSuspendBlock)) catch unreachable; - a_promise = @frame(); - } - - // Test to make sure that @frame() works as advertised (issue #1296) - // var our_handle: anyframe = @frame(); - expect(a_promise == @as(anyframe, @frame())) catch @panic("test failed"); - - global_result = true; -} - -var await_a_promise: anyframe = undefined; -var await_final_result: i32 = 0; - -test "coroutine await" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - await_seq('a'); - var p = async await_amain(); - _ = &p; - await_seq('f'); - resume await_a_promise; - await_seq('i'); - try expect(await_final_result == 1234); - try expect(std.mem.eql(u8, &await_points, "abcdefghi")); -} -fn await_amain() callconv(.@"async") void { - await_seq('b'); - var p = async await_another(); - await_seq('e'); - await_final_result = await p; - await_seq('h'); -} -fn await_another() callconv(.@"async") i32 { - await_seq('c'); - suspend { - await_seq('d'); - await_a_promise = @frame(); - } - await_seq('g'); - return 1234; -} - -var await_points = [_]u8{0} ** "abcdefghi".len; -var await_seq_index: usize = 0; - -fn await_seq(c: u8) void { - await_points[await_seq_index] = c; - await_seq_index += 1; -} - -var early_final_result: i32 = 0; - -test "coroutine await early return" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - early_seq('a'); - var p = async early_amain(); - _ = &p; - early_seq('f'); - try expect(early_final_result == 1234); - try expect(std.mem.eql(u8, &early_points, "abcdef")); -} -fn early_amain() callconv(.@"async") void { - early_seq('b'); - var p = async early_another(); - early_seq('d'); - early_final_result = await p; - early_seq('e'); -} -fn early_another() callconv(.@"async") i32 { - early_seq('c'); - return 1234; -} - -var early_points = [_]u8{0} ** "abcdef".len; -var early_seq_index: usize = 0; - -fn early_seq(c: u8) void { - early_points[early_seq_index] = c; - early_seq_index += 1; -} - -test "async function with dot syntax" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var y: i32 = 1; - fn foo() callconv(.@"async") void { - y += 1; - suspend {} - } - }; - const p = async S.foo(); - _ = p; - try expect(S.y == 2); -} - -test "async fn pointer in a struct field" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - var data: i32 = 1; - const Foo = struct { - bar: fn (*i32) callconv(.@"async") void, - }; - var foo = Foo{ .bar = simpleAsyncFn2 }; - _ = &foo; - var bytes: [64]u8 align(16) = undefined; - const f = @asyncCall(&bytes, {}, foo.bar, .{&data}); - comptime assert(@TypeOf(f) == anyframe->void); - try expect(data == 2); - resume f; - try expect(data == 4); - _ = async doTheAwait(f); - try expect(data == 4); -} - -fn doTheAwait(f: anyframe->void) void { - await f; -} -fn simpleAsyncFn2(y: *i32) callconv(.@"async") void { - defer y.* += 2; - y.* += 1; - suspend {} -} - -test "@asyncCall with return type" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const Foo = struct { - bar: fn () callconv(.@"async") i32, - - var global_frame: anyframe = undefined; - fn middle() callconv(.@"async") i32 { - return afunc(); - } - - fn afunc() i32 { - global_frame = @frame(); - suspend {} - return 1234; - } - }; - var foo = Foo{ .bar = Foo.middle }; - _ = &foo; - var bytes: [150]u8 align(16) = undefined; - var aresult: i32 = 0; - _ = @asyncCall(&bytes, &aresult, foo.bar, .{}); - try expect(aresult == 0); - resume Foo.global_frame; - try expect(aresult == 1234); -} - -test "async fn with inferred error set" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - - fn doTheTest() !void { - var frame: [1]@Frame(middle) = undefined; - var fn_ptr = middle; - _ = &fn_ptr; - var result: @typeInfo(@typeInfo(@TypeOf(fn_ptr)).@"fn".return_type.?).error_union.error_set!void = undefined; - _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr, .{}); - resume global_frame; - try std.testing.expectError(error.Fail, result); - } - fn middle() callconv(.@"async") !void { - var f = async middle2(); - return await f; - } - - fn middle2() !void { - return failing(); - } - - fn failing() !void { - global_frame = @frame(); - suspend {} - return error.Fail; - } - }; - try S.doTheTest(); -} - -test "error return trace across suspend points - early return" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const p = nonFailing(); - resume p; - const p2 = async printTrace(p); - _ = p2; -} - -test "error return trace across suspend points - async return" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const p = nonFailing(); - const p2 = async printTrace(p); - _ = p2; - resume p; -} - -fn nonFailing() (anyframe->anyerror!void) { - const Static = struct { - var frame: @Frame(suspendThenFail) = undefined; - }; - Static.frame = async suspendThenFail(); - return &Static.frame; -} -fn suspendThenFail() callconv(.@"async") anyerror!void { - suspend {} - return error.Fail; -} -fn printTrace(p: anyframe->(anyerror!void)) callconv(.@"async") void { - (await p) catch |e| { - std.testing.expect(e == error.Fail) catch @panic("test failure"); - if (@errorReturnTrace()) |trace| { - expect(trace.index == 1) catch @panic("test failure"); - } else switch (builtin.mode) { - .Debug, .ReleaseSafe => @panic("expected return trace"), - .ReleaseFast, .ReleaseSmall => {}, - } - }; -} - -test "break from suspend" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - var my_result: i32 = 1; - const p = async testBreakFromSuspend(&my_result); - _ = p; - try std.testing.expect(my_result == 2); -} -fn testBreakFromSuspend(my_result: *i32) callconv(.@"async") void { - suspend { - resume @frame(); - } - my_result.* += 1; - suspend {} - my_result.* += 1; -} - -test "heap allocated async function frame" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var x: i32 = 42; - - fn doTheTest() !void { - const frame = try std.testing.allocator.create(@Frame(someFunc)); - defer std.testing.allocator.destroy(frame); - - try expect(x == 42); - frame.* = async someFunc(); - try expect(x == 43); - resume frame; - try expect(x == 44); - } - - fn someFunc() void { - x += 1; - suspend {} - x += 1; - } - }; - try S.doTheTest(); -} - -test "async function call return value" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var frame: anyframe = undefined; - var pt = Point{ .x = 10, .y = 11 }; - - fn doTheTest() !void { - try expectEqual(pt.x, 10); - try expectEqual(pt.y, 11); - _ = async first(); - try expectEqual(pt.x, 10); - try expectEqual(pt.y, 11); - resume frame; - try expectEqual(pt.x, 1); - try expectEqual(pt.y, 2); - } - - fn first() void { - pt = second(1, 2); - } - - fn second(x: i32, y: i32) Point { - return other(x, y); - } - - fn other(x: i32, y: i32) Point { - frame = @frame(); - suspend {} - return Point{ - .x = x, - .y = y, - }; - } - - const Point = struct { - x: i32, - y: i32, - }; - }; - try S.doTheTest(); -} - -test "suspension points inside branching control flow" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var result: i32 = 10; - - fn doTheTest() !void { - try expect(10 == result); - var frame = async func(true); - try expect(10 == result); - resume frame; - try expect(11 == result); - resume frame; - try expect(12 == result); - resume frame; - try expect(13 == result); - } - - fn func(b: bool) void { - while (b) { - suspend {} - result += 1; - } - } - }; - try S.doTheTest(); -} - -test "call async function which has struct return type" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var frame: anyframe = undefined; - - fn doTheTest() void { - _ = async atest(); - resume frame; - } - - fn atest() void { - const result = func(); - expect(result.x == 5) catch @panic("test failed"); - expect(result.y == 6) catch @panic("test failed"); - } - - const Point = struct { - x: usize, - y: usize, - }; - - fn func() Point { - suspend { - frame = @frame(); - } - return Point{ - .x = 5, - .y = 6, - }; - } - }; - S.doTheTest(); -} - -test "pass string literal to async function" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var frame: anyframe = undefined; - var ok: bool = false; - - fn doTheTest() !void { - _ = async hello("hello"); - resume frame; - try expect(ok); - } - - fn hello(msg: []const u8) void { - frame = @frame(); - suspend {} - expectEqualStrings("hello", msg) catch @panic("test failed"); - ok = true; - } - }; - try S.doTheTest(); -} - -test "await inside an errdefer" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var frame: anyframe = undefined; - - fn doTheTest() !void { - _ = async amainWrap(); - resume frame; - } - - fn amainWrap() !void { - var foo = async func(); - errdefer await foo; - return error.Bad; - } - - fn func() void { - frame = @frame(); - suspend {} - } - }; - try S.doTheTest(); -} - -test "try in an async function with error union and non-zero-bit payload" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var frame: anyframe = undefined; - var ok = false; - - fn doTheTest() !void { - _ = async amain(); - resume frame; - try expect(ok); - } - - fn amain() void { - std.testing.expectError(error.Bad, theProblem()) catch @panic("test failed"); - ok = true; - } - - fn theProblem() ![]u8 { - frame = @frame(); - suspend {} - const result = try other(); - return result; - } - - fn other() ![]u8 { - return error.Bad; - } - }; - try S.doTheTest(); -} - -test "returning a const error from async function" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var frame: anyframe = undefined; - var ok = false; - - fn doTheTest() !void { - _ = async amain(); - resume frame; - try expect(ok); - } - - fn amain() !void { - var download_frame = async fetchUrl(10, "a string"); - const download_text = try await download_frame; - _ = download_text; - - @panic("should not get here"); - } - - fn fetchUrl(unused: i32, url: []const u8) ![]u8 { - _ = unused; - _ = url; - frame = @frame(); - suspend {} - ok = true; - return error.OutOfMemory; - } - }; - try S.doTheTest(); -} - -test "async/await typical usage" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - inline for ([_]bool{ false, true }) |b1| { - inline for ([_]bool{ false, true }) |b2| { - inline for ([_]bool{ false, true }) |b3| { - inline for ([_]bool{ false, true }) |b4| { - testAsyncAwaitTypicalUsage(b1, b2, b3, b4).doTheTest(); - } - } - } - } -} - -fn testAsyncAwaitTypicalUsage( - comptime simulate_fail_download: bool, - comptime simulate_fail_file: bool, - comptime suspend_download: bool, - comptime suspend_file: bool, -) type { - return struct { - fn doTheTest() void { - _ = async amainWrap(); - if (suspend_file) { - resume global_file_frame; - } - if (suspend_download) { - resume global_download_frame; - } - } - fn amainWrap() void { - if (amain()) |_| { - expect(!simulate_fail_download) catch @panic("test failure"); - expect(!simulate_fail_file) catch @panic("test failure"); - } else |e| switch (e) { - error.NoResponse => expect(simulate_fail_download) catch @panic("test failure"), - error.FileNotFound => expect(simulate_fail_file) catch @panic("test failure"), - else => @panic("test failure"), - } - } - - fn amain() !void { - const allocator = std.testing.allocator; - var download_frame = async fetchUrl(allocator, "https://example.com/"); - var download_awaited = false; - errdefer if (!download_awaited) { - if (await download_frame) |x| allocator.free(x) else |_| {} - }; - - var file_frame = async readFile(allocator, "something.txt"); - var file_awaited = false; - errdefer if (!file_awaited) { - if (await file_frame) |x| allocator.free(x) else |_| {} - }; - - download_awaited = true; - const download_text = try await download_frame; - defer allocator.free(download_text); - - file_awaited = true; - const file_text = try await file_frame; - defer allocator.free(file_text); - - try expect(std.mem.eql(u8, "expected download text", download_text)); - try expect(std.mem.eql(u8, "expected file text", file_text)); - } - - var global_download_frame: anyframe = undefined; - fn fetchUrl(allocator: std.mem.Allocator, url: []const u8) anyerror![]u8 { - _ = url; - const result = try allocator.dupe(u8, "expected download text"); - errdefer allocator.free(result); - if (suspend_download) { - suspend { - global_download_frame = @frame(); - } - } - if (simulate_fail_download) return error.NoResponse; - return result; - } - - var global_file_frame: anyframe = undefined; - fn readFile(allocator: std.mem.Allocator, filename: []const u8) anyerror![]u8 { - _ = filename; - const result = try allocator.dupe(u8, "expected file text"); - errdefer allocator.free(result); - if (suspend_file) { - suspend { - global_file_frame = @frame(); - } - } - if (simulate_fail_file) return error.FileNotFound; - return result; - } - }; -} - -test "alignment of local variables in async functions" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - fn doTheTest() !void { - var y: u8 = 123; - _ = &y; - var x: u8 align(128) = 1; - try expect(@intFromPtr(&x) % 128 == 0); - } - }; - try S.doTheTest(); -} - -test "no reason to resolve frame still works" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - _ = async simpleNothing(); -} -fn simpleNothing() void { - var x: i32 = 1234; - _ = &x; -} - -test "async call a generic function" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - fn doTheTest() !void { - var f = async func(i32, 2); - const result = await f; - try expect(result == 3); - } - - fn func(comptime T: type, inc: T) T { - var x: T = 1; - suspend { - resume @frame(); - } - x += inc; - return x; - } - }; - _ = async S.doTheTest(); -} - -test "return from suspend block" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - fn doTheTest() !void { - expect(func() == 1234) catch @panic("test failure"); - } - fn func() i32 { - suspend { - return 1234; - } - } - }; - _ = async S.doTheTest(); -} - -test "struct parameter to async function is copied to the frame" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - const Point = struct { - x: i32, - y: i32, - }; - - var frame: anyframe = undefined; - - fn doTheTest() void { - _ = async atest(); - resume frame; - } - - fn atest() void { - var f: @Frame(foo) = undefined; - bar(&f); - clobberStack(10); - } - - fn clobberStack(x: i32) void { - if (x == 0) return; - clobberStack(x - 1); - var y: i32 = x; - _ = &y; - } - - fn bar(f: *@Frame(foo)) void { - var pt = Point{ .x = 1, .y = 2 }; - _ = &pt; - f.* = async foo(pt); - const result = await f; - expect(result == 1) catch @panic("test failure"); - } - - fn foo(point: Point) i32 { - suspend { - frame = @frame(); - } - return point.x; - } - }; - S.doTheTest(); -} - -test "cast fn to async fn when it is inferred to be async" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var frame: anyframe = undefined; - var ok = false; - - fn doTheTest() void { - var ptr: fn () callconv(.@"async") i32 = undefined; - ptr = func; - var buf: [100]u8 align(16) = undefined; - var result: i32 = undefined; - const f = @asyncCall(&buf, &result, ptr, .{}); - _ = await f; - expect(result == 1234) catch @panic("test failure"); - ok = true; - } - - fn func() i32 { - suspend { - frame = @frame(); - } - return 1234; - } - }; - _ = async S.doTheTest(); - resume S.frame; - try expect(S.ok); -} - -test "cast fn to async fn when it is inferred to be async, awaited directly" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var frame: anyframe = undefined; - var ok = false; - - fn doTheTest() void { - var ptr: fn () callconv(.@"async") i32 = undefined; - ptr = func; - var buf: [100]u8 align(16) = undefined; - var result: i32 = undefined; - _ = await @asyncCall(&buf, &result, ptr, .{}); - expect(result == 1234) catch @panic("test failure"); - ok = true; - } - - fn func() i32 { - suspend { - frame = @frame(); - } - return 1234; - } - }; - _ = async S.doTheTest(); - resume S.frame; - try expect(S.ok); -} - -test "await does not force async if callee is blocking" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - fn simple() i32 { - return 1234; - } - }; - var x = async S.simple(); - try expect(await x == 1234); -} - -test "recursive async function" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - try expect(recursiveAsyncFunctionTest(false).doTheTest() == 55); - try expect(recursiveAsyncFunctionTest(true).doTheTest() == 55); -} - -fn recursiveAsyncFunctionTest(comptime suspending_implementation: bool) type { - return struct { - fn fib(allocator: std.mem.Allocator, x: u32) error{OutOfMemory}!u32 { - if (x <= 1) return x; - - if (suspending_implementation) { - suspend { - resume @frame(); - } - } - - const f1 = try allocator.create(@Frame(fib)); - defer allocator.destroy(f1); - - const f2 = try allocator.create(@Frame(fib)); - defer allocator.destroy(f2); - - f1.* = async fib(allocator, x - 1); - var f1_awaited = false; - errdefer if (!f1_awaited) { - _ = await f1; - }; - - f2.* = async fib(allocator, x - 2); - var f2_awaited = false; - errdefer if (!f2_awaited) { - _ = await f2; - }; - - var sum: u32 = 0; - - f1_awaited = true; - sum += try await f1; - - f2_awaited = true; - sum += try await f2; - - return sum; - } - - fn doTheTest() u32 { - if (suspending_implementation) { - var result: u32 = undefined; - _ = async amain(&result); - return result; - } else { - return fib(std.testing.allocator, 10) catch unreachable; - } - } - - fn amain(result: *u32) void { - var x = async fib(std.testing.allocator, 10); - result.* = (await x) catch unreachable; - } - }; -} - -test "@asyncCall with comptime-known function, but not awaited directly" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - - fn doTheTest() !void { - var frame: [1]@Frame(middle) = undefined; - var result: @typeInfo(@typeInfo(@TypeOf(middle)).@"fn".return_type.?).error_union.error_set!void = undefined; - _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle, .{}); - resume global_frame; - try std.testing.expectError(error.Fail, result); - } - fn middle() callconv(.@"async") !void { - var f = async middle2(); - return await f; - } - - fn middle2() !void { - return failing(); - } - - fn failing() !void { - global_frame = @frame(); - suspend {} - return error.Fail; - } - }; - try S.doTheTest(); -} - -test "@asyncCall with actual frame instead of byte buffer" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - fn func() i32 { - suspend {} - return 1234; - } - }; - var frame: @Frame(S.func) = undefined; - var result: i32 = undefined; - const ptr = @asyncCall(&frame, &result, S.func, .{}); - resume ptr; - try expect(result == 1234); -} - -test "@asyncCall using the result location inside the frame" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - fn simple2(y: *i32) callconv(.@"async") i32 { - defer y.* += 2; - y.* += 1; - suspend {} - return 1234; - } - fn getAnswer(f: anyframe->i32, out: *i32) void { - out.* = await f; - } - }; - var data: i32 = 1; - const Foo = struct { - bar: fn (*i32) callconv(.@"async") i32, - }; - var foo = Foo{ .bar = S.simple2 }; - _ = &foo; - var bytes: [64]u8 align(16) = undefined; - const f = @asyncCall(&bytes, {}, foo.bar, .{&data}); - comptime assert(@TypeOf(f) == anyframe->i32); - try expect(data == 2); - resume f; - try expect(data == 4); - _ = async S.getAnswer(f, &data); - try expect(data == 1234); -} - -test "@TypeOf an async function call of generic fn with error union type" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - fn func(comptime x: anytype) anyerror!i32 { - const T = @TypeOf(async func(x)); - comptime assert(T == @typeInfo(@TypeOf(@frame())).pointer.child); - return undefined; - } - }; - _ = async S.func(i32); -} - -test "using @TypeOf on a generic function call" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - var global_ok = false; - - var buf: [100]u8 align(16) = undefined; - - fn amain(x: anytype) void { - if (x == 0) { - global_ok = true; - return; - } - suspend { - global_frame = @frame(); - } - const F = @TypeOf(async amain(x - 1)); - const frame = @as(*F, @ptrFromInt(@intFromPtr(&buf))); - return await @asyncCall(frame, {}, amain, .{x - 1}); - } - }; - _ = async S.amain(@as(u32, 1)); - resume S.global_frame; - try expect(S.global_ok); -} - -test "recursive call of await @asyncCall with struct return type" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - var global_ok = false; - - var buf: [100]u8 align(16) = undefined; - - fn amain(x: anytype) Foo { - if (x == 0) { - global_ok = true; - return Foo{ .x = 1, .y = 2, .z = 3 }; - } - suspend { - global_frame = @frame(); - } - const F = @TypeOf(async amain(x - 1)); - const frame = @as(*F, @ptrFromInt(@intFromPtr(&buf))); - return await @asyncCall(frame, {}, amain, .{x - 1}); - } - - const Foo = struct { - x: u64, - y: u64, - z: u64, - }; - }; - var res: S.Foo = undefined; - var frame: @TypeOf(async S.amain(@as(u32, 1))) = undefined; - _ = @asyncCall(&frame, &res, S.amain, .{@as(u32, 1)}); - resume S.global_frame; - try expect(S.global_ok); - try expect(res.x == 1); - try expect(res.y == 2); - try expect(res.z == 3); -} - -test "nosuspend function call" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - fn doTheTest() !void { - const result = nosuspend add(50, 100); - try expect(result == 150); - } - fn add(a: i32, b: i32) i32 { - if (a > 100) { - suspend {} - } - return a + b; - } - }; - try S.doTheTest(); -} - -test "await used in expression and awaiting fn with no suspend but async calling convention" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - fn atest() void { - var f1 = async add(1, 2); - var f2 = async add(3, 4); - - const sum = (await f1) + (await f2); - expect(sum == 10) catch @panic("test failure"); - } - fn add(a: i32, b: i32) callconv(.@"async") i32 { - return a + b; - } - }; - _ = async S.atest(); -} - -test "await used in expression after a fn call" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - fn atest() void { - var f1 = async add(3, 4); - var sum: i32 = 0; - sum = foo() + await f1; - expect(sum == 8) catch @panic("test failure"); - } - fn add(a: i32, b: i32) callconv(.@"async") i32 { - return a + b; - } - fn foo() i32 { - return 1; - } - }; - _ = async S.atest(); -} - -test "async fn call used in expression after a fn call" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - fn atest() void { - var sum: i32 = 0; - sum = foo() + add(3, 4); - expect(sum == 8) catch @panic("test failure"); - } - fn add(a: i32, b: i32) callconv(.@"async") i32 { - return a + b; - } - fn foo() i32 { - return 1; - } - }; - _ = async S.atest(); -} - -test "suspend in for loop" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: ?anyframe = null; - - fn doTheTest() void { - _ = async atest(); - while (global_frame) |f| resume f; - } - - fn atest() void { - expect(func(&[_]u8{ 1, 2, 3 }) == 6) catch @panic("test failure"); - } - fn func(stuff: []const u8) u32 { - global_frame = @frame(); - var sum: u32 = 0; - for (stuff) |x| { - suspend {} - sum += x; - } - global_frame = null; - return sum; - } - }; - S.doTheTest(); -} - -test "suspend in while loop" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: ?anyframe = null; - - fn doTheTest() void { - _ = async atest(); - while (global_frame) |f| resume f; - } - - fn atest() void { - expect(optional(6) == 6) catch @panic("test failure"); - expect(errunion(6) == 6) catch @panic("test failure"); - } - fn optional(stuff: ?u32) u32 { - global_frame = @frame(); - defer global_frame = null; - while (stuff) |val| { - suspend {} - return val; - } - return 0; - } - fn errunion(stuff: anyerror!u32) u32 { - global_frame = @frame(); - defer global_frame = null; - while (stuff) |val| { - suspend {} - return val; - } else |err| { - err catch {}; - return 0; - } - } - }; - S.doTheTest(); -} - -test "correctly spill when returning the error union result of another async fn" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - - fn doTheTest() !void { - expect((atest() catch unreachable) == 1234) catch @panic("test failure"); - } - - fn atest() !i32 { - return fallible1(); - } - - fn fallible1() anyerror!i32 { - suspend { - global_frame = @frame(); - } - return 1234; - } - }; - _ = async S.doTheTest(); - resume S.global_frame; -} - -test "spill target expr in a for loop" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - - fn doTheTest() !void { - var foo = Foo{ - .slice = &[_]i32{ 1, 2 }, - }; - expect(atest(&foo) == 3) catch @panic("test failure"); - } - - const Foo = struct { - slice: []const i32, - }; - - fn atest(foo: *Foo) i32 { - var sum: i32 = 0; - for (foo.slice) |x| { - suspend { - global_frame = @frame(); - } - sum += x; - } - return sum; - } - }; - _ = async S.doTheTest(); - resume S.global_frame; - resume S.global_frame; -} - -test "spill target expr in a for loop, with a var decl in the loop body" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - - fn doTheTest() !void { - var foo = Foo{ - .slice = &[_]i32{ 1, 2 }, - }; - expect(atest(&foo) == 3) catch @panic("test failure"); - } - - const Foo = struct { - slice: []const i32, - }; - - fn atest(foo: *Foo) i32 { - var sum: i32 = 0; - for (foo.slice) |x| { - // Previously this var decl would prevent spills. This test makes sure - // the for loop spills still happen even though there is a VarDecl in scope - // before the suspend. - var anything = true; - _ = &anything; - suspend { - global_frame = @frame(); - } - sum += x; - } - return sum; - } - }; - _ = async S.doTheTest(); - resume S.global_frame; - resume S.global_frame; -} - -test "async call with @call" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - fn doTheTest() void { - _ = @call(.{ .modifier = .async_kw }, atest, .{}); - resume global_frame; - } - fn atest() void { - var frame = @call(.{ .modifier = .async_kw }, afoo, .{}); - const res = await frame; - expect(res == 42) catch @panic("test failure"); - } - fn afoo() i32 { - suspend { - global_frame = @frame(); - } - return 42; - } - }; - S.doTheTest(); -} - -test "async function passed 0-bit arg after non-0-bit arg" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - var global_int: i32 = 0; - - fn foo() void { - bar(1, .{}) catch unreachable; - } - - fn bar(x: i32, args: anytype) anyerror!void { - _ = args; - global_frame = @frame(); - suspend {} - global_int = x; - } - }; - _ = async S.foo(); - resume S.global_frame; - try expect(S.global_int == 1); -} - -test "async function passed align(16) arg after align(8) arg" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - var global_int: u128 = 0; - - fn foo() void { - var a: u128 = 99; - _ = &a; - bar(10, .{a}) catch unreachable; - } - - fn bar(x: u64, args: anytype) anyerror!void { - try expect(x == 10); - global_frame = @frame(); - suspend {} - global_int = args[0]; - } - }; - _ = async S.foo(); - resume S.global_frame; - try expect(S.global_int == 99); -} - -test "async function call resolves target fn frame, comptime func" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - var global_int: i32 = 9; - - fn foo() anyerror!void { - const stack_size = 1000; - var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; - return await @asyncCall(&stack_frame, {}, bar, .{}); - } - - fn bar() anyerror!void { - global_frame = @frame(); - suspend {} - global_int += 1; - } - }; - _ = async S.foo(); - resume S.global_frame; - try expect(S.global_int == 10); -} - -test "async function call resolves target fn frame, runtime func" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - var global_int: i32 = 9; - - fn foo() anyerror!void { - const stack_size = 1000; - var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; - var func: fn () callconv(.@"async") anyerror!void = bar; - _ = &func; - return await @asyncCall(&stack_frame, {}, func, .{}); - } - - fn bar() anyerror!void { - global_frame = @frame(); - suspend {} - global_int += 1; - } - }; - _ = async S.foo(); - resume S.global_frame; - try expect(S.global_int == 10); -} - -test "properly spill optional payload capture value" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - var global_int: usize = 2; - - fn foo() void { - var opt: ?usize = 1234; - _ = &opt; - if (opt) |x| { - bar(); - global_int += x; - } - } - - fn bar() void { - global_frame = @frame(); - suspend {} - global_int += 1; - } - }; - _ = async S.foo(); - resume S.global_frame; - try expect(S.global_int == 1237); -} - -test "handle defer interfering with return value spill" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame1: anyframe = undefined; - var global_frame2: anyframe = undefined; - var finished = false; - var baz_happened = false; - - fn doTheTest() !void { - _ = async testFoo(); - resume global_frame1; - resume global_frame2; - try expect(baz_happened); - try expect(finished); - } - - fn testFoo() void { - expectError(error.Bad, foo()) catch @panic("test failure"); - finished = true; - } - - fn foo() anyerror!void { - defer baz(); - return bar() catch |err| return err; - } - - fn bar() anyerror!void { - global_frame1 = @frame(); - suspend {} - return error.Bad; - } - - fn baz() void { - global_frame2 = @frame(); - suspend {} - baz_happened = true; - } - }; - try S.doTheTest(); -} - -test "take address of temporary async frame" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var global_frame: anyframe = undefined; - var finished = false; - - fn doTheTest() !void { - _ = async asyncDoTheTest(); - resume global_frame; - try expect(finished); - } - - fn asyncDoTheTest() void { - expect(finishIt(&async foo(10)) == 1245) catch @panic("test failure"); - finished = true; - } - - fn foo(arg: i32) i32 { - global_frame = @frame(); - suspend {} - return arg + 1234; - } - - fn finishIt(frame: anyframe->i32) i32 { - return (await frame) + 1; - } - }; - try S.doTheTest(); -} - -test "nosuspend await" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var finished = false; - - fn doTheTest() !void { - var frame = async foo(false); - try expect(nosuspend await frame == 42); - finished = true; - } - - fn foo(want_suspend: bool) i32 { - if (want_suspend) { - suspend {} - } - return 42; - } - }; - try S.doTheTest(); - try expect(S.finished); -} - -test "nosuspend on function calls" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S0 = struct { - b: i32 = 42, - }; - const S1 = struct { - fn c() S0 { - return S0{}; - } - fn d() !S0 { - return S0{}; - } - }; - try expectEqual(@as(i32, 42), nosuspend S1.c().b); - try expectEqual(@as(i32, 42), (try nosuspend S1.d()).b); -} - -test "nosuspend on async function calls" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S0 = struct { - b: i32 = 42, - }; - const S1 = struct { - fn c() S0 { - return S0{}; - } - fn d() !S0 { - return S0{}; - } - }; - var frame_c = nosuspend async S1.c(); - try expectEqual(@as(i32, 42), (await frame_c).b); - var frame_d = nosuspend async S1.d(); - try expectEqual(@as(i32, 42), (try await frame_d).b); -} - -// test "resume nosuspend async function calls" { -// if (true) return error.SkipZigTest; // if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO -// const S0 = struct { -// b: i32 = 42, -// }; -// const S1 = struct { -// fn c() S0 { -// suspend {} -// return S0{}; -// } -// fn d() !S0 { -// suspend {} -// return S0{}; -// } -// }; -// var frame_c = nosuspend async S1.c(); -// resume frame_c; -// try expectEqual(@as(i32, 42), (await frame_c).b); -// var frame_d = nosuspend async S1.d(); -// resume frame_d; -// try expectEqual(@as(i32, 42), (try await frame_d).b); -// } - -test "nosuspend resume async function calls" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S0 = struct { - b: i32 = 42, - }; - const S1 = struct { - fn c() S0 { - suspend {} - return S0{}; - } - fn d() !S0 { - suspend {} - return S0{}; - } - }; - var frame_c = async S1.c(); - nosuspend resume frame_c; - try expectEqual(@as(i32, 42), (await frame_c).b); - var frame_d = async S1.d(); - nosuspend resume frame_d; - try expectEqual(@as(i32, 42), (try await frame_d).b); -} - -test "avoid forcing frame alignment resolution implicit cast to *anyopaque" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const S = struct { - var x: ?*anyopaque = null; - - fn foo() bool { - suspend { - x = @frame(); - } - return true; - } - }; - var frame = async S.foo(); - resume @as(anyframe->bool, @ptrCast(@alignCast(S.x))); - try expect(nosuspend await frame); -} - -test "@asyncCall with pass-by-value arguments" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const F0: u64 = 0xbeefbeefbeefbeef; - const F1: u64 = 0xf00df00df00df00d; - const F2: u64 = 0xcafecafecafecafe; - - const S = struct { - pub const ST = struct { f0: usize, f1: usize }; - pub const AT = [5]u8; - - pub fn f(_fill0: u64, s: ST, _fill1: u64, a: AT, _fill2: u64) callconv(.@"async") void { - _ = s; - _ = a; - // Check that the array and struct arguments passed by value don't - // end up overflowing the adjacent fields in the frame structure. - expectEqual(F0, _fill0) catch @panic("test failure"); - expectEqual(F1, _fill1) catch @panic("test failure"); - expectEqual(F2, _fill2) catch @panic("test failure"); - } - }; - - var buffer: [1024]u8 align(@alignOf(@Frame(S.f))) = undefined; - // The function pointer must not be comptime-known. - var t = S.f; - _ = &t; - var frame_ptr = @asyncCall(&buffer, {}, t, .{ - F0, - .{ .f0 = 1, .f1 = 2 }, - F1, - [_]u8{ 1, 2, 3, 4, 5 }, - F2, - }); - _ = &frame_ptr; -} - -test "@asyncCall with arguments having non-standard alignment" { - if (true) return error.SkipZigTest; // TODO - if (builtin.os.tag == .wasi) return error.SkipZigTest; // TODO - - const F0: u64 = 0xbeefbeef; - const F1: u64 = 0xf00df00df00df00d; - - const S = struct { - pub fn f(_fill0: u32, s: struct { x: u64 align(16) }, _fill1: u64) callconv(.@"async") void { - _ = s; - // The compiler inserts extra alignment for s, check that the - // generated code picks the right slot for fill1. - expectEqual(F0, _fill0) catch @panic("test failure"); - expectEqual(F1, _fill1) catch @panic("test failure"); - } - }; - - var buffer: [1024]u8 align(@alignOf(@Frame(S.f))) = undefined; - // The function pointer must not be comptime-known. - var t = S.f; - _ = &t; - var frame_ptr = @asyncCall(&buffer, {}, t, .{ F0, undefined, F1 }); - _ = &frame_ptr; -} diff --git a/test/behavior/await_struct.zig b/test/behavior/await_struct.zig deleted file mode 100644 index c919922f03..0000000000 --- a/test/behavior/await_struct.zig +++ /dev/null @@ -1,47 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const expect = std.testing.expect; - -const Foo = struct { - x: i32, -}; - -var await_a_promise: anyframe = undefined; -var await_final_result = Foo{ .x = 0 }; - -test "coroutine await struct" { - if (true) return error.SkipZigTest; // TODO - - await_seq('a'); - var p = async await_amain(); - _ = &p; - await_seq('f'); - resume await_a_promise; - await_seq('i'); - try expect(await_final_result.x == 1234); - try expect(std.mem.eql(u8, &await_points, "abcdefghi")); -} -fn await_amain() callconv(.@"async") void { - await_seq('b'); - var p = async await_another(); - await_seq('e'); - await_final_result = await p; - await_seq('h'); -} -fn await_another() callconv(.@"async") Foo { - await_seq('c'); - suspend { - await_seq('d'); - await_a_promise = @frame(); - } - await_seq('g'); - return Foo{ .x = 1234 }; -} - -var await_points = [_]u8{0} ** "abcdefghi".len; -var await_seq_index: usize = 0; - -fn await_seq(c: u8) void { - await_points[await_seq_index] = c; - await_seq_index += 1; -} diff --git a/test/behavior/call.zig b/test/behavior/call.zig index 5cfae1b35d..ee0084b21f 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -37,7 +37,7 @@ test "basic invocations" { comptime { // comptime calls with supported modifiers try expect(@call(.auto, foo, .{2}) == 1234); - try expect(@call(.no_async, foo, .{3}) == 1234); + try expect(@call(.no_suspend, foo, .{3}) == 1234); try expect(@call(.always_tail, foo, .{4}) == 1234); try expect(@call(.always_inline, foo, .{5}) == 1234); } @@ -45,7 +45,7 @@ test "basic invocations" { const result = @call(.compile_time, foo, .{6}) == 1234; comptime assert(result); // runtime calls of comptime-known function - try expect(@call(.no_async, foo, .{7}) == 1234); + try expect(@call(.no_suspend, foo, .{7}) == 1234); try expect(@call(.never_tail, foo, .{8}) == 1234); try expect(@call(.never_inline, foo, .{9}) == 1234); // CBE does not support attributes on runtime functions @@ -53,7 +53,7 @@ test "basic invocations" { // runtime calls of non comptime-known function var alias_foo = &foo; _ = &alias_foo; - try expect(@call(.no_async, alias_foo, .{10}) == 1234); + try expect(@call(.no_suspend, alias_foo, .{10}) == 1234); try expect(@call(.never_tail, alias_foo, .{11}) == 1234); try expect(@call(.never_inline, alias_foo, .{12}) == 1234); } diff --git a/test/cases/compile_errors/async/async_function_depends_on_its_own_frame.zig b/test/cases/compile_errors/async/async_function_depends_on_its_own_frame.zig deleted file mode 100644 index a1bd3c01e7..0000000000 --- a/test/cases/compile_errors/async/async_function_depends_on_its_own_frame.zig +++ /dev/null @@ -1,13 +0,0 @@ -export fn entry() void { - _ = async amain(); -} -fn amain() callconv(.@"async") void { - var x: [@sizeOf(@Frame(amain))]u8 = undefined; - _ = &x; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:4:1: error: cannot resolve '@Frame(amain)': function not fully analyzed yet diff --git a/test/cases/compile_errors/async/async_function_indirectly_depends_on_its_own_frame.zig b/test/cases/compile_errors/async/async_function_indirectly_depends_on_its_own_frame.zig deleted file mode 100644 index b4944eefc3..0000000000 --- a/test/cases/compile_errors/async/async_function_indirectly_depends_on_its_own_frame.zig +++ /dev/null @@ -1,17 +0,0 @@ -export fn entry() void { - _ = async amain(); -} -fn amain() callconv(.@"async") void { - other(); -} -fn other() void { - var x: [@sizeOf(@Frame(amain))]u8 = undefined; - _ = &x; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:4:1: error: unable to determine async function frame of 'amain' -// tmp.zig:5:10: note: analysis of function 'other' depends on the frame diff --git a/test/cases/compile_errors/async/const_frame_cast_to_anyframe.zig b/test/cases/compile_errors/async/const_frame_cast_to_anyframe.zig deleted file mode 100644 index 52b866afcf..0000000000 --- a/test/cases/compile_errors/async/const_frame_cast_to_anyframe.zig +++ /dev/null @@ -1,19 +0,0 @@ -export fn a() void { - const f = async func(); - resume f; -} -export fn b() void { - const f = async func(); - var x: anyframe = &f; - _ = &x; -} -fn func() void { - suspend {} -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:12: error: expected type 'anyframe', found '*const @Frame(func)' -// tmp.zig:7:24: error: expected type 'anyframe', found '*const @Frame(func)' diff --git a/test/cases/compile_errors/async/function_with_ccc_indirectly_calling_async_function.zig b/test/cases/compile_errors/async/function_with_ccc_indirectly_calling_async_function.zig deleted file mode 100644 index 9fadb992b4..0000000000 --- a/test/cases/compile_errors/async/function_with_ccc_indirectly_calling_async_function.zig +++ /dev/null @@ -1,18 +0,0 @@ -export fn entry() void { - foo(); -} -fn foo() void { - bar(); -} -fn bar() void { - suspend {} -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:1:1: error: function with calling convention 'C' cannot be async -// tmp.zig:2:8: note: async function call here -// tmp.zig:5:8: note: async function call here -// tmp.zig:8:5: note: suspends here diff --git a/test/cases/compile_errors/async/indirect_recursion_of_async_functions_detected.zig b/test/cases/compile_errors/async/indirect_recursion_of_async_functions_detected.zig deleted file mode 100644 index 804baed45f..0000000000 --- a/test/cases/compile_errors/async/indirect_recursion_of_async_functions_detected.zig +++ /dev/null @@ -1,36 +0,0 @@ -var frame: ?anyframe = null; - -export fn a() void { - _ = async rangeSum(10); - while (frame) |f| resume f; -} - -fn rangeSum(x: i32) i32 { - suspend { - frame = @frame(); - } - frame = null; - - if (x == 0) return 0; - const child = rangeSumIndirect(x - 1); - return child + 1; -} - -fn rangeSumIndirect(x: i32) i32 { - suspend { - frame = @frame(); - } - frame = null; - - if (x == 0) return 0; - const child = rangeSum(x - 1); - return child + 1; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:8:1: error: '@Frame(rangeSum)' depends on itself -// tmp.zig:15:35: note: when analyzing type '@Frame(rangeSum)' here -// tmp.zig:28:25: note: when analyzing type '@Frame(rangeSumIndirect)' here diff --git a/test/cases/compile_errors/async/invalid_suspend_in_exported_function.zig b/test/cases/compile_errors/async/invalid_suspend_in_exported_function.zig deleted file mode 100644 index fb3488ce95..0000000000 --- a/test/cases/compile_errors/async/invalid_suspend_in_exported_function.zig +++ /dev/null @@ -1,15 +0,0 @@ -export fn entry() void { - var frame = async func(); - var result = await frame; - _ = &result; -} -fn func() void { - suspend {} -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:1:1: error: function with calling convention 'C' cannot be async -// tmp.zig:3:18: note: await here is a suspend point diff --git a/test/cases/compile_errors/async/returning_error_from_void_async_function.zig b/test/cases/compile_errors/async/returning_error_from_void_async_function.zig deleted file mode 100644 index 97e29accd2..0000000000 --- a/test/cases/compile_errors/async/returning_error_from_void_async_function.zig +++ /dev/null @@ -1,12 +0,0 @@ -export fn entry() void { - _ = async amain(); -} -fn amain() callconv(.@"async") void { - return error.ShouldBeCompileError; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:5:17: error: expected type 'void', found 'error{ShouldBeCompileError}' diff --git a/test/cases/compile_errors/async/runtime-known_async_function_called.zig b/test/cases/compile_errors/async/runtime-known_async_function_called.zig deleted file mode 100644 index b3e7fabcea..0000000000 --- a/test/cases/compile_errors/async/runtime-known_async_function_called.zig +++ /dev/null @@ -1,15 +0,0 @@ -export fn entry() void { - _ = async amain(); -} -fn amain() void { - var ptr = afunc; - _ = ptr(); - _ = &ptr; -} -fn afunc() callconv(.@"async") void {} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:6:12: error: function is not comptime-known; @asyncCall required diff --git a/test/cases/compile_errors/async/runtime-known_function_called_with_async_keyword.zig b/test/cases/compile_errors/async/runtime-known_function_called_with_async_keyword.zig deleted file mode 100644 index 082251c137..0000000000 --- a/test/cases/compile_errors/async/runtime-known_function_called_with_async_keyword.zig +++ /dev/null @@ -1,13 +0,0 @@ -export fn entry() void { - var ptr = afunc; - _ = async ptr(); - _ = &ptr; -} - -fn afunc() callconv(.@"async") void {} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:15: error: function is not comptime-known; @asyncCall required diff --git a/test/cases/compile_errors/async/wrong_frame_type_used_for_async_call.zig b/test/cases/compile_errors/async/wrong_frame_type_used_for_async_call.zig deleted file mode 100644 index c02c20f495..0000000000 --- a/test/cases/compile_errors/async/wrong_frame_type_used_for_async_call.zig +++ /dev/null @@ -1,16 +0,0 @@ -export fn entry() void { - var frame: @Frame(foo) = undefined; - frame = async bar(); -} -fn foo() void { - suspend {} -} -fn bar() void { - suspend {} -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:13: error: expected type '*@Frame(bar)', found '*@Frame(foo)' diff --git a/test/cases/compile_errors/async/wrong_type_for_result_ptr_to_asyncCall.zig b/test/cases/compile_errors/async/wrong_type_for_result_ptr_to_asyncCall.zig deleted file mode 100644 index b4193d4de1..0000000000 --- a/test/cases/compile_errors/async/wrong_type_for_result_ptr_to_asyncCall.zig +++ /dev/null @@ -1,16 +0,0 @@ -export fn entry() void { - _ = async amain(); -} -fn amain() i32 { - var frame: @Frame(foo) = undefined; - return await @asyncCall(&frame, false, foo, .{}); -} -fn foo() i32 { - return 1234; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:6:37: error: expected type '*i32', found 'bool' diff --git a/test/cases/compile_errors/combination_of_nosuspend_and_async.zig b/test/cases/compile_errors/combination_of_nosuspend_and_async.zig deleted file mode 100644 index dd853432b6..0000000000 --- a/test/cases/compile_errors/combination_of_nosuspend_and_async.zig +++ /dev/null @@ -1,15 +0,0 @@ -export fn entry() void { - nosuspend { - const bar = async foo(); - suspend {} - resume bar; - } -} -fn foo() void {} - -// error -// backend=stage2 -// target=native -// -// :4:9: error: suspend inside nosuspend block -// :2:5: note: nosuspend block here diff --git a/test/cases/compile_errors/suspend_inside_suspend_block.zig b/test/cases/compile_errors/suspend_inside_suspend_block.zig deleted file mode 100644 index 5963f1c0ec..0000000000 --- a/test/cases/compile_errors/suspend_inside_suspend_block.zig +++ /dev/null @@ -1,15 +0,0 @@ -export fn entry() void { - _ = async foo(); -} -fn foo() void { - suspend { - suspend {} - } -} - -// error -// backend=stage2 -// target=native -// -// :6:9: error: cannot suspend inside suspend block -// :5:5: note: other suspend block here diff --git a/test/cases/safety/@asyncCall with too small a frame.zig b/test/cases/safety/@asyncCall with too small a frame.zig deleted file mode 100644 index 00fbcef537..0000000000 --- a/test/cases/safety/@asyncCall with too small a frame.zig +++ /dev/null @@ -1,26 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); - -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { - _ = message; - _ = stack_trace; - std.process.exit(0); -} -pub fn main() !void { - if (builtin.zig_backend == .stage1 and builtin.os.tag == .wasi) { - // TODO file a bug for this failure - std.process.exit(0); // skip the test - } - var bytes: [1]u8 align(16) = undefined; - var ptr = other; - _ = &ptr; - var frame = @asyncCall(&bytes, {}, ptr, .{}); - _ = &frame; - return error.TestFailed; -} -fn other() callconv(.@"async") void { - suspend {} -} -// run -// backend=stage1 -// target=native diff --git a/test/cases/safety/awaiting twice.zig b/test/cases/safety/awaiting twice.zig deleted file mode 100644 index 6767ad4e76..0000000000 --- a/test/cases/safety/awaiting twice.zig +++ /dev/null @@ -1,29 +0,0 @@ -const std = @import("std"); - -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { - _ = message; - _ = stack_trace; - std.process.exit(0); -} -var frame: anyframe = undefined; - -pub fn main() !void { - _ = async amain(); - resume frame; - return error.TestFailed; -} - -fn amain() void { - var f = async func(); - await f; - await f; -} - -fn func() void { - suspend { - frame = @frame(); - } -} -// run -// backend=stage1 -// target=native diff --git a/test/cases/safety/error return trace across suspend points.zig b/test/cases/safety/error return trace across suspend points.zig deleted file mode 100644 index efd611662a..0000000000 --- a/test/cases/safety/error return trace across suspend points.zig +++ /dev/null @@ -1,38 +0,0 @@ -const std = @import("std"); - -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { - _ = message; - _ = stack_trace; - std.process.exit(0); -} - -var failing_frame: @Frame(failing) = undefined; - -pub fn main() !void { - const p = nonFailing(); - resume p; - const p2 = async printTrace(p); - _ = p2; - return error.TestFailed; -} - -fn nonFailing() anyframe->anyerror!void { - failing_frame = async failing(); - return &failing_frame; -} - -fn failing() anyerror!void { - suspend {} - return second(); -} - -fn second() callconv(.@"async") anyerror!void { - return error.Fail; -} - -fn printTrace(p: anyframe->anyerror!void) void { - (await p) catch unreachable; -} -// run -// backend=stage1 -// target=native diff --git a/test/cases/safety/invalid resume of async function.zig b/test/cases/safety/invalid resume of async function.zig deleted file mode 100644 index c58f13b99d..0000000000 --- a/test/cases/safety/invalid resume of async function.zig +++ /dev/null @@ -1,19 +0,0 @@ -const std = @import("std"); - -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { - _ = message; - _ = stack_trace; - std.process.exit(0); -} -pub fn main() !void { - var p = async suspendOnce(); - resume p; //ok - resume p; //bad - return error.TestFailed; -} -fn suspendOnce() void { - suspend {} -} -// run -// backend=stage1 -// target=native diff --git a/test/cases/safety/resuming a function which is awaiting a call.zig b/test/cases/safety/resuming a function which is awaiting a call.zig deleted file mode 100644 index 47545584ea..0000000000 --- a/test/cases/safety/resuming a function which is awaiting a call.zig +++ /dev/null @@ -1,21 +0,0 @@ -const std = @import("std"); - -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { - _ = message; - _ = stack_trace; - std.process.exit(0); -} -pub fn main() !void { - var frame = async first(); - resume frame; - return error.TestFailed; -} -fn first() void { - other(); -} -fn other() void { - suspend {} -} -// run -// backend=stage1 -// target=native diff --git a/test/cases/safety/resuming a function which is awaiting a frame.zig b/test/cases/safety/resuming a function which is awaiting a frame.zig deleted file mode 100644 index 26df1ae900..0000000000 --- a/test/cases/safety/resuming a function which is awaiting a frame.zig +++ /dev/null @@ -1,22 +0,0 @@ -const std = @import("std"); - -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { - _ = message; - _ = stack_trace; - std.process.exit(0); -} -pub fn main() !void { - var frame = async first(); - resume frame; - return error.TestFailed; -} -fn first() void { - var frame = async other(); - await frame; -} -fn other() void { - suspend {} -} -// run -// backend=stage1 -// target=native diff --git a/test/cases/safety/resuming a non-suspended function which has been suspended and resumed.zig b/test/cases/safety/resuming a non-suspended function which has been suspended and resumed.zig deleted file mode 100644 index f8bf6d44c0..0000000000 --- a/test/cases/safety/resuming a non-suspended function which has been suspended and resumed.zig +++ /dev/null @@ -1,32 +0,0 @@ -const std = @import("std"); - -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { - _ = message; - _ = stack_trace; - std.process.exit(0); -} -fn foo() void { - suspend { - global_frame = @frame(); - } - var f = async bar(@frame()); - _ = &f; - std.process.exit(1); -} - -fn bar(frame: anyframe) void { - suspend { - resume frame; - } - std.process.exit(1); -} - -var global_frame: anyframe = undefined; -pub fn main() !void { - _ = async foo(); - resume global_frame; - std.process.exit(1); -} -// run -// backend=stage1 -// target=native diff --git a/test/cases/safety/resuming a non-suspended function which never been suspended.zig b/test/cases/safety/resuming a non-suspended function which never been suspended.zig deleted file mode 100644 index af288ab8ba..0000000000 --- a/test/cases/safety/resuming a non-suspended function which never been suspended.zig +++ /dev/null @@ -1,27 +0,0 @@ -const std = @import("std"); - -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { - _ = message; - _ = stack_trace; - std.process.exit(0); -} -fn foo() void { - var f = async bar(@frame()); - _ = &f; - std.process.exit(1); -} - -fn bar(frame: anyframe) void { - suspend { - resume frame; - } - std.process.exit(1); -} - -pub fn main() !void { - _ = async foo(); - return error.TestFailed; -} -// run -// backend=stage1 -// target=native diff --git a/tools/docgen.zig b/tools/docgen.zig index 6b3e898b9f..054df8e2b5 100644 --- a/tools/docgen.zig +++ b/tools/docgen.zig @@ -710,8 +710,6 @@ fn tokenizeAndPrintRaw( .keyword_align, .keyword_and, .keyword_asm, - .keyword_async, - .keyword_await, .keyword_break, .keyword_catch, .keyword_comptime, diff --git a/tools/doctest.zig b/tools/doctest.zig index af5ce9f983..5193dd42a9 100644 --- a/tools/doctest.zig +++ b/tools/doctest.zig @@ -653,8 +653,6 @@ fn tokenizeAndPrint(arena: Allocator, out: anytype, raw_src: []const u8) !void { .keyword_align, .keyword_and, .keyword_asm, - .keyword_async, - .keyword_await, .keyword_break, .keyword_catch, .keyword_comptime, diff --git a/tools/lldb_pretty_printers.py b/tools/lldb_pretty_printers.py index 63bcb63111..354b4f7d15 100644 --- a/tools/lldb_pretty_printers.py +++ b/tools/lldb_pretty_printers.py @@ -50,8 +50,6 @@ zig_keywords = { 'anyframe', 'anytype', 'asm', - 'async', - 'await', 'break', 'callconv', 'catch',