simple async function passing test

This commit is contained in:
Andrew Kelley 2019-07-21 19:56:37 -04:00
parent 56c08eb302
commit 78e03c466c
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
9 changed files with 354 additions and 318 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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<TldFn *>(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;

View File

@ -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"),
}
}

View File

@ -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);

View File

@ -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");

View File

@ -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<allocator> 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<allocator> 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<allocator> 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<allocator> 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<allocator> 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<allocator> 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<allocator> 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<allocator> 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<allocator> printTrace(p);
cancel p2;
}
test "error return trace across suspend points - async return" {
const p = nonFailing();
const p2 = try async<std.debug.global_allocator> printTrace(p);
resume p;
cancel p2;
}
fn nonFailing() (promise->anyerror!void) {
return async<std.debug.global_allocator> 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<a> 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<allocator> 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<allocator> 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<allocator> 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<allocator> 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<allocator> 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<allocator> 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<allocator> 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<allocator> 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<allocator> printTrace(p);
// cancel p2;
//}
//
//test "error return trace across suspend points - async return" {
// const p = nonFailing();
// const p2 = try async<std.debug.global_allocator> printTrace(p);
// resume p;
// cancel p2;
//}
//
//fn nonFailing() (promise->anyerror!void) {
// return async<std.debug.global_allocator> 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<a> 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;
//}

View File

@ -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));