authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-14 00:38:27-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-14 00:38:27-04:00
log7799423f24a0f628641e772146f1e6a5c2f6bdcb
tree77f5b4c92b5ce9fc88cb3ca6e9d5fba4838e17fc
parent5749dc49d839ba607392ed0934008773d33f47d7
signaturelock-open Commit is signed but in an unrecognized format.

rename behavior test files


5 files changed, 829 insertions(+), 829 deletions(-)

test/stage1/behavior.zig+6-6
...@@ -3,12 +3,13 @@ comptime {...@@ -3,12 +3,13 @@ comptime {
3 _ = @import("behavior/alignof.zig");3 _ = @import("behavior/alignof.zig");
4 _ = @import("behavior/array.zig");4 _ = @import("behavior/array.zig");
5 _ = @import("behavior/asm.zig");5 _ = @import("behavior/asm.zig");
6 _ = @import("behavior/async_fn.zig");
6 _ = @import("behavior/atomics.zig");7 _ = @import("behavior/atomics.zig");
8 _ = @import("behavior/await_struct.zig");
7 _ = @import("behavior/bit_shifting.zig");9 _ = @import("behavior/bit_shifting.zig");
8 _ = @import("behavior/bitcast.zig");10 _ = @import("behavior/bitcast.zig");
9 _ = @import("behavior/bitreverse.zig");11 _ = @import("behavior/bitreverse.zig");
10 _ = @import("behavior/bool.zig");12 _ = @import("behavior/bool.zig");
11 _ = @import("behavior/byteswap.zig");
12 _ = @import("behavior/bugs/1025.zig");13 _ = @import("behavior/bugs/1025.zig");
13 _ = @import("behavior/bugs/1076.zig");14 _ = @import("behavior/bugs/1076.zig");
14 _ = @import("behavior/bugs/1111.zig");15 _ = @import("behavior/bugs/1111.zig");
...@@ -38,23 +39,24 @@ comptime {...@@ -38,23 +39,24 @@ comptime {
38 _ = @import("behavior/bugs/726.zig");39 _ = @import("behavior/bugs/726.zig");
39 _ = @import("behavior/bugs/828.zig");40 _ = @import("behavior/bugs/828.zig");
40 _ = @import("behavior/bugs/920.zig");41 _ = @import("behavior/bugs/920.zig");
42 _ = @import("behavior/byteswap.zig");
41 _ = @import("behavior/byval_arg_var.zig");43 _ = @import("behavior/byval_arg_var.zig");
42 _ = @import("behavior/cancel.zig");44 _ = @import("behavior/cancel.zig");
43 _ = @import("behavior/cast.zig");45 _ = @import("behavior/cast.zig");
44 _ = @import("behavior/const_slice_child.zig");46 _ = @import("behavior/const_slice_child.zig");
45 _ = @import("behavior/coroutine_await_struct.zig");
46 _ = @import("behavior/coroutines.zig");
47 _ = @import("behavior/defer.zig");47 _ = @import("behavior/defer.zig");
48 _ = @import("behavior/enum.zig");48 _ = @import("behavior/enum.zig");
49 _ = @import("behavior/enum_with_members.zig");49 _ = @import("behavior/enum_with_members.zig");
50 _ = @import("behavior/error.zig");50 _ = @import("behavior/error.zig");
51 _ = @import("behavior/eval.zig");51 _ = @import("behavior/eval.zig");
52 _ = @import("behavior/field_parent_ptr.zig");52 _ = @import("behavior/field_parent_ptr.zig");
53 _ = @import("behavior/floatop.zig");
53 _ = @import("behavior/fn.zig");54 _ = @import("behavior/fn.zig");
54 _ = @import("behavior/fn_in_struct_in_comptime.zig");55 _ = @import("behavior/fn_in_struct_in_comptime.zig");
55 _ = @import("behavior/for.zig");56 _ = @import("behavior/for.zig");
56 _ = @import("behavior/generics.zig");57 _ = @import("behavior/generics.zig");
57 _ = @import("behavior/hasdecl.zig");58 _ = @import("behavior/hasdecl.zig");
59 _ = @import("behavior/hasfield.zig");
58 _ = @import("behavior/if.zig");60 _ = @import("behavior/if.zig");
59 _ = @import("behavior/import.zig");61 _ = @import("behavior/import.zig");
60 _ = @import("behavior/incomplete_struct_param_tld.zig");62 _ = @import("behavior/incomplete_struct_param_tld.zig");
...@@ -63,14 +65,13 @@ comptime {...@@ -63,14 +65,13 @@ comptime {
63 _ = @import("behavior/math.zig");65 _ = @import("behavior/math.zig");
64 _ = @import("behavior/merge_error_sets.zig");66 _ = @import("behavior/merge_error_sets.zig");
65 _ = @import("behavior/misc.zig");67 _ = @import("behavior/misc.zig");
68 _ = @import("behavior/muladd.zig");
66 _ = @import("behavior/namespace_depends_on_compile_var.zig");69 _ = @import("behavior/namespace_depends_on_compile_var.zig");
67 _ = @import("behavior/new_stack_call.zig");70 _ = @import("behavior/new_stack_call.zig");
68 _ = @import("behavior/null.zig");71 _ = @import("behavior/null.zig");
69 _ = @import("behavior/optional.zig");72 _ = @import("behavior/optional.zig");
70 _ = @import("behavior/pointers.zig");73 _ = @import("behavior/pointers.zig");
71 _ = @import("behavior/popcount.zig");74 _ = @import("behavior/popcount.zig");
72 _ = @import("behavior/muladd.zig");
73 _ = @import("behavior/floatop.zig");
74 _ = @import("behavior/ptrcast.zig");75 _ = @import("behavior/ptrcast.zig");
75 _ = @import("behavior/pub_enum.zig");76 _ = @import("behavior/pub_enum.zig");
76 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");77 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
...@@ -99,5 +100,4 @@ comptime {...@@ -99,5 +100,4 @@ comptime {
99 _ = @import("behavior/void.zig");100 _ = @import("behavior/void.zig");
100 _ = @import("behavior/while.zig");101 _ = @import("behavior/while.zig");
101 _ = @import("behavior/widening.zig");102 _ = @import("behavior/widening.zig");
102 _ = @import("behavior/hasfield.zig");
103}103}
test/stage1/behavior/async_fn.zig created+779
...@@ -0,0 +1,779 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
5
6var global_x: i32 = 1;
7
8test "simple coroutine suspend and resume" {
9 const frame = async simpleAsyncFn();
10 expect(global_x == 2);
11 resume frame;
12 expect(global_x == 3);
13 const af: anyframe->void = &frame;
14 resume frame;
15 expect(global_x == 4);
16}
17fn simpleAsyncFn() void {
18 global_x += 1;
19 suspend;
20 global_x += 1;
21 suspend;
22 global_x += 1;
23}
24
25var global_y: i32 = 1;
26
27test "pass parameter to coroutine" {
28 const p = async simpleAsyncFnWithArg(2);
29 expect(global_y == 3);
30 resume p;
31 expect(global_y == 5);
32}
33fn simpleAsyncFnWithArg(delta: i32) void {
34 global_y += delta;
35 suspend;
36 global_y += delta;
37}
38
39test "suspend at end of function" {
40 const S = struct {
41 var x: i32 = 1;
42
43 fn doTheTest() void {
44 expect(x == 1);
45 const p = async suspendAtEnd();
46 expect(x == 2);
47 }
48
49 fn suspendAtEnd() void {
50 x += 1;
51 suspend;
52 }
53 };
54 S.doTheTest();
55}
56
57test "local variable in async function" {
58 const S = struct {
59 var x: i32 = 0;
60
61 fn doTheTest() void {
62 expect(x == 0);
63 const p = async add(1, 2);
64 expect(x == 0);
65 resume p;
66 expect(x == 0);
67 resume p;
68 expect(x == 0);
69 resume p;
70 expect(x == 3);
71 }
72
73 fn add(a: i32, b: i32) void {
74 var accum: i32 = 0;
75 suspend;
76 accum += a;
77 suspend;
78 accum += b;
79 suspend;
80 x = accum;
81 }
82 };
83 S.doTheTest();
84}
85
86test "calling an inferred async function" {
87 const S = struct {
88 var x: i32 = 1;
89 var other_frame: *@Frame(other) = undefined;
90
91 fn doTheTest() void {
92 _ = async first();
93 expect(x == 1);
94 resume other_frame.*;
95 expect(x == 2);
96 }
97
98 fn first() void {
99 other();
100 }
101 fn other() void {
102 other_frame = @frame();
103 suspend;
104 x += 1;
105 }
106 };
107 S.doTheTest();
108}
109
110test "@frameSize" {
111 const S = struct {
112 fn doTheTest() void {
113 {
114 var ptr = @ptrCast(async fn(i32) void, other);
115 const size = @frameSize(ptr);
116 expect(size == @sizeOf(@Frame(other)));
117 }
118 {
119 var ptr = @ptrCast(async fn() void, first);
120 const size = @frameSize(ptr);
121 expect(size == @sizeOf(@Frame(first)));
122 }
123 }
124
125 fn first() void {
126 other(1);
127 }
128 fn other(param: i32) void {
129 var local: i32 = undefined;
130 suspend;
131 }
132 };
133 S.doTheTest();
134}
135
136test "coroutine suspend, resume" {
137 const S = struct {
138 var frame: anyframe = undefined;
139
140 fn doTheTest() void {
141 _ = async amain();
142 seq('d');
143 resume frame;
144 seq('h');
145
146 expect(std.mem.eql(u8, points, "abcdefgh"));
147 }
148
149 fn amain() void {
150 seq('a');
151 var f = async testAsyncSeq();
152 seq('c');
153 cancel f;
154 seq('g');
155 }
156
157 fn testAsyncSeq() void {
158 defer seq('f');
159
160 seq('b');
161 suspend {
162 frame = @frame();
163 }
164 seq('e');
165 }
166 var points = [_]u8{'x'} ** "abcdefgh".len;
167 var index: usize = 0;
168
169 fn seq(c: u8) void {
170 points[index] = c;
171 index += 1;
172 }
173 };
174 S.doTheTest();
175}
176
177test "coroutine suspend with block" {
178 const p = async testSuspendBlock();
179 expect(!global_result);
180 resume a_promise;
181 expect(global_result);
182}
183
184var a_promise: anyframe = undefined;
185var global_result = false;
186async fn testSuspendBlock() void {
187 suspend {
188 comptime expect(@typeOf(@frame()) == *@Frame(testSuspendBlock));
189 a_promise = @frame();
190 }
191
192 // Test to make sure that @frame() works as advertised (issue #1296)
193 // var our_handle: anyframe = @frame();
194 expect(a_promise == anyframe(@frame()));
195
196 global_result = true;
197}
198
199var await_a_promise: anyframe = undefined;
200var await_final_result: i32 = 0;
201
202test "coroutine await" {
203 await_seq('a');
204 const p = async await_amain();
205 await_seq('f');
206 resume await_a_promise;
207 await_seq('i');
208 expect(await_final_result == 1234);
209 expect(std.mem.eql(u8, await_points, "abcdefghi"));
210}
211async fn await_amain() void {
212 await_seq('b');
213 const p = async await_another();
214 await_seq('e');
215 await_final_result = await p;
216 await_seq('h');
217}
218async fn await_another() i32 {
219 await_seq('c');
220 suspend {
221 await_seq('d');
222 await_a_promise = @frame();
223 }
224 await_seq('g');
225 return 1234;
226}
227
228var await_points = [_]u8{0} ** "abcdefghi".len;
229var await_seq_index: usize = 0;
230
231fn await_seq(c: u8) void {
232 await_points[await_seq_index] = c;
233 await_seq_index += 1;
234}
235
236var early_final_result: i32 = 0;
237
238test "coroutine await early return" {
239 early_seq('a');
240 const p = async early_amain();
241 early_seq('f');
242 expect(early_final_result == 1234);
243 expect(std.mem.eql(u8, early_points, "abcdef"));
244}
245async fn early_amain() void {
246 early_seq('b');
247 const p = async early_another();
248 early_seq('d');
249 early_final_result = await p;
250 early_seq('e');
251}
252async fn early_another() i32 {
253 early_seq('c');
254 return 1234;
255}
256
257var early_points = [_]u8{0} ** "abcdef".len;
258var early_seq_index: usize = 0;
259
260fn early_seq(c: u8) void {
261 early_points[early_seq_index] = c;
262 early_seq_index += 1;
263}
264
265test "async function with dot syntax" {
266 const S = struct {
267 var y: i32 = 1;
268 async fn foo() void {
269 y += 1;
270 suspend;
271 }
272 };
273 const p = async S.foo();
274 // can't cancel in tests because they are non-async functions
275 expect(S.y == 2);
276}
277
278test "async fn pointer in a struct field" {
279 var data: i32 = 1;
280 const Foo = struct {
281 bar: async fn (*i32) void,
282 };
283 var foo = Foo{ .bar = simpleAsyncFn2 };
284 var bytes: [64]u8 = undefined;
285 const f = @asyncCall(&bytes, {}, foo.bar, &data);
286 comptime expect(@typeOf(f) == anyframe->void);
287 expect(data == 2);
288 resume f;
289 expect(data == 2);
290 _ = async doTheAwait(f);
291 expect(data == 4);
292}
293
294fn doTheAwait(f: anyframe->void) void {
295 await f;
296}
297
298async fn simpleAsyncFn2(y: *i32) void {
299 defer y.* += 2;
300 y.* += 1;
301 suspend;
302}
303
304test "@asyncCall with return type" {
305 const Foo = struct {
306 bar: async fn () i32,
307
308 var global_frame: anyframe = undefined;
309
310 async fn middle() i32 {
311 return afunc();
312 }
313
314 fn afunc() i32 {
315 global_frame = @frame();
316 suspend;
317 return 1234;
318 }
319 };
320 var foo = Foo{ .bar = Foo.middle };
321 var bytes: [150]u8 = undefined;
322 var aresult: i32 = 0;
323 _ = @asyncCall(&bytes, &aresult, foo.bar);
324 expect(aresult == 0);
325 resume Foo.global_frame;
326 expect(aresult == 1234);
327}
328
329test "async fn with inferred error set" {
330 const S = struct {
331 var global_frame: anyframe = undefined;
332
333 fn doTheTest() void {
334 var frame: [1]@Frame(middle) = undefined;
335 var result: anyerror!void = undefined;
336 _ = @asyncCall(@sliceToBytes(frame[0..]), &result, middle);
337 resume global_frame;
338 std.testing.expectError(error.Fail, result);
339 }
340
341 async fn middle() !void {
342 var f = async middle2();
343 return await f;
344 }
345
346 fn middle2() !void {
347 return failing();
348 }
349
350 fn failing() !void {
351 global_frame = @frame();
352 suspend;
353 return error.Fail;
354 }
355 };
356 S.doTheTest();
357}
358
359test "error return trace across suspend points - early return" {
360 const p = nonFailing();
361 resume p;
362 const p2 = async printTrace(p);
363}
364
365test "error return trace across suspend points - async return" {
366 const p = nonFailing();
367 const p2 = async printTrace(p);
368 resume p;
369}
370
371fn nonFailing() (anyframe->anyerror!void) {
372 const Static = struct {
373 var frame: @Frame(suspendThenFail) = undefined;
374 };
375 Static.frame = async suspendThenFail();
376 return &Static.frame;
377}
378async fn suspendThenFail() anyerror!void {
379 suspend;
380 return error.Fail;
381}
382async fn printTrace(p: anyframe->(anyerror!void)) void {
383 (await p) catch |e| {
384 std.testing.expect(e == error.Fail);
385 if (@errorReturnTrace()) |trace| {
386 expect(trace.index == 1);
387 } else switch (builtin.mode) {
388 .Debug, .ReleaseSafe => @panic("expected return trace"),
389 .ReleaseFast, .ReleaseSmall => {},
390 }
391 };
392}
393
394test "break from suspend" {
395 var my_result: i32 = 1;
396 const p = async testBreakFromSuspend(&my_result);
397 // can't cancel here
398 std.testing.expect(my_result == 2);
399}
400async fn testBreakFromSuspend(my_result: *i32) void {
401 suspend {
402 resume @frame();
403 }
404 my_result.* += 1;
405 suspend;
406 my_result.* += 1;
407}
408
409test "heap allocated async function frame" {
410 const S = struct {
411 var x: i32 = 42;
412
413 fn doTheTest() !void {
414 const frame = try std.heap.direct_allocator.create(@Frame(someFunc));
415 defer std.heap.direct_allocator.destroy(frame);
416
417 expect(x == 42);
418 frame.* = async someFunc();
419 expect(x == 43);
420 resume frame;
421 expect(x == 44);
422 }
423
424 fn someFunc() void {
425 x += 1;
426 suspend;
427 x += 1;
428 }
429 };
430 try S.doTheTest();
431}
432
433test "async function call return value" {
434 const S = struct {
435 var frame: anyframe = undefined;
436 var pt = Point{.x = 10, .y = 11 };
437
438 fn doTheTest() void {
439 expectEqual(pt.x, 10);
440 expectEqual(pt.y, 11);
441 _ = async first();
442 expectEqual(pt.x, 10);
443 expectEqual(pt.y, 11);
444 resume frame;
445 expectEqual(pt.x, 1);
446 expectEqual(pt.y, 2);
447 }
448
449 fn first() void {
450 pt = second(1, 2);
451 }
452
453 fn second(x: i32, y: i32) Point {
454 return other(x, y);
455 }
456
457 fn other(x: i32, y: i32) Point {
458 frame = @frame();
459 suspend;
460 return Point{
461 .x = x,
462 .y = y,
463 };
464 }
465
466 const Point = struct {
467 x: i32,
468 y: i32,
469 };
470 };
471 S.doTheTest();
472}
473
474test "suspension points inside branching control flow" {
475 const S = struct {
476 var result: i32 = 10;
477
478 fn doTheTest() void {
479 expect(10 == result);
480 var frame = async func(true);
481 expect(10 == result);
482 resume frame;
483 expect(11 == result);
484 resume frame;
485 expect(12 == result);
486 resume frame;
487 expect(13 == result);
488 }
489
490 fn func(b: bool) void {
491 while (b) {
492 suspend;
493 result += 1;
494 }
495 }
496 };
497 S.doTheTest();
498}
499
500test "call async function which has struct return type" {
501 const S = struct {
502 var frame: anyframe = undefined;
503
504 fn doTheTest() void {
505 _ = async atest();
506 resume frame;
507 }
508
509 fn atest() void {
510 const result = func();
511 expect(result.x == 5);
512 expect(result.y == 6);
513 }
514
515 const Point = struct {
516 x: usize,
517 y: usize,
518 };
519
520 fn func() Point {
521 suspend {
522 frame = @frame();
523 }
524 return Point{
525 .x = 5,
526 .y = 6,
527 };
528 }
529 };
530 S.doTheTest();
531}
532
533test "errdefers in scope get run when canceling async fn call" {
534 const S = struct {
535 var frame: anyframe = undefined;
536 var x: u32 = 0;
537
538 fn doTheTest() void {
539 x = 9;
540 _ = async cancelIt();
541 resume frame;
542 expect(x == 6);
543
544 x = 9;
545 _ = async awaitIt();
546 resume frame;
547 expect(x == 11);
548 }
549
550 fn cancelIt() void {
551 var f = async func();
552 cancel f;
553 }
554
555 fn awaitIt() void {
556 var f = async func();
557 await f;
558 }
559
560 fn func() void {
561 defer x += 1;
562 errdefer x /= 2;
563 defer x += 1;
564 suspend {
565 frame = @frame();
566 }
567 }
568 };
569 S.doTheTest();
570}
571
572test "pass string literal to async function" {
573 const S = struct {
574 var frame: anyframe = undefined;
575 var ok: bool = false;
576
577 fn doTheTest() void {
578 _ = async hello("hello");
579 resume frame;
580 expect(ok);
581 }
582
583 fn hello(msg: []const u8) void {
584 frame = @frame();
585 suspend;
586 expectEqual(([]const u8)("hello"), msg);
587 ok = true;
588 }
589 };
590 S.doTheTest();
591}
592
593test "cancel inside an errdefer" {
594 const S = struct {
595 var frame: anyframe = undefined;
596
597 fn doTheTest() void {
598 _ = async amainWrap();
599 resume frame;
600 }
601
602 fn amainWrap() !void {
603 var foo = async func();
604 errdefer cancel foo;
605 return error.Bad;
606 }
607
608 fn func() void {
609 frame = @frame();
610 suspend;
611 }
612
613 };
614 S.doTheTest();
615}
616
617test "combining try with errdefer cancel" {
618 const S = struct {
619 var frame: anyframe = undefined;
620 var ok = false;
621
622 fn doTheTest() void {
623 _ = async amain();
624 resume frame;
625 expect(ok);
626 }
627
628 fn amain() !void {
629 var f = async func("https://example.com/");
630 errdefer cancel f;
631
632 _ = try await f;
633 }
634
635 fn func(url: []const u8) ![]u8 {
636 errdefer ok = true;
637 frame = @frame();
638 suspend;
639 return error.Bad;
640 }
641
642 };
643 S.doTheTest();
644}
645
646test "try in an async function with error union and non-zero-bit payload" {
647 const S = struct {
648 var frame: anyframe = undefined;
649 var ok = false;
650
651 fn doTheTest() void {
652 _ = async amain();
653 resume frame;
654 expect(ok);
655 }
656
657 fn amain() void {
658 std.testing.expectError(error.Bad, theProblem());
659 ok = true;
660 }
661
662 fn theProblem() ![]u8 {
663 frame = @frame();
664 suspend;
665 const result = try other();
666 return result;
667 }
668
669 fn other() ![]u8 {
670 return error.Bad;
671 }
672 };
673 S.doTheTest();
674}
675
676test "returning a const error from async function" {
677 const S = struct {
678 var frame: anyframe = undefined;
679 var ok = false;
680
681 fn doTheTest() void {
682 _ = async amain();
683 resume frame;
684 expect(ok);
685 }
686
687 fn amain() !void {
688 var download_frame = async fetchUrl(10, "a string");
689 const download_text = try await download_frame;
690
691 @panic("should not get here");
692 }
693
694 fn fetchUrl(unused: i32, url: []const u8) ![]u8 {
695 frame = @frame();
696 suspend;
697 ok = true;
698 return error.OutOfMemory;
699 }
700 };
701 S.doTheTest();
702}
703
704test "async/await typical usage" {
705 inline for ([_]bool{false, true}) |b1| {
706 inline for ([_]bool{false, true}) |b2| {
707 testAsyncAwaitTypicalUsage(b1, b2).doTheTest();
708 }
709 }
710}
711
712fn testAsyncAwaitTypicalUsage(comptime simulate_fail_download: bool, comptime simulate_fail_file: bool) type {
713 return struct {
714 fn doTheTest() void {
715 _ = async amainWrap();
716 resume global_file_frame;
717 resume global_download_frame;
718 }
719 fn amainWrap() void {
720 if (amain()) |_| {
721 expect(!simulate_fail_download);
722 expect(!simulate_fail_file);
723 } else |e| switch (e) {
724 error.NoResponse => expect(simulate_fail_download),
725 error.FileNotFound => expect(simulate_fail_file),
726 else => @panic("test failure"),
727 }
728 }
729
730 fn amain() !void {
731 const allocator = std.heap.direct_allocator; // TODO once we have the debug allocator, use that, so that this can detect leaks
732 var download_frame = async fetchUrl(allocator, "https://example.com/");
733 errdefer cancel download_frame;
734
735 var file_frame = async readFile(allocator, "something.txt");
736 errdefer cancel file_frame;
737
738 const download_text = try await download_frame;
739 defer allocator.free(download_text);
740
741 const file_text = try await file_frame;
742 defer allocator.free(file_text);
743
744 expect(std.mem.eql(u8, "expected download text", download_text));
745 expect(std.mem.eql(u8, "expected file text", file_text));
746 }
747
748 var global_download_frame: anyframe = undefined;
749 fn fetchUrl(allocator: *std.mem.Allocator, url: []const u8) anyerror![]u8 {
750 global_download_frame = @frame();
751 const result = try std.mem.dupe(allocator, u8, "expected download text");
752 errdefer allocator.free(result);
753 suspend;
754 if (simulate_fail_download) return error.NoResponse;
755 return result;
756 }
757
758 var global_file_frame: anyframe = undefined;
759 fn readFile(allocator: *std.mem.Allocator, filename: []const u8) anyerror![]u8 {
760 global_file_frame = @frame();
761 const result = try std.mem.dupe(allocator, u8, "expected file text");
762 errdefer allocator.free(result);
763 suspend;
764 if (simulate_fail_file) return error.FileNotFound;
765 return result;
766 }
767 };
768}
769
770test "alignment of local variables in async functions" {
771 const S = struct {
772 fn doTheTest() void {
773 var y: u8 = 123;
774 var x: u8 align(128) = 1;
775 expect(@ptrToInt(&x) % 128 == 0);
776 }
777 };
778 S.doTheTest();
779}
test/stage1/behavior/await_struct.zig created+44
...@@ -0,0 +1,44 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4
5const Foo = struct {
6 x: i32,
7};
8
9var await_a_promise: anyframe = undefined;
10var await_final_result = Foo{ .x = 0 };
11
12test "coroutine await struct" {
13 await_seq('a');
14 const p = async await_amain();
15 await_seq('f');
16 resume await_a_promise;
17 await_seq('i');
18 expect(await_final_result.x == 1234);
19 expect(std.mem.eql(u8, await_points, "abcdefghi"));
20}
21async fn await_amain() void {
22 await_seq('b');
23 const p = async await_another();
24 await_seq('e');
25 await_final_result = await p;
26 await_seq('h');
27}
28async fn await_another() Foo {
29 await_seq('c');
30 suspend {
31 await_seq('d');
32 await_a_promise = @frame();
33 }
34 await_seq('g');
35 return Foo{ .x = 1234 };
36}
37
38var await_points = [_]u8{0} ** "abcdefghi".len;
39var await_seq_index: usize = 0;
40
41fn await_seq(c: u8) void {
42 await_points[await_seq_index] = c;
43 await_seq_index += 1;
44}
test/stage1/behavior/coroutine_await_struct.zig deleted-44
...@@ -1,44 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4
5const Foo = struct {
6 x: i32,
7};
8
9var await_a_promise: anyframe = undefined;
10var await_final_result = Foo{ .x = 0 };
11
12test "coroutine await struct" {
13 await_seq('a');
14 const p = async await_amain();
15 await_seq('f');
16 resume await_a_promise;
17 await_seq('i');
18 expect(await_final_result.x == 1234);
19 expect(std.mem.eql(u8, await_points, "abcdefghi"));
20}
21async fn await_amain() void {
22 await_seq('b');
23 const p = async await_another();
24 await_seq('e');
25 await_final_result = await p;
26 await_seq('h');
27}
28async fn await_another() Foo {
29 await_seq('c');
30 suspend {
31 await_seq('d');
32 await_a_promise = @frame();
33 }
34 await_seq('g');
35 return Foo{ .x = 1234 };
36}
37
38var await_points = [_]u8{0} ** "abcdefghi".len;
39var await_seq_index: usize = 0;
40
41fn await_seq(c: u8) void {
42 await_points[await_seq_index] = c;
43 await_seq_index += 1;
44}
test/stage1/behavior/coroutines.zig deleted-779
...@@ -1,779 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
5
6var global_x: i32 = 1;
7
8test "simple coroutine suspend and resume" {
9 const frame = async simpleAsyncFn();
10 expect(global_x == 2);
11 resume frame;
12 expect(global_x == 3);
13 const af: anyframe->void = &frame;
14 resume frame;
15 expect(global_x == 4);
16}
17fn simpleAsyncFn() void {
18 global_x += 1;
19 suspend;
20 global_x += 1;
21 suspend;
22 global_x += 1;
23}
24
25var global_y: i32 = 1;
26
27test "pass parameter to coroutine" {
28 const p = async simpleAsyncFnWithArg(2);
29 expect(global_y == 3);
30 resume p;
31 expect(global_y == 5);
32}
33fn simpleAsyncFnWithArg(delta: i32) void {
34 global_y += delta;
35 suspend;
36 global_y += delta;
37}
38
39test "suspend at end of function" {
40 const S = struct {
41 var x: i32 = 1;
42
43 fn doTheTest() void {
44 expect(x == 1);
45 const p = async suspendAtEnd();
46 expect(x == 2);
47 }
48
49 fn suspendAtEnd() void {
50 x += 1;
51 suspend;
52 }
53 };
54 S.doTheTest();
55}
56
57test "local variable in async function" {
58 const S = struct {
59 var x: i32 = 0;
60
61 fn doTheTest() void {
62 expect(x == 0);
63 const p = async add(1, 2);
64 expect(x == 0);
65 resume p;
66 expect(x == 0);
67 resume p;
68 expect(x == 0);
69 resume p;
70 expect(x == 3);
71 }
72
73 fn add(a: i32, b: i32) void {
74 var accum: i32 = 0;
75 suspend;
76 accum += a;
77 suspend;
78 accum += b;
79 suspend;
80 x = accum;
81 }
82 };
83 S.doTheTest();
84}
85
86test "calling an inferred async function" {
87 const S = struct {
88 var x: i32 = 1;
89 var other_frame: *@Frame(other) = undefined;
90
91 fn doTheTest() void {
92 _ = async first();
93 expect(x == 1);
94 resume other_frame.*;
95 expect(x == 2);
96 }
97
98 fn first() void {
99 other();
100 }
101 fn other() void {
102 other_frame = @frame();
103 suspend;
104 x += 1;
105 }
106 };
107 S.doTheTest();
108}
109
110test "@frameSize" {
111 const S = struct {
112 fn doTheTest() void {
113 {
114 var ptr = @ptrCast(async fn(i32) void, other);
115 const size = @frameSize(ptr);
116 expect(size == @sizeOf(@Frame(other)));
117 }
118 {
119 var ptr = @ptrCast(async fn() void, first);
120 const size = @frameSize(ptr);
121 expect(size == @sizeOf(@Frame(first)));
122 }
123 }
124
125 fn first() void {
126 other(1);
127 }
128 fn other(param: i32) void {
129 var local: i32 = undefined;
130 suspend;
131 }
132 };
133 S.doTheTest();
134}
135
136test "coroutine suspend, resume" {
137 const S = struct {
138 var frame: anyframe = undefined;
139
140 fn doTheTest() void {
141 _ = async amain();
142 seq('d');
143 resume frame;
144 seq('h');
145
146 expect(std.mem.eql(u8, points, "abcdefgh"));
147 }
148
149 fn amain() void {
150 seq('a');
151 var f = async testAsyncSeq();
152 seq('c');
153 cancel f;
154 seq('g');
155 }
156
157 fn testAsyncSeq() void {
158 defer seq('f');
159
160 seq('b');
161 suspend {
162 frame = @frame();
163 }
164 seq('e');
165 }
166 var points = [_]u8{'x'} ** "abcdefgh".len;
167 var index: usize = 0;
168
169 fn seq(c: u8) void {
170 points[index] = c;
171 index += 1;
172 }
173 };
174 S.doTheTest();
175}
176
177test "coroutine suspend with block" {
178 const p = async testSuspendBlock();
179 expect(!global_result);
180 resume a_promise;
181 expect(global_result);
182}
183
184var a_promise: anyframe = undefined;
185var global_result = false;
186async fn testSuspendBlock() void {
187 suspend {
188 comptime expect(@typeOf(@frame()) == *@Frame(testSuspendBlock));
189 a_promise = @frame();
190 }
191
192 // Test to make sure that @frame() works as advertised (issue #1296)
193 // var our_handle: anyframe = @frame();
194 expect(a_promise == anyframe(@frame()));
195
196 global_result = true;
197}
198
199var await_a_promise: anyframe = undefined;
200var await_final_result: i32 = 0;
201
202test "coroutine await" {
203 await_seq('a');
204 const p = async await_amain();
205 await_seq('f');
206 resume await_a_promise;
207 await_seq('i');
208 expect(await_final_result == 1234);
209 expect(std.mem.eql(u8, await_points, "abcdefghi"));
210}
211async fn await_amain() void {
212 await_seq('b');
213 const p = async await_another();
214 await_seq('e');
215 await_final_result = await p;
216 await_seq('h');
217}
218async fn await_another() i32 {
219 await_seq('c');
220 suspend {
221 await_seq('d');
222 await_a_promise = @frame();
223 }
224 await_seq('g');
225 return 1234;
226}
227
228var await_points = [_]u8{0} ** "abcdefghi".len;
229var await_seq_index: usize = 0;
230
231fn await_seq(c: u8) void {
232 await_points[await_seq_index] = c;
233 await_seq_index += 1;
234}
235
236var early_final_result: i32 = 0;
237
238test "coroutine await early return" {
239 early_seq('a');
240 const p = async early_amain();
241 early_seq('f');
242 expect(early_final_result == 1234);
243 expect(std.mem.eql(u8, early_points, "abcdef"));
244}
245async fn early_amain() void {
246 early_seq('b');
247 const p = async early_another();
248 early_seq('d');
249 early_final_result = await p;
250 early_seq('e');
251}
252async fn early_another() i32 {
253 early_seq('c');
254 return 1234;
255}
256
257var early_points = [_]u8{0} ** "abcdef".len;
258var early_seq_index: usize = 0;
259
260fn early_seq(c: u8) void {
261 early_points[early_seq_index] = c;
262 early_seq_index += 1;
263}
264
265test "async function with dot syntax" {
266 const S = struct {
267 var y: i32 = 1;
268 async fn foo() void {
269 y += 1;
270 suspend;
271 }
272 };
273 const p = async S.foo();
274 // can't cancel in tests because they are non-async functions
275 expect(S.y == 2);
276}
277
278test "async fn pointer in a struct field" {
279 var data: i32 = 1;
280 const Foo = struct {
281 bar: async fn (*i32) void,
282 };
283 var foo = Foo{ .bar = simpleAsyncFn2 };
284 var bytes: [64]u8 = undefined;
285 const f = @asyncCall(&bytes, {}, foo.bar, &data);
286 comptime expect(@typeOf(f) == anyframe->void);
287 expect(data == 2);
288 resume f;
289 expect(data == 2);
290 _ = async doTheAwait(f);
291 expect(data == 4);
292}
293
294fn doTheAwait(f: anyframe->void) void {
295 await f;
296}
297
298async fn simpleAsyncFn2(y: *i32) void {
299 defer y.* += 2;
300 y.* += 1;
301 suspend;
302}
303
304test "@asyncCall with return type" {
305 const Foo = struct {
306 bar: async fn () i32,
307
308 var global_frame: anyframe = undefined;
309
310 async fn middle() i32 {
311 return afunc();
312 }
313
314 fn afunc() i32 {
315 global_frame = @frame();
316 suspend;
317 return 1234;
318 }
319 };
320 var foo = Foo{ .bar = Foo.middle };
321 var bytes: [150]u8 = undefined;
322 var aresult: i32 = 0;
323 _ = @asyncCall(&bytes, &aresult, foo.bar);
324 expect(aresult == 0);
325 resume Foo.global_frame;
326 expect(aresult == 1234);
327}
328
329test "async fn with inferred error set" {
330 const S = struct {
331 var global_frame: anyframe = undefined;
332
333 fn doTheTest() void {
334 var frame: [1]@Frame(middle) = undefined;
335 var result: anyerror!void = undefined;
336 _ = @asyncCall(@sliceToBytes(frame[0..]), &result, middle);
337 resume global_frame;
338 std.testing.expectError(error.Fail, result);
339 }
340
341 async fn middle() !void {
342 var f = async middle2();
343 return await f;
344 }
345
346 fn middle2() !void {
347 return failing();
348 }
349
350 fn failing() !void {
351 global_frame = @frame();
352 suspend;
353 return error.Fail;
354 }
355 };
356 S.doTheTest();
357}
358
359test "error return trace across suspend points - early return" {
360 const p = nonFailing();
361 resume p;
362 const p2 = async printTrace(p);
363}
364
365test "error return trace across suspend points - async return" {
366 const p = nonFailing();
367 const p2 = async printTrace(p);
368 resume p;
369}
370
371fn nonFailing() (anyframe->anyerror!void) {
372 const Static = struct {
373 var frame: @Frame(suspendThenFail) = undefined;
374 };
375 Static.frame = async suspendThenFail();
376 return &Static.frame;
377}
378async fn suspendThenFail() anyerror!void {
379 suspend;
380 return error.Fail;
381}
382async fn printTrace(p: anyframe->(anyerror!void)) void {
383 (await p) catch |e| {
384 std.testing.expect(e == error.Fail);
385 if (@errorReturnTrace()) |trace| {
386 expect(trace.index == 1);
387 } else switch (builtin.mode) {
388 .Debug, .ReleaseSafe => @panic("expected return trace"),
389 .ReleaseFast, .ReleaseSmall => {},
390 }
391 };
392}
393
394test "break from suspend" {
395 var my_result: i32 = 1;
396 const p = async testBreakFromSuspend(&my_result);
397 // can't cancel here
398 std.testing.expect(my_result == 2);
399}
400async fn testBreakFromSuspend(my_result: *i32) void {
401 suspend {
402 resume @frame();
403 }
404 my_result.* += 1;
405 suspend;
406 my_result.* += 1;
407}
408
409test "heap allocated async function frame" {
410 const S = struct {
411 var x: i32 = 42;
412
413 fn doTheTest() !void {
414 const frame = try std.heap.direct_allocator.create(@Frame(someFunc));
415 defer std.heap.direct_allocator.destroy(frame);
416
417 expect(x == 42);
418 frame.* = async someFunc();
419 expect(x == 43);
420 resume frame;
421 expect(x == 44);
422 }
423
424 fn someFunc() void {
425 x += 1;
426 suspend;
427 x += 1;
428 }
429 };
430 try S.doTheTest();
431}
432
433test "async function call return value" {
434 const S = struct {
435 var frame: anyframe = undefined;
436 var pt = Point{.x = 10, .y = 11 };
437
438 fn doTheTest() void {
439 expectEqual(pt.x, 10);
440 expectEqual(pt.y, 11);
441 _ = async first();
442 expectEqual(pt.x, 10);
443 expectEqual(pt.y, 11);
444 resume frame;
445 expectEqual(pt.x, 1);
446 expectEqual(pt.y, 2);
447 }
448
449 fn first() void {
450 pt = second(1, 2);
451 }
452
453 fn second(x: i32, y: i32) Point {
454 return other(x, y);
455 }
456
457 fn other(x: i32, y: i32) Point {
458 frame = @frame();
459 suspend;
460 return Point{
461 .x = x,
462 .y = y,
463 };
464 }
465
466 const Point = struct {
467 x: i32,
468 y: i32,
469 };
470 };
471 S.doTheTest();
472}
473
474test "suspension points inside branching control flow" {
475 const S = struct {
476 var result: i32 = 10;
477
478 fn doTheTest() void {
479 expect(10 == result);
480 var frame = async func(true);
481 expect(10 == result);
482 resume frame;
483 expect(11 == result);
484 resume frame;
485 expect(12 == result);
486 resume frame;
487 expect(13 == result);
488 }
489
490 fn func(b: bool) void {
491 while (b) {
492 suspend;
493 result += 1;
494 }
495 }
496 };
497 S.doTheTest();
498}
499
500test "call async function which has struct return type" {
501 const S = struct {
502 var frame: anyframe = undefined;
503
504 fn doTheTest() void {
505 _ = async atest();
506 resume frame;
507 }
508
509 fn atest() void {
510 const result = func();
511 expect(result.x == 5);
512 expect(result.y == 6);
513 }
514
515 const Point = struct {
516 x: usize,
517 y: usize,
518 };
519
520 fn func() Point {
521 suspend {
522 frame = @frame();
523 }
524 return Point{
525 .x = 5,
526 .y = 6,
527 };
528 }
529 };
530 S.doTheTest();
531}
532
533test "errdefers in scope get run when canceling async fn call" {
534 const S = struct {
535 var frame: anyframe = undefined;
536 var x: u32 = 0;
537
538 fn doTheTest() void {
539 x = 9;
540 _ = async cancelIt();
541 resume frame;
542 expect(x == 6);
543
544 x = 9;
545 _ = async awaitIt();
546 resume frame;
547 expect(x == 11);
548 }
549
550 fn cancelIt() void {
551 var f = async func();
552 cancel f;
553 }
554
555 fn awaitIt() void {
556 var f = async func();
557 await f;
558 }
559
560 fn func() void {
561 defer x += 1;
562 errdefer x /= 2;
563 defer x += 1;
564 suspend {
565 frame = @frame();
566 }
567 }
568 };
569 S.doTheTest();
570}
571
572test "pass string literal to async function" {
573 const S = struct {
574 var frame: anyframe = undefined;
575 var ok: bool = false;
576
577 fn doTheTest() void {
578 _ = async hello("hello");
579 resume frame;
580 expect(ok);
581 }
582
583 fn hello(msg: []const u8) void {
584 frame = @frame();
585 suspend;
586 expectEqual(([]const u8)("hello"), msg);
587 ok = true;
588 }
589 };
590 S.doTheTest();
591}
592
593test "cancel inside an errdefer" {
594 const S = struct {
595 var frame: anyframe = undefined;
596
597 fn doTheTest() void {
598 _ = async amainWrap();
599 resume frame;
600 }
601
602 fn amainWrap() !void {
603 var foo = async func();
604 errdefer cancel foo;
605 return error.Bad;
606 }
607
608 fn func() void {
609 frame = @frame();
610 suspend;
611 }
612
613 };
614 S.doTheTest();
615}
616
617test "combining try with errdefer cancel" {
618 const S = struct {
619 var frame: anyframe = undefined;
620 var ok = false;
621
622 fn doTheTest() void {
623 _ = async amain();
624 resume frame;
625 expect(ok);
626 }
627
628 fn amain() !void {
629 var f = async func("https://example.com/");
630 errdefer cancel f;
631
632 _ = try await f;
633 }
634
635 fn func(url: []const u8) ![]u8 {
636 errdefer ok = true;
637 frame = @frame();
638 suspend;
639 return error.Bad;
640 }
641
642 };
643 S.doTheTest();
644}
645
646test "try in an async function with error union and non-zero-bit payload" {
647 const S = struct {
648 var frame: anyframe = undefined;
649 var ok = false;
650
651 fn doTheTest() void {
652 _ = async amain();
653 resume frame;
654 expect(ok);
655 }
656
657 fn amain() void {
658 std.testing.expectError(error.Bad, theProblem());
659 ok = true;
660 }
661
662 fn theProblem() ![]u8 {
663 frame = @frame();
664 suspend;
665 const result = try other();
666 return result;
667 }
668
669 fn other() ![]u8 {
670 return error.Bad;
671 }
672 };
673 S.doTheTest();
674}
675
676test "returning a const error from async function" {
677 const S = struct {
678 var frame: anyframe = undefined;
679 var ok = false;
680
681 fn doTheTest() void {
682 _ = async amain();
683 resume frame;
684 expect(ok);
685 }
686
687 fn amain() !void {
688 var download_frame = async fetchUrl(10, "a string");
689 const download_text = try await download_frame;
690
691 @panic("should not get here");
692 }
693
694 fn fetchUrl(unused: i32, url: []const u8) ![]u8 {
695 frame = @frame();
696 suspend;
697 ok = true;
698 return error.OutOfMemory;
699 }
700 };
701 S.doTheTest();
702}
703
704test "async/await typical usage" {
705 inline for ([_]bool{false, true}) |b1| {
706 inline for ([_]bool{false, true}) |b2| {
707 testAsyncAwaitTypicalUsage(b1, b2).doTheTest();
708 }
709 }
710}
711
712fn testAsyncAwaitTypicalUsage(comptime simulate_fail_download: bool, comptime simulate_fail_file: bool) type {
713 return struct {
714 fn doTheTest() void {
715 _ = async amainWrap();
716 resume global_file_frame;
717 resume global_download_frame;
718 }
719 fn amainWrap() void {
720 if (amain()) |_| {
721 expect(!simulate_fail_download);
722 expect(!simulate_fail_file);
723 } else |e| switch (e) {
724 error.NoResponse => expect(simulate_fail_download),
725 error.FileNotFound => expect(simulate_fail_file),
726 else => @panic("test failure"),
727 }
728 }
729
730 fn amain() !void {
731 const allocator = std.heap.direct_allocator; // TODO once we have the debug allocator, use that, so that this can detect leaks
732 var download_frame = async fetchUrl(allocator, "https://example.com/");
733 errdefer cancel download_frame;
734
735 var file_frame = async readFile(allocator, "something.txt");
736 errdefer cancel file_frame;
737
738 const download_text = try await download_frame;
739 defer allocator.free(download_text);
740
741 const file_text = try await file_frame;
742 defer allocator.free(file_text);
743
744 expect(std.mem.eql(u8, "expected download text", download_text));
745 expect(std.mem.eql(u8, "expected file text", file_text));
746 }
747
748 var global_download_frame: anyframe = undefined;
749 fn fetchUrl(allocator: *std.mem.Allocator, url: []const u8) anyerror![]u8 {
750 global_download_frame = @frame();
751 const result = try std.mem.dupe(allocator, u8, "expected download text");
752 errdefer allocator.free(result);
753 suspend;
754 if (simulate_fail_download) return error.NoResponse;
755 return result;
756 }
757
758 var global_file_frame: anyframe = undefined;
759 fn readFile(allocator: *std.mem.Allocator, filename: []const u8) anyerror![]u8 {
760 global_file_frame = @frame();
761 const result = try std.mem.dupe(allocator, u8, "expected file text");
762 errdefer allocator.free(result);
763 suspend;
764 if (simulate_fail_file) return error.FileNotFound;
765 return result;
766 }
767 };
768}
769
770test "alignment of local variables in async functions" {
771 const S = struct {
772 fn doTheTest() void {
773 var y: u8 = 123;
774 var x: u8 align(128) = 1;
775 expect(@ptrToInt(&x) % 128 == 0);
776 }
777 };
778 S.doTheTest();
779}