master
  1const builtin = @import("builtin");
  2const std = @import("std");
  3const assert = std.debug.assert;
  4const expect = std.testing.expect;
  5const expectEqual = std.testing.expectEqual;
  6
  7test "super basic invocations" {
  8    const foo = struct {
  9        fn foo() i32 {
 10            return 1234;
 11        }
 12    }.foo;
 13    try expect(@call(.auto, foo, .{}) == 1234);
 14    comptime assert(@call(.always_inline, foo, .{}) == 1234);
 15    {
 16        // comptime call without comptime keyword
 17        const result = @call(.compile_time, foo, .{}) == 1234;
 18        comptime assert(result);
 19    }
 20}
 21
 22test "basic invocations" {
 23    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 24    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
 25    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 26    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 27    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 28
 29    if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support tail call modifiers
 30
 31    const foo = struct {
 32        fn foo(_: i32) i32 {
 33            return 1234;
 34        }
 35    }.foo;
 36    try expect(@call(.auto, foo, .{1}) == 1234);
 37    comptime {
 38        // comptime calls with supported modifiers
 39        try expect(@call(.auto, foo, .{2}) == 1234);
 40        try expect(@call(.no_suspend, foo, .{3}) == 1234);
 41        try expect(@call(.always_tail, foo, .{4}) == 1234);
 42        try expect(@call(.always_inline, foo, .{5}) == 1234);
 43    }
 44    // comptime call without comptime keyword
 45    const result = @call(.compile_time, foo, .{6}) == 1234;
 46    comptime assert(result);
 47    // runtime calls of comptime-known function
 48    try expect(@call(.no_suspend, foo, .{7}) == 1234);
 49    try expect(@call(.never_tail, foo, .{8}) == 1234);
 50    try expect(@call(.never_inline, foo, .{9}) == 1234);
 51    // CBE does not support attributes on runtime functions
 52    if (builtin.zig_backend != .stage2_c) {
 53        // runtime calls of non comptime-known function
 54        var alias_foo = &foo;
 55        _ = &alias_foo;
 56        try expect(@call(.no_suspend, alias_foo, .{10}) == 1234);
 57        try expect(@call(.never_tail, alias_foo, .{11}) == 1234);
 58        try expect(@call(.never_inline, alias_foo, .{12}) == 1234);
 59    }
 60}
 61
 62test "tuple parameters" {
 63    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 64    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 65    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 66
 67    const add = struct {
 68        fn add(a: i32, b: i32) i32 {
 69            return a + b;
 70        }
 71    }.add;
 72    var a: i32 = 12;
 73    var b: i32 = 34;
 74    _ = .{ &a, &b };
 75    try expect(@call(.auto, add, .{ a, 34 }) == 46);
 76    try expect(@call(.auto, add, .{ 12, b }) == 46);
 77    try expect(@call(.auto, add, .{ a, b }) == 46);
 78    try expect(@call(.auto, add, .{ 12, 34 }) == 46);
 79    if (false) {
 80        comptime assert(@call(.auto, add, .{ 12, 34 }) == 46); // TODO
 81    }
 82    try expect(comptime @call(.auto, add, .{ 12, 34 }) == 46);
 83    {
 84        const separate_args0 = .{ a, b };
 85        const separate_args1 = .{ a, 34 };
 86        const separate_args2 = .{ 12, 34 };
 87        const separate_args3 = .{ 12, b };
 88        try expect(@call(.always_inline, add, separate_args0) == 46);
 89        try expect(@call(.always_inline, add, separate_args1) == 46);
 90        try expect(@call(.always_inline, add, separate_args2) == 46);
 91        try expect(@call(.always_inline, add, separate_args3) == 46);
 92    }
 93}
 94
 95test "result location of function call argument through runtime condition and struct init" {
 96    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 97    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 98
 99    const E = enum { a, b };
100    const S = struct {
101        e: E,
102    };
103    const namespace = struct {
104        fn foo(s: S) !void {
105            try expect(s.e == .b);
106        }
107    };
108    var runtime = true;
109    _ = &runtime;
110    try namespace.foo(.{
111        .e = if (!runtime) .a else .b,
112    });
113}
114
115test "function call with 40 arguments" {
116    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
117    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
119
120    const S = struct {
121        fn doTheTest(thirty_nine: i32) !void {
122            const result = add(
123                0,
124                1,
125                2,
126                3,
127                4,
128                5,
129                6,
130                7,
131                8,
132                9,
133                10,
134                11,
135                12,
136                13,
137                14,
138                15,
139                16,
140                17,
141                18,
142                19,
143                20,
144                21,
145                22,
146                23,
147                24,
148                25,
149                26,
150                27,
151                28,
152                29,
153                30,
154                31,
155                32,
156                33,
157                34,
158                35,
159                36,
160                37,
161                38,
162                thirty_nine,
163                40,
164            );
165            try expect(result == 820);
166            try expect(thirty_nine == 39);
167        }
168
169        fn add(
170            a0: i32,
171            a1: i32,
172            a2: i32,
173            a3: i32,
174            a4: i32,
175            a5: i32,
176            a6: i32,
177            a7: i32,
178            a8: i32,
179            a9: i32,
180            a10: i32,
181            a11: i32,
182            a12: i32,
183            a13: i32,
184            a14: i32,
185            a15: i32,
186            a16: i32,
187            a17: i32,
188            a18: i32,
189            a19: i32,
190            a20: i32,
191            a21: i32,
192            a22: i32,
193            a23: i32,
194            a24: i32,
195            a25: i32,
196            a26: i32,
197            a27: i32,
198            a28: i32,
199            a29: i32,
200            a30: i32,
201            a31: i32,
202            a32: i32,
203            a33: i32,
204            a34: i32,
205            a35: i32,
206            a36: i32,
207            a37: i32,
208            a38: i32,
209            a39: i32,
210            a40: i32,
211        ) i32 {
212            return a0 +
213                a1 +
214                a2 +
215                a3 +
216                a4 +
217                a5 +
218                a6 +
219                a7 +
220                a8 +
221                a9 +
222                a10 +
223                a11 +
224                a12 +
225                a13 +
226                a14 +
227                a15 +
228                a16 +
229                a17 +
230                a18 +
231                a19 +
232                a20 +
233                a21 +
234                a22 +
235                a23 +
236                a24 +
237                a25 +
238                a26 +
239                a27 +
240                a28 +
241                a29 +
242                a30 +
243                a31 +
244                a32 +
245                a33 +
246                a34 +
247                a35 +
248                a36 +
249                a37 +
250                a38 +
251                a39 +
252                a40;
253        }
254    };
255    try S.doTheTest(39);
256}
257
258test "arguments to comptime parameters generated in comptime blocks" {
259    const S = struct {
260        fn fortyTwo() i32 {
261            return 42;
262        }
263
264        fn foo(comptime x: i32) void {
265            if (x != 42) @compileError("bad");
266        }
267    };
268    S.foo(S.fortyTwo());
269}
270
271test "forced tail call" {
272    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
273    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
274    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
275    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
276    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
277    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
278    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
279
280    if (builtin.zig_backend == .stage2_llvm) {
281        if (builtin.cpu.arch.isMIPS() or builtin.cpu.arch.isPowerPC() or builtin.cpu.arch.isWasm()) {
282            return error.SkipZigTest;
283        }
284    }
285
286    if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls
287
288    const S = struct {
289        fn fibonacciTailInternal(n: u16, a: u16, b: u16) u16 {
290            if (n == 0) return a;
291            if (n == 1) return b;
292            return @call(
293                .always_tail,
294                fibonacciTailInternal,
295                .{ n - 1, b, a + b },
296            );
297        }
298
299        fn fibonacciTail(n: u16) u16 {
300            return fibonacciTailInternal(n, 0, 1);
301        }
302    };
303    try expect(S.fibonacciTail(10) == 55);
304}
305
306test "inline call preserves tail call" {
307    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
308    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
309    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
310    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
311    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
312    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
313    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
314
315    if (builtin.zig_backend == .stage2_llvm) {
316        if (builtin.cpu.arch.isMIPS() or builtin.cpu.arch.isPowerPC() or builtin.cpu.arch.isWasm()) {
317            return error.SkipZigTest;
318        }
319    }
320
321    if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls
322
323    const max_depth = 1000;
324    const S = struct {
325        var a: u16 = 0;
326        fn foo() void {
327            return bar();
328        }
329
330        inline fn bar() void {
331            if (a == max_depth) return;
332            // Stack overflow if not tail called
333            var buf: [100_000]u16 = undefined;
334            buf[a] = a;
335            a += 1;
336            return @call(.always_tail, foo, .{});
337        }
338    };
339    S.foo();
340    try expect(S.a == max_depth);
341}
342
343test "inline call doesn't re-evaluate non generic struct" {
344    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
345    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
346
347    const S = struct {
348        fn foo(f: struct { a: u8, b: u8 }) !void {
349            try expect(f.a == 123);
350            try expect(f.b == 45);
351        }
352    };
353    const ArgTuple = std.meta.ArgsTuple(@TypeOf(S.foo));
354    try @call(.always_inline, S.foo, ArgTuple{.{ .a = 123, .b = 45 }});
355    try comptime @call(.always_inline, S.foo, ArgTuple{.{ .a = 123, .b = 45 }});
356}
357
358test "Enum constructed by @Enum passed as generic argument" {
359    const S = struct {
360        const E = std.meta.FieldEnum(struct {
361            prev_pos: bool,
362            pos: bool,
363            vel: bool,
364            damp_vel: bool,
365            acc: bool,
366            rgba: bool,
367            prev_scale: bool,
368            scale: bool,
369            prev_rotation: bool,
370            rotation: bool,
371            angular_vel: bool,
372            alive: bool,
373        });
374        fn foo(comptime a: E, b: u32) !void {
375            try expect(@intFromEnum(a) == b);
376        }
377    };
378    inline for (@typeInfo(S.E).@"enum".fields, 0..) |_, i| {
379        try S.foo(@as(S.E, @enumFromInt(i)), i);
380    }
381}
382
383test "generic function with generic function parameter" {
384    const S = struct {
385        fn f(comptime a: fn (anytype) anyerror!void, b: anytype) anyerror!void {
386            try a(b);
387        }
388        fn g(a: anytype) anyerror!void {
389            try expect(a == 123);
390        }
391    };
392    try S.f(S.g, 123);
393}
394
395test "recursive inline call with comptime known argument" {
396    const S = struct {
397        inline fn foo(x: i32) i32 {
398            if (x <= 0) {
399                return 0;
400            } else {
401                return x * 2 + foo(x - 1);
402            }
403        }
404    };
405
406    try expect(S.foo(4) == 20);
407}
408
409test "inline while with @call" {
410    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
411
412    const S = struct {
413        fn inc(a: *u32) void {
414            a.* += 1;
415        }
416    };
417    var a: u32 = 0;
418    comptime var i = 0;
419    inline while (i < 10) : (i += 1) {
420        @call(.auto, S.inc, .{&a});
421    }
422    try expect(a == 10);
423}
424
425test "method call as parameter type" {
426    const S = struct {
427        fn foo(x: anytype, y: @TypeOf(x).Inner()) @TypeOf(y) {
428            return y;
429        }
430        fn Inner() type {
431            return u64;
432        }
433    };
434    try expectEqual(@as(u64, 123), S.foo(S{}, 123));
435    try expectEqual(@as(u64, 500), S.foo(S{}, 500));
436}
437
438test "non-anytype generic parameters provide result type" {
439    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
440    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
441
442    const S = struct {
443        fn f(comptime T: type, y: T) !void {
444            try expectEqual(@as(T, 123), y);
445        }
446
447        fn g(x: anytype, y: @TypeOf(x)) !void {
448            try expectEqual(@as(@TypeOf(x), 0x222), y);
449        }
450    };
451
452    var rt_u16: u16 = 123;
453    var rt_u32: u32 = 0x10000222;
454    _ = .{ &rt_u16, &rt_u32 };
455
456    try S.f(u8, @intCast(rt_u16));
457    try S.f(u8, @intCast(123));
458
459    try S.g(rt_u16, @truncate(rt_u32));
460    try S.g(rt_u16, @truncate(0x10000222));
461
462    try comptime S.f(u8, @intCast(123));
463    try comptime S.g(@as(u16, undefined), @truncate(0x99990222));
464}
465
466test "argument to generic function has correct result type" {
467    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
468    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
469
470    const S = struct {
471        fn foo(_: anytype, e: enum { a, b }) bool {
472            return e == .b;
473        }
474
475        fn doTheTest() !void {
476            var t = true;
477            _ = &t;
478
479            // Since the enum literal passes through a runtime conditional here, these can only
480            // compile if RLS provides the correct result type to the argument
481            try expect(foo({}, if (!t) .a else .b));
482            try expect(!foo("dummy", if (t) .a else .b));
483            try expect(foo({}, if (t) .b else .a));
484            try expect(!foo(123, if (t) .a else .a));
485            try expect(foo(123, if (t) .b else .b));
486        }
487    };
488
489    try S.doTheTest();
490    try comptime S.doTheTest();
491}
492
493test "call inline fn through pointer" {
494    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
495
496    const S = struct {
497        inline fn foo(x: u8) !void {
498            try expect(x == 123);
499        }
500    };
501    const f = &S.foo;
502    try f(123);
503}
504
505test "call function in comptime field" {
506    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
507
508    const S = struct {
509        comptime capacity: fn () u64 = capacity_,
510        fn capacity_() u64 {
511            return 64;
512        }
513    };
514    try std.testing.expect((S{}).capacity() == 64);
515}
516
517test "call function pointer in comptime field" {
518    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
519    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
520    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
521
522    const Auto = struct {
523        auto: [max_len]u8 = undefined,
524        offset: u64 = 0,
525
526        comptime capacityFn: *const fn () u64 = capacity,
527
528        const max_len: u64 = 32;
529
530        fn capacity() u64 {
531            return max_len;
532        }
533    };
534
535    const a: Auto = .{ .offset = 16, .capacityFn = Auto.capacity };
536    try std.testing.expect(a.capacityFn() == 32);
537    try std.testing.expect((a.capacityFn)() == 32);
538}
539
540test "generic function pointer can be called" {
541    const S = struct {
542        var ok = false;
543        fn foo(x: anytype) void {
544            ok = x;
545        }
546    };
547    const x = &S.foo;
548    x(true);
549    try expect(S.ok);
550}
551
552test "value returned from comptime function is comptime known" {
553    const S = struct {
554        fn fields(comptime T: type) switch (@typeInfo(T)) {
555            .@"struct" => []const std.builtin.Type.StructField,
556            else => unreachable,
557        } {
558            return switch (@typeInfo(T)) {
559                .@"struct" => |info| info.fields,
560                else => unreachable,
561            };
562        }
563    };
564    const fields_list = S.fields(@TypeOf(.{}));
565    if (fields_list.len != 0)
566        @compileError("Argument count mismatch");
567}
568
569test "registers get overwritten when ignoring return" {
570    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
571    if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .linux) return error.SkipZigTest;
572
573    const S = struct {
574        fn open() usize {
575            return 42;
576        }
577        fn write(fd: usize, a: [*]const u8, len: usize) usize {
578            return syscall4(.WRITE, fd, @intFromPtr(a), len);
579        }
580        fn syscall4(_: enum { WRITE }, _: usize, _: usize, _: usize) usize {
581            return 23;
582        }
583        fn close(fd: usize) usize {
584            if (fd != 42)
585                unreachable;
586            return 0;
587        }
588    };
589
590    const fd = S.open();
591    _ = S.write(fd, "a", 1);
592    _ = S.close(fd);
593}
594
595test "call with union with zero sized field is not memorized incorrectly" {
596    const U = union(enum) {
597        T: type,
598        N: void,
599        fn S(comptime query: @This()) type {
600            return struct {
601                fn tag() type {
602                    return query.T;
603                }
604            };
605        }
606    };
607    const s1 = U.S(U{ .T = u32 }).tag();
608    try std.testing.expectEqual(u32, s1);
609
610    const s2 = U.S(U{ .T = u64 }).tag();
611    try std.testing.expectEqual(u64, s2);
612}
613
614test "function call with cast to anyopaque pointer" {
615    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
616    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
617    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
618
619    const Foo = struct {
620        y: u8,
621        var foo: @This() = undefined;
622        const t = &foo;
623
624        fn bar(pointer: ?*anyopaque) void {
625            _ = pointer;
626        }
627    };
628    Foo.bar(Foo.t);
629}
630
631test "arguments pointed to on stack into tailcall" {
632    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
633    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
634    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
635    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
636    if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls
637
638    switch (builtin.cpu.arch) {
639        .wasm32,
640        .wasm64,
641        .mips,
642        .mipsel,
643        .mips64,
644        .mips64el,
645        .powerpc,
646        .powerpcle,
647        .powerpc64,
648        .powerpc64le,
649        => return error.SkipZigTest,
650        else => {},
651    }
652
653    const S = struct {
654        var base: usize = undefined;
655        var result_off: [7]usize = undefined;
656        var result_len: [7]usize = undefined;
657        var result_index: usize = 0;
658
659        noinline fn insertionSort(data: []u64) void {
660            result_off[result_index] = @intFromPtr(data.ptr) - base;
661            result_len[result_index] = data.len;
662            result_index += 1;
663            if (data.len > 1) {
664                var least_i: usize = 0;
665                var i: usize = 1;
666                while (i < data.len) : (i += 1) {
667                    if (data[i] < data[least_i])
668                        least_i = i;
669                }
670                std.mem.swap(u64, &data[0], &data[least_i]);
671
672                // there used to be a bug where
673                // `data[1..]` is created on the stack
674                // and pointed to by the first argument register
675                // then stack is invalidated by the tailcall and
676                // overwritten by callee
677                // https://github.com/ziglang/zig/issues/9703
678                return @call(.always_tail, insertionSort, .{data[1..]});
679            }
680        }
681    };
682
683    var data = [_]u64{ 1, 6, 2, 7, 1, 9, 3 };
684    S.base = @intFromPtr(&data);
685    S.insertionSort(data[0..]);
686    try expect(S.result_len[0] == 7);
687    try expect(S.result_len[1] == 6);
688    try expect(S.result_len[2] == 5);
689    try expect(S.result_len[3] == 4);
690    try expect(S.result_len[4] == 3);
691    try expect(S.result_len[5] == 2);
692    try expect(S.result_len[6] == 1);
693
694    try expect(S.result_off[0] == 0);
695    try expect(S.result_off[1] == 8);
696    try expect(S.result_off[2] == 16);
697    try expect(S.result_off[3] == 24);
698    try expect(S.result_off[4] == 32);
699    try expect(S.result_off[5] == 40);
700    try expect(S.result_off[6] == 48);
701}
702
703test "tail call function pointer" {
704    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
705    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
706    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
707    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
708    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
709    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
710    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
711
712    if (builtin.zig_backend == .stage2_llvm) {
713        if (builtin.cpu.arch.isMIPS() or builtin.cpu.arch.isPowerPC() or builtin.cpu.arch.isWasm()) {
714            return error.SkipZigTest;
715        }
716    }
717
718    if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls
719
720    const S = struct {
721        fn foo(n: u8) void {
722            if (n == 0) return;
723            const other: *const fn (u8) void = &bar;
724            return @call(.always_tail, other, .{n - 1});
725        }
726        fn bar(n: u8) void {
727            var other: *const fn (u8) void = undefined;
728            other = &foo; // runtime-known pointer
729            return @call(.always_tail, other, .{n});
730        }
731    };
732
733    S.foo(100);
734}