master
  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_c and builtin.cpu.arch == .x86) return error.SkipZigTest;
151    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
152
153    const S = extern struct {
154        ptr: *const fn () callconv(if (builtin.target.cpu.arch == .x86) .{ .x86_stdcall = .{} } else .c) i32,
155
156        fn foo() callconv(if (builtin.target.cpu.arch == .x86) .{ .x86_stdcall = .{} } else .c) i32 {
157            return 1234;
158        }
159    };
160
161    var s: S = undefined;
162    s.ptr = S.foo;
163    try expect(s.ptr() == 1234);
164}
165
166const nComplexCallconv = 100;
167fn fComplexCallconvRet(x: u32) callconv(blk: {
168    const s: struct { n: u32 } = .{ .n = nComplexCallconv };
169    break :blk switch (s.n) {
170        0 => .c,
171        1 => .@"inline",
172        else => .auto,
173    };
174}) struct { x: u32 } {
175    return .{ .x = x * x };
176}
177
178test "function with complex callconv and return type expressions" {
179    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
180    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
181
182    try expect(fComplexCallconvRet(3).x == 9);
183}
184
185test "pass by non-copying value" {
186    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
187
188    try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
189}
190
191const Point = struct {
192    x: i32,
193    y: i32,
194};
195
196fn addPointCoords(pt: Point) i32 {
197    return pt.x + pt.y;
198}
199
200test "pass by non-copying value through var arg" {
201    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
202
203    try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3);
204}
205
206fn addPointCoordsVar(pt: anytype) !i32 {
207    comptime assert(@TypeOf(pt) == Point);
208    return pt.x + pt.y;
209}
210
211test "pass by non-copying value as method" {
212    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
213
214    var pt = Point2{ .x = 1, .y = 2 };
215    try expect(pt.addPointCoords() == 3);
216}
217
218const Point2 = struct {
219    x: i32,
220    y: i32,
221
222    fn addPointCoords(self: Point2) i32 {
223        return self.x + self.y;
224    }
225};
226
227test "pass by non-copying value as method, which is generic" {
228    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
229
230    var pt = Point3{ .x = 1, .y = 2 };
231    try expect(pt.addPointCoords(i32) == 3);
232}
233
234const Point3 = struct {
235    x: i32,
236    y: i32,
237
238    fn addPointCoords(self: Point3, comptime T: type) i32 {
239        _ = T;
240        return self.x + self.y;
241    }
242};
243
244test "pass by non-copying value as method, at comptime" {
245    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
246
247    comptime {
248        var pt = Point2{ .x = 1, .y = 2 };
249        try expect(pt.addPointCoords() == 3);
250    }
251}
252
253test "implicit cast fn call result to optional in field result" {
254    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
255    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
256    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
257
258    const S = struct {
259        fn entry() !void {
260            const x = Foo{
261                .field = optionalPtr(),
262            };
263            try expect(x.field.?.* == 999);
264        }
265
266        const glob: i32 = 999;
267
268        fn optionalPtr() *const i32 {
269            return &glob;
270        }
271
272        const Foo = struct {
273            field: ?*const i32,
274        };
275    };
276    try S.entry();
277    try comptime S.entry();
278}
279
280test "void parameters" {
281    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
282
283    try voidFun(1, void{}, 2, {});
284}
285fn voidFun(a: i32, b: void, c: i32, d: void) !void {
286    _ = d;
287    const v = b;
288    const vv: void = if (a == 1) v else {};
289    try expect(a + c == 3);
290    return vv;
291}
292
293test "call function with empty string" {
294    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
295
296    acceptsString("");
297}
298
299fn acceptsString(foo: []u8) void {
300    _ = foo;
301}
302
303test "function pointers" {
304    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
305    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
307
308    const fns = [_]*const @TypeOf(fn1){
309        &fn1,
310        &fn2,
311        &fn3,
312        &fn4,
313    };
314    for (fns, 0..) |f, i| {
315        try expect(f() == @as(u32, @intCast(i)) + 5);
316    }
317}
318fn fn1() u32 {
319    return 5;
320}
321fn fn2() u32 {
322    return 6;
323}
324fn fn3() u32 {
325    return 7;
326}
327fn fn4() u32 {
328    return 8;
329}
330
331test "number literal as an argument" {
332    try numberLiteralArg(3);
333    try comptime numberLiteralArg(3);
334}
335
336fn numberLiteralArg(a: anytype) !void {
337    try expect(a == 3);
338}
339
340test "function call with anon list literal" {
341    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
342    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
343
344    const S = struct {
345        fn doTheTest() !void {
346            try consumeVec(.{ 9, 8, 7 });
347        }
348
349        fn consumeVec(vec: [3]f32) !void {
350            try expect(vec[0] == 9);
351            try expect(vec[1] == 8);
352            try expect(vec[2] == 7);
353        }
354    };
355    try S.doTheTest();
356    try comptime S.doTheTest();
357}
358
359test "function call with anon list literal - 2D" {
360    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
361    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
362
363    const S = struct {
364        fn doTheTest() !void {
365            try consumeVec(.{ .{ 9, 8 }, .{ 7, 6 } });
366        }
367
368        fn consumeVec(vec: [2][2]f32) !void {
369            try expect(vec[0][0] == 9);
370            try expect(vec[0][1] == 8);
371            try expect(vec[1][0] == 7);
372            try expect(vec[1][1] == 6);
373        }
374    };
375    try S.doTheTest();
376    try comptime S.doTheTest();
377}
378
379test "ability to give comptime types and non comptime types to same parameter" {
380    const S = struct {
381        fn doTheTest() !void {
382            var x: i32 = 1;
383            _ = &x;
384            try expect(foo(x) == 10);
385            try expect(foo(i32) == 20);
386        }
387
388        fn foo(arg: anytype) i32 {
389            if (@typeInfo(@TypeOf(arg)) == .type and arg == i32) return 20;
390            return 9 + arg;
391        }
392    };
393    try S.doTheTest();
394    try comptime S.doTheTest();
395}
396
397test "function with inferred error set but returning no error" {
398    const S = struct {
399        fn foo() !void {}
400    };
401
402    const return_ty = @typeInfo(@TypeOf(S.foo)).@"fn".return_type.?;
403    try expectEqual(0, @typeInfo(@typeInfo(return_ty).error_union.error_set).error_set.?.len);
404}
405
406test "import passed byref to function in return type" {
407    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
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_wasm) return error.SkipZigTest; // TODO
422    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
423
424    const S1 = struct {
425        export fn someFunctionThatReturnsAValue() c_int {
426            return 123;
427        }
428    };
429    var fnPtr1: *const fn () callconv(.c) c_int = S1.someFunctionThatReturnsAValue;
430    _ = &fnPtr1;
431    try expect(fnPtr1() == 123);
432    const S2 = struct {
433        extern fn someFunctionThatReturnsAValue() c_int;
434    };
435    var fnPtr2: *const fn () callconv(.c) c_int = S2.someFunctionThatReturnsAValue;
436    _ = &fnPtr2;
437    try expect(fnPtr2() == 123);
438}
439
440test "method call with optional and error union first param" {
441    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
442    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
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    const S = struct {
748        var global: i32 = 1;
749
750        fn returnGlobalPointer() *i32 {
751            return &global;
752        }
753
754        fn returnUndefPointer() *i32 {
755            return undefined;
756        }
757
758        /// Semantically equivalent to `returnUndefPointer`.
759        fn returnStackPointer() *i32 {
760            var stack_allocation: i32 = 1234;
761            const ptr = &stack_allocation; // defeats ast-check detection
762            return ptr;
763        }
764    };
765
766    const ok_ptr = S.returnGlobalPointer();
767    try expect(ok_ptr.* == 1);
768    const bad_ptr_1 = S.returnStackPointer();
769    _ = bad_ptr_1; // dereferencing this would be illegal behavior
770    const bad_ptr_2 = S.returnStackPointer();
771    _ = bad_ptr_2; // dereferencing this would be illegal behavior
772}