authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-21 19:56:37-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-21 19:56:37-04:00
log78e03c466c6641571adef4bb3931d6cc6f425eb4
tree7e59a9aae51c69eee5414a39a534b43a40f2e903
parent56c08eb3025a622e5d3f5b2b6c704f8dc2cddf47
signature Commit is signed but in an unrecognized format.

simple async function passing test


9 files changed, 355 insertions(+), 319 deletions(-)

src/all_types.hpp+10-1
......@@ -1346,7 +1346,16 @@ struct ZigFn {
13461346 Scope *child_scope; // parent is scope for last parameter
13471347 ScopeBlock *def_scope; // parent is child_scope
13481348 Buf symbol_name;
1349 ZigType *type_entry; // function type
1349 // This is the function type assuming the function does not suspend.
1350 // Note that for an async function, this can be shared with non-async functions. So the value here
1351 // should only be read for things in common between non-async and async function types.
1352 ZigType *type_entry;
1353 // For normal functions one could use the type_entry->raw_type_ref and type_entry->raw_di_type.
1354 // However for functions that suspend, those values could possibly be their non-suspending equivalents.
1355 // So these values should be preferred.
1356 LLVMTypeRef raw_type_ref;
1357 ZigLLVMDIType *raw_di_type;
1358
13501359 ZigType *frame_type; // coro frame type
13511360 // in the case of normal functions this is the implicit return type
13521361 // in the case of async functions this is the implicit return type according to the
src/analyze.cpp+15-2
......@@ -3750,7 +3750,7 @@ bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *sour
37503750 return true;
37513751}
37523752
3753void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node) {
3753static void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node) {
37543754 ZigType *fn_type = fn_table_entry->type_entry;
37553755 assert(!fn_type->data.fn.is_generic);
37563756 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
......@@ -5850,6 +5850,7 @@ static const ZigTypeId all_type_ids[] = {
58505850 ZigTypeIdBoundFn,
58515851 ZigTypeIdArgTuple,
58525852 ZigTypeIdOpaque,
5853 ZigTypeIdCoroFrame,
58535854 ZigTypeIdVector,
58545855 ZigTypeIdEnumLiteral,
58555856};
......@@ -7035,7 +7036,13 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {
70357036}
70367037
70377038void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {
7038 if (fn_type->llvm_di_type != nullptr) return;
7039 if (fn_type->llvm_di_type != nullptr) {
7040 if (fn != nullptr) {
7041 fn->raw_type_ref = fn_type->data.fn.raw_type_ref;
7042 fn->raw_di_type = fn_type->data.fn.raw_di_type;
7043 }
7044 return;
7045 }
70397046
70407047 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
70417048 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) {
71187125 for (size_t i = 0; i < gen_param_types.length; i += 1) {
71197126 assert(gen_param_types.items[i] != nullptr);
71207127 }
7128 if (fn != nullptr) {
7129 fn->raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
7130 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
7131 fn->raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
7132 return;
7133 }
71217134 fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
71227135 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
71237136 fn_type->llvm_type = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
src/analyze.hpp-1
......@@ -105,7 +105,6 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v
105105void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max);
106106
107107void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val);
108void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node);
109108
110109ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent);
111110ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent);
src/codegen.cpp+12-8
......@@ -499,7 +499,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
499499 ZigType *fn_type = fn_table_entry->type_entry;
500500 // Make the raw_type_ref populated
501501 resolve_llvm_types_fn(g, fn_type, fn_table_entry);
502 LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref;
502 LLVMTypeRef fn_llvm_type = fn_table_entry->raw_type_ref;
503503 if (fn_table_entry->body_node == nullptr) {
504504 LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));
505505 if (existing_llvm_fn) {
......@@ -521,9 +521,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
521521 assert(entry->value->id == TldIdFn);
522522 TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);
523523 // Make the raw_type_ref populated
524 (void)get_llvm_type(g, tld_fn->fn_entry->type_entry);
524 resolve_llvm_types_fn(g, tld_fn->fn_entry->type_entry, tld_fn->fn_entry);
525525 tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),
526 tld_fn->fn_entry->type_entry->data.fn.raw_type_ref);
526 tld_fn->fn_entry->raw_type_ref);
527527 fn_table_entry->llvm_value = LLVMConstBitCast(tld_fn->fn_entry->llvm_value,
528528 LLVMPointerType(fn_llvm_type, 0));
529529 return fn_table_entry->llvm_value;
......@@ -683,10 +683,11 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
683683 unsigned flags = ZigLLVM_DIFlags_StaticMember;
684684 ZigLLVMDIScope *fn_di_scope = get_di_scope(g, scope->parent);
685685 assert(fn_di_scope != nullptr);
686 assert(fn_table_entry->raw_di_type != nullptr);
686687 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
687688 fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
688689 import->data.structure.root_struct->di_file, line_number,
689 fn_table_entry->type_entry->data.fn.raw_di_type, is_internal_linkage,
690 fn_table_entry->raw_di_type, is_internal_linkage,
690691 is_definition, scope_line, flags, is_optimized, nullptr);
691692
692693 scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
......@@ -3472,10 +3473,13 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
34723473 }
34733474
34743475 gen_param_values.append(result_loc);
3475 } else if (first_arg_ret) {
3476 gen_param_values.append(result_loc);
3477 } else if (prefix_arg_err_ret_stack) {
3478 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
3476 } else {
3477 if (first_arg_ret) {
3478 gen_param_values.append(result_loc);
3479 }
3480 if (prefix_arg_err_ret_stack) {
3481 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
3482 }
34793483 }
34803484 FnWalk fn_walk = {};
34813485 fn_walk.id = FnWalkIdCall;
std/hash_map.zig+59-58
......@@ -535,17 +535,18 @@ pub fn getAutoEqlFn(comptime K: type) (fn (K, K) bool) {
535535// TODO improve these hash functions
536536pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type) HashInt {
537537 switch (@typeInfo(@typeOf(key))) {
538 builtin.TypeId.NoReturn,
539 builtin.TypeId.Opaque,
540 builtin.TypeId.Undefined,
541 builtin.TypeId.ArgTuple,
538 .NoReturn,
539 .Opaque,
540 .Undefined,
541 .ArgTuple,
542 .Frame,
542543 => @compileError("cannot hash this type"),
543544
544 builtin.TypeId.Void,
545 builtin.TypeId.Null,
545 .Void,
546 .Null,
546547 => return 0,
547548
548 builtin.TypeId.Int => |info| {
549 .Int => |info| {
549550 const unsigned_x = @bitCast(@IntType(false, info.bits), key);
550551 if (info.bits <= HashInt.bit_count) {
551552 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
554555 }
555556 },
556557
557 builtin.TypeId.Float => |info| {
558 .Float => |info| {
558559 return autoHash(@bitCast(@IntType(false, info.bits), key), rng, HashInt);
559560 },
560 builtin.TypeId.Bool => return autoHash(@boolToInt(key), rng, HashInt),
561 builtin.TypeId.Enum => return autoHash(@enumToInt(key), rng, HashInt),
562 builtin.TypeId.ErrorSet => return autoHash(@errorToInt(key), rng, HashInt),
563 builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng, HashInt),
564
565 builtin.TypeId.BoundFn,
566 builtin.TypeId.ComptimeFloat,
567 builtin.TypeId.ComptimeInt,
568 builtin.TypeId.Type,
569 builtin.TypeId.EnumLiteral,
561 .Bool => return autoHash(@boolToInt(key), rng, HashInt),
562 .Enum => return autoHash(@enumToInt(key), rng, HashInt),
563 .ErrorSet => return autoHash(@errorToInt(key), rng, HashInt),
564 .Fn => return autoHash(@ptrToInt(key), rng, HashInt),
565
566 .BoundFn,
567 .ComptimeFloat,
568 .ComptimeInt,
569 .Type,
570 .EnumLiteral,
570571 => return 0,
571572
572 builtin.TypeId.Pointer => |info| switch (info.size) {
573 builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto hash for single item pointers"),
574 builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto hash for many item pointers"),
575 builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto hash C pointers"),
576 builtin.TypeInfo.Pointer.Size.Slice => {
573 .Pointer => |info| switch (info.size) {
574 .One => @compileError("TODO auto hash for single item pointers"),
575 .Many => @compileError("TODO auto hash for many item pointers"),
576 .C => @compileError("TODO auto hash C pointers"),
577 .Slice => {
577578 const interval = std.math.max(1, key.len / 256);
578579 var i: usize = 0;
579580 var h = comptime rng.scalar(HashInt);
......@@ -584,44 +585,44 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
584585 },
585586 },
586587
587 builtin.TypeId.Optional => @compileError("TODO auto hash for optionals"),
588 builtin.TypeId.Array => @compileError("TODO auto hash for arrays"),
589 builtin.TypeId.Vector => @compileError("TODO auto hash for vectors"),
590 builtin.TypeId.Struct => @compileError("TODO auto hash for structs"),
591 builtin.TypeId.Union => @compileError("TODO auto hash for unions"),
592 builtin.TypeId.ErrorUnion => @compileError("TODO auto hash for unions"),
588 .Optional => @compileError("TODO auto hash for optionals"),
589 .Array => @compileError("TODO auto hash for arrays"),
590 .Vector => @compileError("TODO auto hash for vectors"),
591 .Struct => @compileError("TODO auto hash for structs"),
592 .Union => @compileError("TODO auto hash for unions"),
593 .ErrorUnion => @compileError("TODO auto hash for unions"),
593594 }
594595}
595596
596597pub fn autoEql(a: var, b: @typeOf(a)) bool {
597598 switch (@typeInfo(@typeOf(a))) {
598 builtin.TypeId.NoReturn,
599 builtin.TypeId.Opaque,
600 builtin.TypeId.Undefined,
601 builtin.TypeId.ArgTuple,
599 .NoReturn,
600 .Opaque,
601 .Undefined,
602 .ArgTuple,
602603 => @compileError("cannot test equality of this type"),
603 builtin.TypeId.Void,
604 builtin.TypeId.Null,
604 .Void,
605 .Null,
605606 => return true,
606 builtin.TypeId.Bool,
607 builtin.TypeId.Int,
608 builtin.TypeId.Float,
609 builtin.TypeId.ComptimeFloat,
610 builtin.TypeId.ComptimeInt,
611 builtin.TypeId.EnumLiteral,
612 builtin.TypeId.Promise,
613 builtin.TypeId.Enum,
614 builtin.TypeId.BoundFn,
615 builtin.TypeId.Fn,
616 builtin.TypeId.ErrorSet,
617 builtin.TypeId.Type,
607 .Bool,
608 .Int,
609 .Float,
610 .ComptimeFloat,
611 .ComptimeInt,
612 .EnumLiteral,
613 .Promise,
614 .Enum,
615 .BoundFn,
616 .Fn,
617 .ErrorSet,
618 .Type,
618619 => return a == b,
619620
620 builtin.TypeId.Pointer => |info| switch (info.size) {
621 builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto eql for single item pointers"),
622 builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto eql for many item pointers"),
623 builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto eql for C pointers"),
624 builtin.TypeInfo.Pointer.Size.Slice => {
621 .Pointer => |info| switch (info.size) {
622 .One => @compileError("TODO auto eql for single item pointers"),
623 .Many => @compileError("TODO auto eql for many item pointers"),
624 .C => @compileError("TODO auto eql for C pointers"),
625 .Slice => {
625626 if (a.len != b.len) return false;
626627 for (a) |a_item, i| {
627628 if (!autoEql(a_item, b[i])) return false;
......@@ -630,11 +631,11 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
630631 },
631632 },
632633
633 builtin.TypeId.Optional => @compileError("TODO auto eql for optionals"),
634 builtin.TypeId.Array => @compileError("TODO auto eql for arrays"),
635 builtin.TypeId.Struct => @compileError("TODO auto eql for structs"),
636 builtin.TypeId.Union => @compileError("TODO auto eql for unions"),
637 builtin.TypeId.ErrorUnion => @compileError("TODO auto eql for unions"),
638 builtin.TypeId.Vector => @compileError("TODO auto eql for vectors"),
634 .Optional => @compileError("TODO auto eql for optionals"),
635 .Array => @compileError("TODO auto eql for arrays"),
636 .Struct => @compileError("TODO auto eql for structs"),
637 .Union => @compileError("TODO auto eql for unions"),
638 .ErrorUnion => @compileError("TODO auto eql for unions"),
639 .Vector => @compileError("TODO auto eql for vectors"),
639640 }
640641}
std/testing.zig+25-24
......@@ -25,35 +25,36 @@ pub fn expectError(expected_error: anyerror, actual_error_union: var) void {
2525/// The types must match exactly.
2626pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
2727 switch (@typeInfo(@typeOf(actual))) {
28 TypeId.NoReturn,
29 TypeId.BoundFn,
30 TypeId.ArgTuple,
31 TypeId.Opaque,
28 .NoReturn,
29 .BoundFn,
30 .ArgTuple,
31 .Opaque,
32 .Frame,
3233 => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"),
3334
34 TypeId.Undefined,
35 TypeId.Null,
36 TypeId.Void,
35 .Undefined,
36 .Null,
37 .Void,
3738 => return,
3839
39 TypeId.Type,
40 TypeId.Bool,
41 TypeId.Int,
42 TypeId.Float,
43 TypeId.ComptimeFloat,
44 TypeId.ComptimeInt,
45 TypeId.EnumLiteral,
46 TypeId.Enum,
47 TypeId.Fn,
48 TypeId.Vector,
49 TypeId.ErrorSet,
40 .Type,
41 .Bool,
42 .Int,
43 .Float,
44 .ComptimeFloat,
45 .ComptimeInt,
46 .EnumLiteral,
47 .Enum,
48 .Fn,
49 .Vector,
50 .ErrorSet,
5051 => {
5152 if (actual != expected) {
5253 std.debug.panic("expected {}, found {}", expected, actual);
5354 }
5455 },
5556
56 TypeId.Pointer => |pointer| {
57 .Pointer => |pointer| {
5758 switch (pointer.size) {
5859 builtin.TypeInfo.Pointer.Size.One,
5960 builtin.TypeInfo.Pointer.Size.Many,
......@@ -75,22 +76,22 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
7576 }
7677 },
7778
78 TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual),
79 .Array => |array| expectEqualSlices(array.child, &expected, &actual),
7980
80 TypeId.Struct => |structType| {
81 .Struct => |structType| {
8182 inline for (structType.fields) |field| {
8283 expectEqual(@field(expected, field.name), @field(actual, field.name));
8384 }
8485 },
8586
86 TypeId.Union => |union_info| {
87 .Union => |union_info| {
8788 if (union_info.tag_type == null) {
8889 @compileError("Unable to compare untagged union values");
8990 }
9091 @compileError("TODO implement testing.expectEqual for tagged unions");
9192 },
9293
93 TypeId.Optional => {
94 .Optional => {
9495 if (expected) |expected_payload| {
9596 if (actual) |actual_payload| {
9697 expectEqual(expected_payload, actual_payload);
......@@ -104,7 +105,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
104105 }
105106 },
106107
107 TypeId.ErrorUnion => {
108 .ErrorUnion => {
108109 if (expected) |expected_payload| {
109110 if (actual) |actual_payload| {
110111 expectEqual(expected_payload, actual_payload);
test/stage1/behavior.zig+1-1
......@@ -43,7 +43,7 @@ comptime {
4343 _ = @import("behavior/cast.zig");
4444 _ = @import("behavior/const_slice_child.zig");
4545 //_ = @import("behavior/coroutine_await_struct.zig");
46 //_ = @import("behavior/coroutines.zig");
46 _ = @import("behavior/coroutines.zig");
4747 _ = @import("behavior/defer.zig");
4848 _ = @import("behavior/enum.zig");
4949 _ = @import("behavior/enum_with_members.zig");
test/stage1/behavior/coroutines.zig+232-223
......@@ -1,236 +1,245 @@
11const std = @import("std");
22const builtin = @import("builtin");
33const expect = std.testing.expect;
4const allocator = std.heap.direct_allocator;
54
65var x: i32 = 1;
76
8test "create a coroutine and cancel it" {
9 const p = try async<allocator> simpleAsyncFn();
10 comptime expect(@typeOf(p) == promise->void);
11 cancel p;
7test "simple coroutine suspend" {
8 const p = async simpleAsyncFn();
129 expect(x == 2);
1310}
14async fn simpleAsyncFn() void {
11fn simpleAsyncFn() void {
1512 x += 1;
1613 suspend;
1714 x += 1;
1815}
1916
20test "coroutine suspend, resume, cancel" {
21 seq('a');
22 const p = try async<allocator> testAsyncSeq();
23 seq('c');
24 resume p;
25 seq('f');
26 cancel p;
27 seq('g');
28
29 expect(std.mem.eql(u8, points, "abcdefg"));
30}
31async fn testAsyncSeq() void {
32 defer seq('e');
33
34 seq('b');
35 suspend;
36 seq('d');
37}
38var points = [_]u8{0} ** "abcdefg".len;
39var index: usize = 0;
40
41fn seq(c: u8) void {
42 points[index] = c;
43 index += 1;
44}
45
46test "coroutine suspend with block" {
47 const p = try async<allocator> testSuspendBlock();
48 std.testing.expect(!result);
49 resume a_promise;
50 std.testing.expect(result);
51 cancel p;
52}
53
54var a_promise: promise = undefined;
55var result = false;
56async fn testSuspendBlock() void {
57 suspend {
58 comptime expect(@typeOf(@handle()) == promise->void);
59 a_promise = @handle();
60 }
61
62 //Test to make sure that @handle() works as advertised (issue #1296)
63 //var our_handle: promise = @handle();
64 expect(a_promise == @handle());
65
66 result = true;
67}
68
69var await_a_promise: promise = undefined;
70var await_final_result: i32 = 0;
71
72test "coroutine await" {
73 await_seq('a');
74 const p = async<allocator> await_amain() catch unreachable;
75 await_seq('f');
76 resume await_a_promise;
77 await_seq('i');
78 expect(await_final_result == 1234);
79 expect(std.mem.eql(u8, await_points, "abcdefghi"));
80}
81async fn await_amain() void {
82 await_seq('b');
83 const p = async await_another() catch unreachable;
84 await_seq('e');
85 await_final_result = await p;
86 await_seq('h');
87}
88async fn await_another() i32 {
89 await_seq('c');
90 suspend {
91 await_seq('d');
92 await_a_promise = @handle();
93 }
94 await_seq('g');
95 return 1234;
96}
97
98var await_points = [_]u8{0} ** "abcdefghi".len;
99var await_seq_index: usize = 0;
100
101fn await_seq(c: u8) void {
102 await_points[await_seq_index] = c;
103 await_seq_index += 1;
104}
105
106var early_final_result: i32 = 0;
107
108test "coroutine await early return" {
109 early_seq('a');
110 const p = async<allocator> early_amain() catch @panic("out of memory");
111 early_seq('f');
112 expect(early_final_result == 1234);
113 expect(std.mem.eql(u8, early_points, "abcdef"));
114}
115async fn early_amain() void {
116 early_seq('b');
117 const p = async early_another() catch @panic("out of memory");
118 early_seq('d');
119 early_final_result = await p;
120 early_seq('e');
121}
122async fn early_another() i32 {
123 early_seq('c');
124 return 1234;
125}
126
127var early_points = [_]u8{0} ** "abcdef".len;
128var early_seq_index: usize = 0;
129
130fn early_seq(c: u8) void {
131 early_points[early_seq_index] = c;
132 early_seq_index += 1;
133}
134
135test "coro allocation failure" {
136 var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0);
137 if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) {
138 @panic("expected allocation failure");
139 } else |err| switch (err) {
140 error.OutOfMemory => {},
141 }
142}
143async fn asyncFuncThatNeverGetsRun() void {
144 @panic("coro frame allocation should fail");
145}
146
147test "async function with dot syntax" {
148 const S = struct {
149 var y: i32 = 1;
150 async fn foo() void {
151 y += 1;
152 suspend;
153 }
154 };
155 const p = try async<allocator> S.foo();
156 cancel p;
157 expect(S.y == 2);
158}
159
160test "async fn pointer in a struct field" {
161 var data: i32 = 1;
162 const Foo = struct {
163 bar: async<*std.mem.Allocator> fn (*i32) void,
164 };
165 var foo = Foo{ .bar = simpleAsyncFn2 };
166 const p = (async<allocator> foo.bar(&data)) catch unreachable;
167 expect(data == 2);
168 cancel p;
169 expect(data == 4);
170}
171async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {
172 defer y.* += 2;
173 y.* += 1;
174 suspend;
175}
176
177test "async fn with inferred error set" {
178 const p = (async<allocator> failing()) catch unreachable;
179 resume p;
180 cancel p;
181}
182
183async fn failing() !void {
184 suspend;
185 return error.Fail;
186}
187
188test "error return trace across suspend points - early return" {
189 const p = nonFailing();
190 resume p;
191 const p2 = try async<allocator> printTrace(p);
192 cancel p2;
193}
194
195test "error return trace across suspend points - async return" {
196 const p = nonFailing();
197 const p2 = try async<std.debug.global_allocator> printTrace(p);
198 resume p;
199 cancel p2;
200}
201
202fn nonFailing() (promise->anyerror!void) {
203 return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
204}
205async fn suspendThenFail() anyerror!void {
206 suspend;
207 return error.Fail;
208}
209async fn printTrace(p: promise->(anyerror!void)) void {
210 (await p) catch |e| {
211 std.testing.expect(e == error.Fail);
212 if (@errorReturnTrace()) |trace| {
213 expect(trace.index == 1);
214 } else switch (builtin.mode) {
215 builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"),
216 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {},
217 }
218 };
219}
220
221test "break from suspend" {
222 var buf: [500]u8 = undefined;
223 var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
224 var my_result: i32 = 1;
225 const p = try async<a> testBreakFromSuspend(&my_result);
226 cancel p;
227 std.testing.expect(my_result == 2);
228}
229async fn testBreakFromSuspend(my_result: *i32) void {
230 suspend {
231 resume @handle();
232 }
233 my_result.* += 1;
234 suspend;
235 my_result.* += 1;
236}
17//test "create a coroutine and cancel it" {
18// const p = try async<allocator> simpleAsyncFn();
19// comptime expect(@typeOf(p) == promise->void);
20// cancel p;
21// expect(x == 2);
22//}
23//async fn simpleAsyncFn() void {
24// x += 1;
25// suspend;
26// x += 1;
27//}
28//
29//test "coroutine suspend, resume, cancel" {
30// seq('a');
31// const p = try async<allocator> testAsyncSeq();
32// seq('c');
33// resume p;
34// seq('f');
35// cancel p;
36// seq('g');
37//
38// expect(std.mem.eql(u8, points, "abcdefg"));
39//}
40//async fn testAsyncSeq() void {
41// defer seq('e');
42//
43// seq('b');
44// suspend;
45// seq('d');
46//}
47//var points = [_]u8{0} ** "abcdefg".len;
48//var index: usize = 0;
49//
50//fn seq(c: u8) void {
51// points[index] = c;
52// index += 1;
53//}
54//
55//test "coroutine suspend with block" {
56// const p = try async<allocator> testSuspendBlock();
57// std.testing.expect(!result);
58// resume a_promise;
59// std.testing.expect(result);
60// cancel p;
61//}
62//
63//var a_promise: promise = undefined;
64//var result = false;
65//async fn testSuspendBlock() void {
66// suspend {
67// comptime expect(@typeOf(@handle()) == promise->void);
68// a_promise = @handle();
69// }
70//
71// //Test to make sure that @handle() works as advertised (issue #1296)
72// //var our_handle: promise = @handle();
73// expect(a_promise == @handle());
74//
75// result = true;
76//}
77//
78//var await_a_promise: promise = undefined;
79//var await_final_result: i32 = 0;
80//
81//test "coroutine await" {
82// await_seq('a');
83// const p = async<allocator> await_amain() catch unreachable;
84// await_seq('f');
85// resume await_a_promise;
86// await_seq('i');
87// expect(await_final_result == 1234);
88// expect(std.mem.eql(u8, await_points, "abcdefghi"));
89//}
90//async fn await_amain() void {
91// await_seq('b');
92// const p = async await_another() catch unreachable;
93// await_seq('e');
94// await_final_result = await p;
95// await_seq('h');
96//}
97//async fn await_another() i32 {
98// await_seq('c');
99// suspend {
100// await_seq('d');
101// await_a_promise = @handle();
102// }
103// await_seq('g');
104// return 1234;
105//}
106//
107//var await_points = [_]u8{0} ** "abcdefghi".len;
108//var await_seq_index: usize = 0;
109//
110//fn await_seq(c: u8) void {
111// await_points[await_seq_index] = c;
112// await_seq_index += 1;
113//}
114//
115//var early_final_result: i32 = 0;
116//
117//test "coroutine await early return" {
118// early_seq('a');
119// const p = async<allocator> early_amain() catch @panic("out of memory");
120// early_seq('f');
121// expect(early_final_result == 1234);
122// expect(std.mem.eql(u8, early_points, "abcdef"));
123//}
124//async fn early_amain() void {
125// early_seq('b');
126// const p = async early_another() catch @panic("out of memory");
127// early_seq('d');
128// early_final_result = await p;
129// early_seq('e');
130//}
131//async fn early_another() i32 {
132// early_seq('c');
133// return 1234;
134//}
135//
136//var early_points = [_]u8{0} ** "abcdef".len;
137//var early_seq_index: usize = 0;
138//
139//fn early_seq(c: u8) void {
140// early_points[early_seq_index] = c;
141// early_seq_index += 1;
142//}
143//
144//test "coro allocation failure" {
145// var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0);
146// if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) {
147// @panic("expected allocation failure");
148// } else |err| switch (err) {
149// error.OutOfMemory => {},
150// }
151//}
152//async fn asyncFuncThatNeverGetsRun() void {
153// @panic("coro frame allocation should fail");
154//}
155//
156//test "async function with dot syntax" {
157// const S = struct {
158// var y: i32 = 1;
159// async fn foo() void {
160// y += 1;
161// suspend;
162// }
163// };
164// const p = try async<allocator> S.foo();
165// cancel p;
166// expect(S.y == 2);
167//}
168//
169//test "async fn pointer in a struct field" {
170// var data: i32 = 1;
171// const Foo = struct {
172// bar: async<*std.mem.Allocator> fn (*i32) void,
173// };
174// var foo = Foo{ .bar = simpleAsyncFn2 };
175// const p = (async<allocator> foo.bar(&data)) catch unreachable;
176// expect(data == 2);
177// cancel p;
178// expect(data == 4);
179//}
180//async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {
181// defer y.* += 2;
182// y.* += 1;
183// suspend;
184//}
185//
186//test "async fn with inferred error set" {
187// const p = (async<allocator> failing()) catch unreachable;
188// resume p;
189// cancel p;
190//}
191//
192//async fn failing() !void {
193// suspend;
194// return error.Fail;
195//}
196//
197//test "error return trace across suspend points - early return" {
198// const p = nonFailing();
199// resume p;
200// const p2 = try async<allocator> printTrace(p);
201// cancel p2;
202//}
203//
204//test "error return trace across suspend points - async return" {
205// const p = nonFailing();
206// const p2 = try async<std.debug.global_allocator> printTrace(p);
207// resume p;
208// cancel p2;
209//}
210//
211//fn nonFailing() (promise->anyerror!void) {
212// return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
213//}
214//async fn suspendThenFail() anyerror!void {
215// suspend;
216// return error.Fail;
217//}
218//async fn printTrace(p: promise->(anyerror!void)) void {
219// (await p) catch |e| {
220// std.testing.expect(e == error.Fail);
221// if (@errorReturnTrace()) |trace| {
222// expect(trace.index == 1);
223// } else switch (builtin.mode) {
224// builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"),
225// builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {},
226// }
227// };
228//}
229//
230//test "break from suspend" {
231// var buf: [500]u8 = undefined;
232// var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
233// var my_result: i32 = 1;
234// const p = try async<a> testBreakFromSuspend(&my_result);
235// cancel p;
236// std.testing.expect(my_result == 2);
237//}
238//async fn testBreakFromSuspend(my_result: *i32) void {
239// suspend {
240// resume @handle();
241// }
242// my_result.* += 1;
243// suspend;
244// my_result.* += 1;
245//}
test/stage1/behavior/type_info.zig+1-1
......@@ -177,7 +177,7 @@ fn testUnion() void {
177177 expect(TypeId(typeinfo_info) == TypeId.Union);
178178 expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
179179 expect(typeinfo_info.Union.tag_type.? == TypeId);
180 expect(typeinfo_info.Union.fields.len == 24);
180 expect(typeinfo_info.Union.fields.len == 25);
181181 expect(typeinfo_info.Union.fields[4].enum_field != null);
182182 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
183183 expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));