simple async function passing test
This commit is contained in:
parent
56c08eb302
commit
78e03c466c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
115
std/hash_map.zig
115
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"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
//}
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue
Block a user