diff --git a/src/all_types.hpp b/src/all_types.hpp index 3f61e77f6..a2b569898 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1346,7 +1346,16 @@ struct ZigFn { Scope *child_scope; // parent is scope for last parameter ScopeBlock *def_scope; // parent is child_scope Buf symbol_name; - ZigType *type_entry; // function type + // This is the function type assuming the function does not suspend. + // Note that for an async function, this can be shared with non-async functions. So the value here + // should only be read for things in common between non-async and async function types. + ZigType *type_entry; + // For normal functions one could use the type_entry->raw_type_ref and type_entry->raw_di_type. + // However for functions that suspend, those values could possibly be their non-suspending equivalents. + // So these values should be preferred. + LLVMTypeRef raw_type_ref; + ZigLLVMDIType *raw_di_type; + ZigType *frame_type; // coro frame type // in the case of normal functions this is the implicit return type // in the case of async functions this is the implicit return type according to the diff --git a/src/analyze.cpp b/src/analyze.cpp index 2b93c390e..91a100795 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3750,7 +3750,7 @@ bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *sour return true; } -void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node) { +static void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node) { ZigType *fn_type = fn_table_entry->type_entry; assert(!fn_type->data.fn.is_generic); FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; @@ -5850,6 +5850,7 @@ static const ZigTypeId all_type_ids[] = { ZigTypeIdBoundFn, ZigTypeIdArgTuple, ZigTypeIdOpaque, + ZigTypeIdCoroFrame, ZigTypeIdVector, ZigTypeIdEnumLiteral, }; @@ -7035,7 +7036,13 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) { } void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) { - if (fn_type->llvm_di_type != nullptr) return; + if (fn_type->llvm_di_type != nullptr) { + if (fn != nullptr) { + fn->raw_type_ref = fn_type->data.fn.raw_type_ref; + fn->raw_di_type = fn_type->data.fn.raw_di_type; + } + return; + } FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; bool first_arg_return = want_first_arg_sret(g, fn_type_id); @@ -7118,6 +7125,12 @@ void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) { for (size_t i = 0; i < gen_param_types.length; i += 1) { assert(gen_param_types.items[i] != nullptr); } + if (fn != nullptr) { + fn->raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type), + gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args); + fn->raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0); + return; + } fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type), gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args); fn_type->llvm_type = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); diff --git a/src/analyze.hpp b/src/analyze.hpp index 286ff5e04..3f226080b 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -105,7 +105,6 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max); void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val); -void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node); ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent); ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent); diff --git a/src/codegen.cpp b/src/codegen.cpp index 4dc1d9ed8..4a9e5fd62 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -499,7 +499,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { ZigType *fn_type = fn_table_entry->type_entry; // Make the raw_type_ref populated resolve_llvm_types_fn(g, fn_type, fn_table_entry); - LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref; + LLVMTypeRef fn_llvm_type = fn_table_entry->raw_type_ref; if (fn_table_entry->body_node == nullptr) { LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name)); if (existing_llvm_fn) { @@ -521,9 +521,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { assert(entry->value->id == TldIdFn); TldFn *tld_fn = reinterpret_cast(entry->value); // Make the raw_type_ref populated - (void)get_llvm_type(g, tld_fn->fn_entry->type_entry); + resolve_llvm_types_fn(g, tld_fn->fn_entry->type_entry, tld_fn->fn_entry); tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), - tld_fn->fn_entry->type_entry->data.fn.raw_type_ref); + tld_fn->fn_entry->raw_type_ref); fn_table_entry->llvm_value = LLVMConstBitCast(tld_fn->fn_entry->llvm_value, LLVMPointerType(fn_llvm_type, 0)); return fn_table_entry->llvm_value; @@ -683,10 +683,11 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { unsigned flags = ZigLLVM_DIFlags_StaticMember; ZigLLVMDIScope *fn_di_scope = get_di_scope(g, scope->parent); assert(fn_di_scope != nullptr); + assert(fn_table_entry->raw_di_type != nullptr); ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "", import->data.structure.root_struct->di_file, line_number, - fn_table_entry->type_entry->data.fn.raw_di_type, is_internal_linkage, + fn_table_entry->raw_di_type, is_internal_linkage, is_definition, scope_line, flags, is_optimized, nullptr); scope->di_scope = ZigLLVMSubprogramToScope(subprogram); @@ -3472,10 +3473,13 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr } gen_param_values.append(result_loc); - } else if (first_arg_ret) { - gen_param_values.append(result_loc); - } else if (prefix_arg_err_ret_stack) { - gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope)); + } else { + if (first_arg_ret) { + gen_param_values.append(result_loc); + } + if (prefix_arg_err_ret_stack) { + gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope)); + } } FnWalk fn_walk = {}; fn_walk.id = FnWalkIdCall; diff --git a/std/hash_map.zig b/std/hash_map.zig index 4327bfddd..bdd6cc751 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -535,17 +535,18 @@ pub fn getAutoEqlFn(comptime K: type) (fn (K, K) bool) { // TODO improve these hash functions pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type) HashInt { switch (@typeInfo(@typeOf(key))) { - builtin.TypeId.NoReturn, - builtin.TypeId.Opaque, - builtin.TypeId.Undefined, - builtin.TypeId.ArgTuple, + .NoReturn, + .Opaque, + .Undefined, + .ArgTuple, + .Frame, => @compileError("cannot hash this type"), - builtin.TypeId.Void, - builtin.TypeId.Null, + .Void, + .Null, => return 0, - builtin.TypeId.Int => |info| { + .Int => |info| { const unsigned_x = @bitCast(@IntType(false, info.bits), key); if (info.bits <= HashInt.bit_count) { return HashInt(unsigned_x) ^ comptime rng.scalar(HashInt); @@ -554,26 +555,26 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type } }, - builtin.TypeId.Float => |info| { + .Float => |info| { return autoHash(@bitCast(@IntType(false, info.bits), key), rng, HashInt); }, - builtin.TypeId.Bool => return autoHash(@boolToInt(key), rng, HashInt), - builtin.TypeId.Enum => return autoHash(@enumToInt(key), rng, HashInt), - builtin.TypeId.ErrorSet => return autoHash(@errorToInt(key), rng, HashInt), - builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng, HashInt), + .Bool => return autoHash(@boolToInt(key), rng, HashInt), + .Enum => return autoHash(@enumToInt(key), rng, HashInt), + .ErrorSet => return autoHash(@errorToInt(key), rng, HashInt), + .Fn => return autoHash(@ptrToInt(key), rng, HashInt), - builtin.TypeId.BoundFn, - builtin.TypeId.ComptimeFloat, - builtin.TypeId.ComptimeInt, - builtin.TypeId.Type, - builtin.TypeId.EnumLiteral, + .BoundFn, + .ComptimeFloat, + .ComptimeInt, + .Type, + .EnumLiteral, => return 0, - builtin.TypeId.Pointer => |info| switch (info.size) { - builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto hash for single item pointers"), - builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto hash for many item pointers"), - builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto hash C pointers"), - builtin.TypeInfo.Pointer.Size.Slice => { + .Pointer => |info| switch (info.size) { + .One => @compileError("TODO auto hash for single item pointers"), + .Many => @compileError("TODO auto hash for many item pointers"), + .C => @compileError("TODO auto hash C pointers"), + .Slice => { const interval = std.math.max(1, key.len / 256); var i: usize = 0; var h = comptime rng.scalar(HashInt); @@ -584,44 +585,44 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type }, }, - builtin.TypeId.Optional => @compileError("TODO auto hash for optionals"), - builtin.TypeId.Array => @compileError("TODO auto hash for arrays"), - builtin.TypeId.Vector => @compileError("TODO auto hash for vectors"), - builtin.TypeId.Struct => @compileError("TODO auto hash for structs"), - builtin.TypeId.Union => @compileError("TODO auto hash for unions"), - builtin.TypeId.ErrorUnion => @compileError("TODO auto hash for unions"), + .Optional => @compileError("TODO auto hash for optionals"), + .Array => @compileError("TODO auto hash for arrays"), + .Vector => @compileError("TODO auto hash for vectors"), + .Struct => @compileError("TODO auto hash for structs"), + .Union => @compileError("TODO auto hash for unions"), + .ErrorUnion => @compileError("TODO auto hash for unions"), } } pub fn autoEql(a: var, b: @typeOf(a)) bool { switch (@typeInfo(@typeOf(a))) { - builtin.TypeId.NoReturn, - builtin.TypeId.Opaque, - builtin.TypeId.Undefined, - builtin.TypeId.ArgTuple, + .NoReturn, + .Opaque, + .Undefined, + .ArgTuple, => @compileError("cannot test equality of this type"), - builtin.TypeId.Void, - builtin.TypeId.Null, + .Void, + .Null, => return true, - builtin.TypeId.Bool, - builtin.TypeId.Int, - builtin.TypeId.Float, - builtin.TypeId.ComptimeFloat, - builtin.TypeId.ComptimeInt, - builtin.TypeId.EnumLiteral, - builtin.TypeId.Promise, - builtin.TypeId.Enum, - builtin.TypeId.BoundFn, - builtin.TypeId.Fn, - builtin.TypeId.ErrorSet, - builtin.TypeId.Type, + .Bool, + .Int, + .Float, + .ComptimeFloat, + .ComptimeInt, + .EnumLiteral, + .Promise, + .Enum, + .BoundFn, + .Fn, + .ErrorSet, + .Type, => return a == b, - builtin.TypeId.Pointer => |info| switch (info.size) { - builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto eql for single item pointers"), - builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto eql for many item pointers"), - builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto eql for C pointers"), - builtin.TypeInfo.Pointer.Size.Slice => { + .Pointer => |info| switch (info.size) { + .One => @compileError("TODO auto eql for single item pointers"), + .Many => @compileError("TODO auto eql for many item pointers"), + .C => @compileError("TODO auto eql for C pointers"), + .Slice => { if (a.len != b.len) return false; for (a) |a_item, i| { if (!autoEql(a_item, b[i])) return false; @@ -630,11 +631,11 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool { }, }, - builtin.TypeId.Optional => @compileError("TODO auto eql for optionals"), - builtin.TypeId.Array => @compileError("TODO auto eql for arrays"), - builtin.TypeId.Struct => @compileError("TODO auto eql for structs"), - builtin.TypeId.Union => @compileError("TODO auto eql for unions"), - builtin.TypeId.ErrorUnion => @compileError("TODO auto eql for unions"), - builtin.TypeId.Vector => @compileError("TODO auto eql for vectors"), + .Optional => @compileError("TODO auto eql for optionals"), + .Array => @compileError("TODO auto eql for arrays"), + .Struct => @compileError("TODO auto eql for structs"), + .Union => @compileError("TODO auto eql for unions"), + .ErrorUnion => @compileError("TODO auto eql for unions"), + .Vector => @compileError("TODO auto eql for vectors"), } } diff --git a/std/testing.zig b/std/testing.zig index 84f6cff5d..3c4772cf3 100644 --- a/std/testing.zig +++ b/std/testing.zig @@ -25,35 +25,36 @@ pub fn expectError(expected_error: anyerror, actual_error_union: var) void { /// The types must match exactly. pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { switch (@typeInfo(@typeOf(actual))) { - TypeId.NoReturn, - TypeId.BoundFn, - TypeId.ArgTuple, - TypeId.Opaque, + .NoReturn, + .BoundFn, + .ArgTuple, + .Opaque, + .Frame, => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"), - TypeId.Undefined, - TypeId.Null, - TypeId.Void, + .Undefined, + .Null, + .Void, => return, - TypeId.Type, - TypeId.Bool, - TypeId.Int, - TypeId.Float, - TypeId.ComptimeFloat, - TypeId.ComptimeInt, - TypeId.EnumLiteral, - TypeId.Enum, - TypeId.Fn, - TypeId.Vector, - TypeId.ErrorSet, + .Type, + .Bool, + .Int, + .Float, + .ComptimeFloat, + .ComptimeInt, + .EnumLiteral, + .Enum, + .Fn, + .Vector, + .ErrorSet, => { if (actual != expected) { std.debug.panic("expected {}, found {}", expected, actual); } }, - TypeId.Pointer => |pointer| { + .Pointer => |pointer| { switch (pointer.size) { builtin.TypeInfo.Pointer.Size.One, builtin.TypeInfo.Pointer.Size.Many, @@ -75,22 +76,22 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { } }, - TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual), + .Array => |array| expectEqualSlices(array.child, &expected, &actual), - TypeId.Struct => |structType| { + .Struct => |structType| { inline for (structType.fields) |field| { expectEqual(@field(expected, field.name), @field(actual, field.name)); } }, - TypeId.Union => |union_info| { + .Union => |union_info| { if (union_info.tag_type == null) { @compileError("Unable to compare untagged union values"); } @compileError("TODO implement testing.expectEqual for tagged unions"); }, - TypeId.Optional => { + .Optional => { if (expected) |expected_payload| { if (actual) |actual_payload| { expectEqual(expected_payload, actual_payload); @@ -104,7 +105,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { } }, - TypeId.ErrorUnion => { + .ErrorUnion => { if (expected) |expected_payload| { if (actual) |actual_payload| { expectEqual(expected_payload, actual_payload); diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 795008834..59401fbe8 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -43,7 +43,7 @@ comptime { _ = @import("behavior/cast.zig"); _ = @import("behavior/const_slice_child.zig"); //_ = @import("behavior/coroutine_await_struct.zig"); - //_ = @import("behavior/coroutines.zig"); + _ = @import("behavior/coroutines.zig"); _ = @import("behavior/defer.zig"); _ = @import("behavior/enum.zig"); _ = @import("behavior/enum_with_members.zig"); diff --git a/test/stage1/behavior/coroutines.zig b/test/stage1/behavior/coroutines.zig index 7395f3e06..cdab411fb 100644 --- a/test/stage1/behavior/coroutines.zig +++ b/test/stage1/behavior/coroutines.zig @@ -1,236 +1,245 @@ const std = @import("std"); const builtin = @import("builtin"); const expect = std.testing.expect; -const allocator = std.heap.direct_allocator; var x: i32 = 1; -test "create a coroutine and cancel it" { - const p = try async simpleAsyncFn(); - comptime expect(@typeOf(p) == promise->void); - cancel p; +test "simple coroutine suspend" { + const p = async simpleAsyncFn(); expect(x == 2); } -async fn simpleAsyncFn() void { +fn simpleAsyncFn() void { x += 1; suspend; x += 1; } -test "coroutine suspend, resume, cancel" { - seq('a'); - const p = try async testAsyncSeq(); - seq('c'); - resume p; - seq('f'); - cancel p; - seq('g'); - - expect(std.mem.eql(u8, points, "abcdefg")); -} -async fn testAsyncSeq() void { - defer seq('e'); - - seq('b'); - suspend; - seq('d'); -} -var points = [_]u8{0} ** "abcdefg".len; -var index: usize = 0; - -fn seq(c: u8) void { - points[index] = c; - index += 1; -} - -test "coroutine suspend with block" { - const p = try async testSuspendBlock(); - std.testing.expect(!result); - resume a_promise; - std.testing.expect(result); - cancel p; -} - -var a_promise: promise = undefined; -var result = false; -async fn testSuspendBlock() void { - suspend { - comptime expect(@typeOf(@handle()) == promise->void); - a_promise = @handle(); - } - - //Test to make sure that @handle() works as advertised (issue #1296) - //var our_handle: promise = @handle(); - expect(a_promise == @handle()); - - result = true; -} - -var await_a_promise: promise = undefined; -var await_final_result: i32 = 0; - -test "coroutine await" { - await_seq('a'); - const p = async await_amain() catch unreachable; - await_seq('f'); - resume await_a_promise; - await_seq('i'); - expect(await_final_result == 1234); - expect(std.mem.eql(u8, await_points, "abcdefghi")); -} -async fn await_amain() void { - await_seq('b'); - const p = async await_another() catch unreachable; - await_seq('e'); - await_final_result = await p; - await_seq('h'); -} -async fn await_another() i32 { - await_seq('c'); - suspend { - await_seq('d'); - await_a_promise = @handle(); - } - 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" { - early_seq('a'); - const p = async early_amain() catch @panic("out of memory"); - early_seq('f'); - expect(early_final_result == 1234); - expect(std.mem.eql(u8, early_points, "abcdef")); -} -async fn early_amain() void { - early_seq('b'); - const p = async early_another() catch @panic("out of memory"); - early_seq('d'); - early_final_result = await p; - early_seq('e'); -} -async fn early_another() 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 "coro allocation failure" { - var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0); - if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) { - @panic("expected allocation failure"); - } else |err| switch (err) { - error.OutOfMemory => {}, - } -} -async fn asyncFuncThatNeverGetsRun() void { - @panic("coro frame allocation should fail"); -} - -test "async function with dot syntax" { - const S = struct { - var y: i32 = 1; - async fn foo() void { - y += 1; - suspend; - } - }; - const p = try async S.foo(); - cancel p; - expect(S.y == 2); -} - -test "async fn pointer in a struct field" { - var data: i32 = 1; - const Foo = struct { - bar: async<*std.mem.Allocator> fn (*i32) void, - }; - var foo = Foo{ .bar = simpleAsyncFn2 }; - const p = (async foo.bar(&data)) catch unreachable; - expect(data == 2); - cancel p; - expect(data == 4); -} -async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void { - defer y.* += 2; - y.* += 1; - suspend; -} - -test "async fn with inferred error set" { - const p = (async failing()) catch unreachable; - resume p; - cancel p; -} - -async fn failing() !void { - suspend; - return error.Fail; -} - -test "error return trace across suspend points - early return" { - const p = nonFailing(); - resume p; - const p2 = try async printTrace(p); - cancel p2; -} - -test "error return trace across suspend points - async return" { - const p = nonFailing(); - const p2 = try async printTrace(p); - resume p; - cancel p2; -} - -fn nonFailing() (promise->anyerror!void) { - return async suspendThenFail() catch unreachable; -} -async fn suspendThenFail() anyerror!void { - suspend; - return error.Fail; -} -async fn printTrace(p: promise->(anyerror!void)) void { - (await p) catch |e| { - std.testing.expect(e == error.Fail); - if (@errorReturnTrace()) |trace| { - expect(trace.index == 1); - } else switch (builtin.mode) { - builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"), - builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {}, - } - }; -} - -test "break from suspend" { - var buf: [500]u8 = undefined; - var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; - var my_result: i32 = 1; - const p = try async testBreakFromSuspend(&my_result); - cancel p; - std.testing.expect(my_result == 2); -} -async fn testBreakFromSuspend(my_result: *i32) void { - suspend { - resume @handle(); - } - my_result.* += 1; - suspend; - my_result.* += 1; -} +//test "create a coroutine and cancel it" { +// const p = try async simpleAsyncFn(); +// comptime expect(@typeOf(p) == promise->void); +// cancel p; +// expect(x == 2); +//} +//async fn simpleAsyncFn() void { +// x += 1; +// suspend; +// x += 1; +//} +// +//test "coroutine suspend, resume, cancel" { +// seq('a'); +// const p = try async testAsyncSeq(); +// seq('c'); +// resume p; +// seq('f'); +// cancel p; +// seq('g'); +// +// expect(std.mem.eql(u8, points, "abcdefg")); +//} +//async fn testAsyncSeq() void { +// defer seq('e'); +// +// seq('b'); +// suspend; +// seq('d'); +//} +//var points = [_]u8{0} ** "abcdefg".len; +//var index: usize = 0; +// +//fn seq(c: u8) void { +// points[index] = c; +// index += 1; +//} +// +//test "coroutine suspend with block" { +// const p = try async testSuspendBlock(); +// std.testing.expect(!result); +// resume a_promise; +// std.testing.expect(result); +// cancel p; +//} +// +//var a_promise: promise = undefined; +//var result = false; +//async fn testSuspendBlock() void { +// suspend { +// comptime expect(@typeOf(@handle()) == promise->void); +// a_promise = @handle(); +// } +// +// //Test to make sure that @handle() works as advertised (issue #1296) +// //var our_handle: promise = @handle(); +// expect(a_promise == @handle()); +// +// result = true; +//} +// +//var await_a_promise: promise = undefined; +//var await_final_result: i32 = 0; +// +//test "coroutine await" { +// await_seq('a'); +// const p = async await_amain() catch unreachable; +// await_seq('f'); +// resume await_a_promise; +// await_seq('i'); +// expect(await_final_result == 1234); +// expect(std.mem.eql(u8, await_points, "abcdefghi")); +//} +//async fn await_amain() void { +// await_seq('b'); +// const p = async await_another() catch unreachable; +// await_seq('e'); +// await_final_result = await p; +// await_seq('h'); +//} +//async fn await_another() i32 { +// await_seq('c'); +// suspend { +// await_seq('d'); +// await_a_promise = @handle(); +// } +// 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" { +// early_seq('a'); +// const p = async early_amain() catch @panic("out of memory"); +// early_seq('f'); +// expect(early_final_result == 1234); +// expect(std.mem.eql(u8, early_points, "abcdef")); +//} +//async fn early_amain() void { +// early_seq('b'); +// const p = async early_another() catch @panic("out of memory"); +// early_seq('d'); +// early_final_result = await p; +// early_seq('e'); +//} +//async fn early_another() 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 "coro allocation failure" { +// var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0); +// if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) { +// @panic("expected allocation failure"); +// } else |err| switch (err) { +// error.OutOfMemory => {}, +// } +//} +//async fn asyncFuncThatNeverGetsRun() void { +// @panic("coro frame allocation should fail"); +//} +// +//test "async function with dot syntax" { +// const S = struct { +// var y: i32 = 1; +// async fn foo() void { +// y += 1; +// suspend; +// } +// }; +// const p = try async S.foo(); +// cancel p; +// expect(S.y == 2); +//} +// +//test "async fn pointer in a struct field" { +// var data: i32 = 1; +// const Foo = struct { +// bar: async<*std.mem.Allocator> fn (*i32) void, +// }; +// var foo = Foo{ .bar = simpleAsyncFn2 }; +// const p = (async foo.bar(&data)) catch unreachable; +// expect(data == 2); +// cancel p; +// expect(data == 4); +//} +//async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void { +// defer y.* += 2; +// y.* += 1; +// suspend; +//} +// +//test "async fn with inferred error set" { +// const p = (async failing()) catch unreachable; +// resume p; +// cancel p; +//} +// +//async fn failing() !void { +// suspend; +// return error.Fail; +//} +// +//test "error return trace across suspend points - early return" { +// const p = nonFailing(); +// resume p; +// const p2 = try async printTrace(p); +// cancel p2; +//} +// +//test "error return trace across suspend points - async return" { +// const p = nonFailing(); +// const p2 = try async printTrace(p); +// resume p; +// cancel p2; +//} +// +//fn nonFailing() (promise->anyerror!void) { +// return async suspendThenFail() catch unreachable; +//} +//async fn suspendThenFail() anyerror!void { +// suspend; +// return error.Fail; +//} +//async fn printTrace(p: promise->(anyerror!void)) void { +// (await p) catch |e| { +// std.testing.expect(e == error.Fail); +// if (@errorReturnTrace()) |trace| { +// expect(trace.index == 1); +// } else switch (builtin.mode) { +// builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"), +// builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {}, +// } +// }; +//} +// +//test "break from suspend" { +// var buf: [500]u8 = undefined; +// var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; +// var my_result: i32 = 1; +// const p = try async testBreakFromSuspend(&my_result); +// cancel p; +// std.testing.expect(my_result == 2); +//} +//async fn testBreakFromSuspend(my_result: *i32) void { +// suspend { +// resume @handle(); +// } +// my_result.* += 1; +// suspend; +// my_result.* += 1; +//} diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 2decf0c32..6a5101512 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -177,7 +177,7 @@ fn testUnion() void { expect(TypeId(typeinfo_info) == TypeId.Union); expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); expect(typeinfo_info.Union.tag_type.? == TypeId); - expect(typeinfo_info.Union.fields.len == 24); + expect(typeinfo_info.Union.fields.len == 25); expect(typeinfo_info.Union.fields[4].enum_field != null); expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4); expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));