1const std = @import("std");
2const builtin = @import("builtin");
3const testing = std.testing;
4const assert = std.debug.assert;
5const expect = testing.expect;
6const expectEqual = testing.expectEqual;
7
8test "params" {
9 try expect(testParamsAdd(22, 11) == 33);
10}
11fn testParamsAdd(a: i32, b: i32) i32 {
12 return a + b;
13}
14
15test "local variables" {
16 testLocVars(2);
17}
18fn testLocVars(b: i32) void {
19 const a: i32 = 1;
20 if (a + b != 3) unreachable;
21}
22
23test "mutable local variables" {
24 var zero: i32 = 0;
25 _ = &zero;
26 try expect(zero == 0);
27
28 var i = @as(i32, 0);
29 while (i != 3) {
30 i += 1;
31 }
32 try expect(i == 3);
33}
34
35test "separate block scopes" {
36 {
37 const no_conflict: i32 = 5;
38 try expect(no_conflict == 5);
39 }
40
41 const c = x: {
42 const no_conflict = @as(i32, 10);
43 break :x no_conflict;
44 };
45 try expect(c == 10);
46}
47
48fn @"weird function name"() i32 {
49 return 1234;
50}
51test "weird function name" {
52 try expect(@"weird function name"() == 1234);
53}
54
55test "assign inline fn to const variable" {
56 const a = inlineFn;
57 a();
58}
59
60inline fn inlineFn() void {}
61
62fn outer(y: u32) *const fn (u32) u32 {
63 const Y = @TypeOf(y);
64 const st = struct {
65 fn get(z: u32) u32 {
66 return z + @sizeOf(Y);
67 }
68 };
69 return st.get;
70}
71
72test "return inner function which references comptime variable of outer function" {
73 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
74
75 const func = outer(10);
76 try expect(func(3) == 7);
77}
78
79test "discard the result of a function that returns a struct" {
80 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
81 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
82
83 const S = struct {
84 fn entry() void {
85 _ = func();
86 }
87
88 fn func() Foo {
89 return undefined;
90 }
91
92 const Foo = struct {
93 a: u64,
94 b: u64,
95 };
96 };
97 S.entry();
98 comptime S.entry();
99}
100
101test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {
102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
105
106 const S = struct {
107 field: u32,
108
109 fn doTheTest() !void {
110 bar2 = actualFn;
111 const result = try foo();
112 try expect(result.field == 1234);
113 }
114
115 const Foo = struct { field: u32 };
116
117 fn foo() !Foo {
118 var res: Foo = undefined;
119 res.field = bar();
120 return res;
121 }
122
123 inline fn bar() u32 {
124 return bar2.?();
125 }
126
127 var bar2: ?*const fn () u32 = null;
128
129 fn actualFn() u32 {
130 return 1234;
131 }
132 };
133 try S.doTheTest();
134}
135
136test "implicit cast function unreachable return" {
137 wantsFnWithVoid(fnWithUnreachable);
138}
139
140fn wantsFnWithVoid(comptime f: fn () void) void {
141 _ = f;
142}
143
144fn fnWithUnreachable() noreturn {
145 unreachable;
146}
147
148test "extern struct with stdcallcc fn pointer" {
149 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
150 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
151
152 const S = extern struct {
153 ptr: *const fn () callconv(if (builtin.target.cpu.arch == .x86) .{ .x86_stdcall = .{} } else .c) i32,
154
155 fn foo() callconv(if (builtin.target.cpu.arch == .x86) .{ .x86_stdcall = .{} } else .c) i32 {
156 return 1234;
157 }
158 };
159
160 var s: S = undefined;
161 s.ptr = S.foo;
162 try expect(s.ptr() == 1234);
163}
164
165const nComplexCallconv = 100;
166fn fComplexCallconvRet(x: u32) callconv(blk: {
167 const s: struct { n: u32 } = .{ .n = nComplexCallconv };
168 break :blk switch (s.n) {
169 0 => .c,
170 1 => .@"inline",
171 else => .auto,
172 };
173}) struct { x: u32 } {
174 return .{ .x = x * x };
175}
176
177test "function with complex callconv and return type expressions" {
178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
179 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
180
181 try expect(fComplexCallconvRet(3).x == 9);
182}
183
184test "pass by non-copying value" {
185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
186
187 try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
188}
189
190const Point = struct {
191 x: i32,
192 y: i32,
193};
194
195fn addPointCoords(pt: Point) i32 {
196 return pt.x + pt.y;
197}
198
199test "pass by non-copying value through var arg" {
200 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
201
202 try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3);
203}
204
205fn addPointCoordsVar(pt: anytype) !i32 {
206 comptime assert(@TypeOf(pt) == Point);
207 return pt.x + pt.y;
208}
209
210test "pass by non-copying value as method" {
211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
212
213 var pt = Point2{ .x = 1, .y = 2 };
214 try expect(pt.addPointCoords() == 3);
215}
216
217const Point2 = struct {
218 x: i32,
219 y: i32,
220
221 fn addPointCoords(self: Point2) i32 {
222 return self.x + self.y;
223 }
224};
225
226test "pass by non-copying value as method, which is generic" {
227 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
228
229 var pt = Point3{ .x = 1, .y = 2 };
230 try expect(pt.addPointCoords(i32) == 3);
231}
232
233const Point3 = struct {
234 x: i32,
235 y: i32,
236
237 fn addPointCoords(self: Point3, comptime T: type) i32 {
238 _ = T;
239 return self.x + self.y;
240 }
241};
242
243test "pass by non-copying value as method, at comptime" {
244 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
245
246 comptime {
247 var pt = Point2{ .x = 1, .y = 2 };
248 try expect(pt.addPointCoords() == 3);
249 }
250}
251
252test "implicit cast fn call result to optional in field result" {
253 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
254 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
255 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
256
257 const S = struct {
258 fn entry() !void {
259 const x = Foo{
260 .field = optionalPtr(),
261 };
262 try expect(x.field.?.* == 999);
263 }
264
265 const glob: i32 = 999;
266
267 fn optionalPtr() *const i32 {
268 return &glob;
269 }
270
271 const Foo = struct {
272 field: ?*const i32,
273 };
274 };
275 try S.entry();
276 try comptime S.entry();
277}
278
279test "void parameters" {
280 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
281
282 try voidFun(1, {}, 2, {});
283}
284fn voidFun(a: i32, b: void, c: i32, d: void) !void {
285 _ = d;
286 const v = b;
287 const vv: void = if (a == 1) v else {};
288 try expect(a + c == 3);
289 return vv;
290}
291
292test "call function with empty string" {
293 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
294
295 acceptsString("");
296}
297
298fn acceptsString(foo: []u8) void {
299 _ = foo;
300}
301
302test "function pointers" {
303 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
304 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
306
307 const fns = [_]*const @TypeOf(fn1){
308 &fn1,
309 &fn2,
310 &fn3,
311 &fn4,
312 };
313 for (fns, 0..) |f, i| {
314 try expect(f() == @as(u32, @intCast(i)) + 5);
315 }
316}
317fn fn1() u32 {
318 return 5;
319}
320fn fn2() u32 {
321 return 6;
322}
323fn fn3() u32 {
324 return 7;
325}
326fn fn4() u32 {
327 return 8;
328}
329
330test "number literal as an argument" {
331 try numberLiteralArg(3);
332 try comptime numberLiteralArg(3);
333}
334
335fn numberLiteralArg(a: anytype) !void {
336 try expect(a == 3);
337}
338
339test "function call with anon list literal" {
340 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
341 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
342
343 const S = struct {
344 fn doTheTest() !void {
345 try consumeVec(.{ 9, 8, 7 });
346 }
347
348 fn consumeVec(vec: [3]f32) !void {
349 try expect(vec[0] == 9);
350 try expect(vec[1] == 8);
351 try expect(vec[2] == 7);
352 }
353 };
354 try S.doTheTest();
355 try comptime S.doTheTest();
356}
357
358test "function call with anon list literal - 2D" {
359 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
360 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
361
362 const S = struct {
363 fn doTheTest() !void {
364 try consumeVec(.{ .{ 9, 8 }, .{ 7, 6 } });
365 }
366
367 fn consumeVec(vec: [2][2]f32) !void {
368 try expect(vec[0][0] == 9);
369 try expect(vec[0][1] == 8);
370 try expect(vec[1][0] == 7);
371 try expect(vec[1][1] == 6);
372 }
373 };
374 try S.doTheTest();
375 try comptime S.doTheTest();
376}
377
378test "ability to give comptime types and non comptime types to same parameter" {
379 const S = struct {
380 fn doTheTest() !void {
381 var x: i32 = 1;
382 _ = &x;
383 try expect(foo(x) == 10);
384 try expect(foo(i32) == 20);
385 }
386
387 fn foo(arg: anytype) i32 {
388 if (@typeInfo(@TypeOf(arg)) == .type and arg == i32) return 20;
389 return 9 + arg;
390 }
391 };
392 try S.doTheTest();
393 try comptime S.doTheTest();
394}
395
396test "function with inferred error set but returning no error" {
397 const S = struct {
398 fn foo() !void {}
399 };
400
401 const return_ty = @typeInfo(@TypeOf(S.foo)).@"fn".return_type.?;
402 try expectEqual(0, @typeInfo(@typeInfo(return_ty).error_union.error_set).error_set.error_names.?.len);
403}
404
405test "import passed byref to function in return type" {
406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
407 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
408
409 const S = struct {
410 fn get() @import("std").ArrayList(i32) {
411 const x: @import("std").ArrayList(i32) = .empty;
412 return x;
413 }
414 };
415 const list = S.get();
416 try expect(list.items.len == 0);
417}
418
419test "implicit cast function to function ptr" {
420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
421 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
422
423 const S1 = struct {
424 export fn someFunctionThatReturnsAValue() c_int {
425 return 123;
426 }
427 };
428 var fnPtr1: *const fn () callconv(.c) c_int = S1.someFunctionThatReturnsAValue;
429 _ = &fnPtr1;
430 try expect(fnPtr1() == 123);
431 const S2 = struct {
432 extern fn someFunctionThatReturnsAValue() c_int;
433 };
434 var fnPtr2: *const fn () callconv(.c) c_int = S2.someFunctionThatReturnsAValue;
435 _ = &fnPtr2;
436 try expect(fnPtr2() == 123);
437}
438
439test "method call with optional and error union first param" {
440 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
441 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
442 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
443
444 const S = struct {
445 x: i32 = 1234,
446
447 fn opt(s: ?@This()) !void {
448 try expect(s.?.x == 1234);
449 }
450 fn errUnion(s: anyerror!@This()) !void {
451 try expect((try s).x == 1234);
452 }
453 };
454 var s: S = .{};
455 try s.opt();
456 try s.errUnion();
457}
458
459test "method call with optional pointer first param" {
460 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
461 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
462 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
463
464 const S = struct {
465 x: i32 = 1234,
466
467 fn method(s: ?*@This()) !void {
468 try expect(s.?.x == 1234);
469 }
470 };
471 var s: S = .{};
472 try s.method();
473 const s_ptr = &s;
474 try s_ptr.method();
475}
476
477test "using @ptrCast on function pointers" {
478 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
479 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
480 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
481
482 const S = struct {
483 const A = struct { data: [4]u8 };
484
485 fn at(arr: *const A, index: usize) *const u8 {
486 return &arr.data[index];
487 }
488
489 fn run() !void {
490 const a = A{ .data = "abcd".* };
491 const casted_fn = @as(*const fn (*const anyopaque, usize) *const u8, @ptrCast(&at));
492 const casted_impl = @as(*const anyopaque, @ptrCast(&a));
493 const ptr = casted_fn(casted_impl, 2);
494 try expect(ptr.* == 'c');
495 }
496 };
497
498 try S.run();
499 // https://github.com/ziglang/zig/issues/2626
500 // try comptime S.run();
501}
502
503test "function returns function returning type" {
504 const S = struct {
505 fn a() fn () type {
506 return (struct {
507 fn b() type {
508 return u32;
509 }
510 }).b;
511 }
512 };
513 try expect(S.a()() == u32);
514}
515
516test "peer type resolution of inferred error set with non-void payload" {
517 const S = struct {
518 fn openDataFile(mode: enum { read, write }) !u32 {
519 return switch (mode) {
520 .read => foo(),
521 .write => bar(),
522 };
523 }
524 fn foo() error{ a, b }!u32 {
525 return 1;
526 }
527 fn bar() error{ c, d }!u32 {
528 return 2;
529 }
530 };
531 try expect(try S.openDataFile(.read) == 1);
532}
533
534test "lazy values passed to anytype parameter" {
535 const A = struct {
536 a: u32,
537 fn foo(comptime a: anytype) !void {
538 try expect(a[0][0] == @sizeOf(@This()));
539 }
540 };
541 try A.foo(.{[_]usize{@sizeOf(A)}});
542
543 const B = struct {
544 fn foo(comptime a: anytype) !void {
545 try expect(a.x == 0);
546 }
547 };
548 try B.foo(.{ .x = @sizeOf(B) });
549
550 const C = struct {};
551 try expect(@as(u32, @truncate(@sizeOf(C))) == 0);
552
553 const D = struct {};
554 try expect(@sizeOf(D) << 1 == 0);
555}
556
557test "pass and return comptime-only types" {
558 const S = struct {
559 fn returnNull(comptime x: @TypeOf(null)) @TypeOf(null) {
560 return x;
561 }
562 fn returnUndefined(comptime x: @TypeOf(undefined)) @TypeOf(undefined) {
563 return x;
564 }
565 };
566
567 try expectEqual(null, S.returnNull(null));
568 try expectEqual(@as(u0, 0), S.returnUndefined(undefined));
569}
570
571test "pointer to alias behaves same as pointer to function" {
572 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
573 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
574
575 const S = struct {
576 fn foo() u32 {
577 return 11227;
578 }
579 const bar = foo;
580 };
581 var a = &S.bar;
582 _ = &a;
583 try std.testing.expect(S.foo() == a());
584}
585
586test "comptime parameters don't have to be marked comptime if only called at comptime" {
587 const S = struct {
588 fn foo(x: comptime_int, y: comptime_int) u32 {
589 return x + y;
590 }
591 };
592 comptime std.debug.assert(S.foo(5, 6) == 11);
593}
594
595test "inline function with comptime-known comptime-only return type called at runtime" {
596 const S = struct {
597 inline fn foo(x: *i32, y: *const i32) type {
598 x.* = y.*;
599 return f32;
600 }
601 };
602 var a: i32 = 0;
603 const b: i32 = 111;
604 const T = S.foo(&a, &b);
605 try expectEqual(111, a);
606 try expectEqual(f32, T);
607}
608
609test "address of function parameter is consistent" {
610 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
611
612 const S = struct {
613 fn paramAddrMatch(x: u8) bool {
614 return &x == &x;
615 }
616 };
617 try expect(S.paramAddrMatch(0));
618 comptime assert(S.paramAddrMatch(0));
619}
620
621test "address of function parameter is consistent in other parameter type" {
622 const S = struct {
623 fn paramAddrMatch(comptime x: u8, y: if (&x != &x) unreachable else u8) void {
624 _ = y;
625 }
626 };
627 S.paramAddrMatch(1, 2);
628}
629
630test "address of function parameter is consistent in function return type" {
631 const S = struct {
632 fn paramAddrMatch(comptime x: u8) if (&x != &x) unreachable else void {}
633 };
634 S.paramAddrMatch(1);
635}
636
637test "function parameter self equality" {
638 const S = struct {
639 fn equal(x: u32) bool {
640 return x == x;
641 }
642 fn notEqual(x: u32) bool {
643 return x != x;
644 }
645 fn lessThan(x: u32) bool {
646 return x < x;
647 }
648 fn lessThanOrEqual(x: u32) bool {
649 return x <= x;
650 }
651 fn greaterThan(x: u32) bool {
652 return x > x;
653 }
654 fn greaterThanOrEqual(x: u32) bool {
655 return x >= x;
656 }
657 };
658 try expect(S.equal(42));
659 try expect(!S.notEqual(42));
660 try expect(!S.lessThan(42));
661 try expect(S.lessThanOrEqual(42));
662 try expect(!S.greaterThan(42));
663 try expect(S.greaterThanOrEqual(42));
664}
665
666test "inline call propagates comptime-known argument to generic parameter and return types" {
667 const S = struct {
668 inline fn f(x: bool, y: if (x) u8 else u16) if (x) bool else u32 {
669 if (x) {
670 comptime assert(@TypeOf(y) == u8);
671 return y == 0;
672 } else {
673 comptime assert(@TypeOf(y) == u16);
674 return y * 10;
675 }
676 }
677 fn g(x: bool, y: if (x) u8 else u16) if (x) bool else u32 {
678 if (x) {
679 comptime assert(@TypeOf(y) == u8);
680 return y == 0;
681 } else {
682 comptime assert(@TypeOf(y) == u16);
683 return y * 10;
684 }
685 }
686 };
687
688 const a0 = S.f(true, 200); // false
689 const a1 = S.f(false, 1234); // 12340
690
691 const b0 = @call(.always_inline, S.g, .{ true, 200 }); // false
692 const b1 = @call(.always_inline, S.g, .{ false, 1234 }); // 12340
693
694 comptime assert(@TypeOf(a0) == bool);
695 comptime assert(@TypeOf(b0) == bool);
696 try expect(a0 == false);
697 try expect(b0 == false);
698
699 comptime assert(@TypeOf(a1) == u32);
700 comptime assert(@TypeOf(b1) == u32);
701 try expect(a1 == 12340);
702 try expect(b1 == 12340);
703}
704
705test "inline function return type is evaluated at comptime" {
706 const S = struct {
707 inline fn assertComptimeAndRet(x: anytype) @TypeOf(x) {
708 if (!@inComptime()) comptime unreachable;
709 return x;
710 }
711
712 inline fn foo(val: anytype) assertComptimeAndRet(u16) {
713 return val;
714 }
715 };
716
717 const result = S.foo(123);
718 comptime assert(@TypeOf(result) == u16);
719 try expect(result == 123);
720}
721
722test "coerce generic function making concrete parameter generic" {
723 const S = struct {
724 fn foo(_: anytype, x: u32) u32 {
725 comptime assert(@TypeOf(x) == u32);
726 return x;
727 }
728 };
729 const coerced: fn (anytype, anytype) u32 = S.foo;
730 const result = coerced({}, 123);
731 try expect(result == 123);
732}
733
734test "coerce generic function making generic parameter concrete" {
735 const S = struct {
736 fn foo(_: anytype, x: anytype) u32 {
737 comptime assert(@TypeOf(x) == u32);
738 return x;
739 }
740 };
741 const coerced: fn (anytype, u32) u32 = S.foo;
742 const result = coerced({}, 123);
743 try expect(result == 123);
744}
745
746test "return undefined pointer from function, directly and by expired local" {
747 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
748
749 const S = struct {
750 var global: i32 = 1;
751
752 fn returnGlobalPointer() *i32 {
753 return &global;
754 }
755
756 fn returnUndefPointer() *i32 {
757 return undefined;
758 }
759
760 /// Semantically equivalent to `returnUndefPointer`.
761 fn returnStackPointer() *i32 {
762 var stack_allocation: i32 = 1234;
763 const ptr = &stack_allocation; // defeats ast-check detection
764 return ptr;
765 }
766 };
767
768 const ok_ptr = S.returnGlobalPointer();
769 try expect(ok_ptr.* == 1);
770 const bad_ptr_1 = S.returnStackPointer();
771 _ = bad_ptr_1; // dereferencing this would be illegal behavior
772 const bad_ptr_2 = S.returnStackPointer();
773 _ = bad_ptr_2; // dereferencing this would be illegal behavior
774}
775
776test "a function that works at comptime but not runtime" {
777 const a = comptime testComptimeOnlyFn(1, 1);
778 try expect(a[0] == 1);
779 try expect(a[1] == 2);
780}
781
782fn testComptimeOnlyFn(x: u32, y: u32) [2]u8 {
783 const xa: [x]u8 = .{1};
784 const ya: [y]u8 = .{2};
785 return xa ++ ya;
786}