master
  1const std = @import("std");
  2const builtin = @import("builtin");
  3const testing = std.testing;
  4const expect = testing.expect;
  5const expectEqual = testing.expectEqual;
  6
  7test "one param, explicit comptime" {
  8    var x: usize = 0;
  9    x += checkSize(i32);
 10    x += checkSize(bool);
 11    x += checkSize(bool);
 12    try expect(x == 6);
 13}
 14
 15fn checkSize(comptime T: type) usize {
 16    return @sizeOf(T);
 17}
 18
 19test "simple generic fn" {
 20    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 21
 22    try expect(max(i32, 3, -1) == 3);
 23    try expect(max(u8, 1, 100) == 100);
 24    try expect(max(f32, 0.123, 0.456) == 0.456);
 25    try expect(add(2, 3) == 5);
 26}
 27
 28fn max(comptime T: type, a: T, b: T) T {
 29    return if (a > b) a else b;
 30}
 31
 32fn add(comptime a: i32, b: i32) i32 {
 33    return (comptime a) + b;
 34}
 35
 36const the_max = max(u32, 1234, 5678);
 37test "compile time generic eval" {
 38    try expect(the_max == 5678);
 39}
 40
 41fn gimmeTheBigOne(a: u32, b: u32) u32 {
 42    return max(u32, a, b);
 43}
 44
 45fn shouldCallSameInstance(a: u32, b: u32) u32 {
 46    return max(u32, a, b);
 47}
 48
 49fn sameButWithFloats(a: f64, b: f64) f64 {
 50    return max(f64, a, b);
 51}
 52
 53test "fn with comptime args" {
 54    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 55    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 56
 57    try expect(gimmeTheBigOne(1234, 5678) == 5678);
 58    try expect(shouldCallSameInstance(34, 12) == 34);
 59    try expect(sameButWithFloats(0.43, 0.49) == 0.49);
 60}
 61
 62test "anytype params" {
 63    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 64    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 65
 66    try expect(max_i32(12, 34) == 34);
 67    try expect(max_f64(1.2, 3.4) == 3.4);
 68    comptime {
 69        try expect(max_i32(12, 34) == 34);
 70        try expect(max_f64(1.2, 3.4) == 3.4);
 71    }
 72}
 73
 74fn max_anytype(a: anytype, b: anytype) @TypeOf(a, b) {
 75    return if (a > b) a else b;
 76}
 77
 78fn max_i32(a: i32, b: i32) i32 {
 79    return max_anytype(a, b);
 80}
 81
 82fn max_f64(a: f64, b: f64) f64 {
 83    return max_anytype(a, b);
 84}
 85
 86test "type constructed by comptime function call" {
 87    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 88    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 89    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 90
 91    var l: SimpleList(10) = undefined;
 92    l.array[0] = 10;
 93    l.array[1] = 11;
 94    l.array[2] = 12;
 95    const ptr = @as([*]u8, @ptrCast(&l.array));
 96    try expect(ptr[0] == 10);
 97    try expect(ptr[1] == 11);
 98    try expect(ptr[2] == 12);
 99}
100
101fn SimpleList(comptime L: usize) type {
102    var mutable_T = u8;
103    _ = &mutable_T;
104    const T = mutable_T;
105    return struct {
106        array: [L]T,
107    };
108}
109
110test "function with return type type" {
111    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
112    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
113
114    var list: List(i32) = undefined;
115    var list2: List(i32) = undefined;
116    list.length = 10;
117    list2.length = 10;
118    try expect(list.prealloc_items.len == 8);
119    try expect(list2.prealloc_items.len == 8);
120}
121
122pub fn List(comptime T: type) type {
123    return SmallList(T, 8);
124}
125
126pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type {
127    return struct {
128        items: []T,
129        length: usize,
130        prealloc_items: [STATIC_SIZE]T,
131    };
132}
133
134test "const decls in struct" {
135    try expect(GenericDataThing(3).count_plus_one == 4);
136}
137fn GenericDataThing(comptime count: isize) type {
138    return struct {
139        const count_plus_one = count + 1;
140    };
141}
142
143test "use generic param in generic param" {
144    try expect(aGenericFn(i32, 3, 4) == 7);
145}
146fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
147    return a + b;
148}
149
150test "generic fn with implicit cast" {
151    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
152    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
153    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
154
155    try expect(getFirstByte(u8, &[_]u8{13}) == 13);
156    try expect(getFirstByte(u16, &[_]u16{
157        0,
158        13,
159    }) == 0);
160}
161fn getByte(ptr: ?*const u8) u8 {
162    return ptr.?.*;
163}
164fn getFirstByte(comptime T: type, mem: []const T) u8 {
165    return getByte(@as(*const u8, @ptrCast(&mem[0])));
166}
167
168test "generic fn keeps non-generic parameter types" {
169    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
170    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
171    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
172    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
173
174    const A = 128;
175
176    const S = struct {
177        fn f(comptime T: type, s: []T) !void {
178            try expect(A != @typeInfo(@TypeOf(s)).pointer.alignment);
179        }
180    };
181
182    // The compiler monomorphizes `S.f` for `T=u8` on its first use, check that
183    // `x` type not affect `s` parameter type.
184    var x: [16]u8 align(A) = undefined;
185    try S.f(u8, &x);
186}
187
188test "array of generic fns" {
189    try expect(foos[0](true));
190    try expect(!foos[1](true));
191}
192
193const foos = [_]fn (anytype) bool{
194    foo1,
195    foo2,
196};
197
198fn foo1(arg: anytype) bool {
199    return arg;
200}
201fn foo2(arg: anytype) bool {
202    return !arg;
203}
204
205test "generic struct" {
206    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
207    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
208
209    var a1 = GenNode(i32){
210        .value = 13,
211        .next = null,
212    };
213    var b1 = GenNode(bool){
214        .value = true,
215        .next = null,
216    };
217    try expect(a1.value == 13);
218    try expect(a1.value == a1.getVal());
219    try expect(b1.getVal());
220}
221fn GenNode(comptime T: type) type {
222    return struct {
223        value: T,
224        next: ?*GenNode(T),
225        fn getVal(n: *const GenNode(T)) T {
226            return n.value;
227        }
228    };
229}
230
231test "function parameter is generic" {
232    const S = struct {
233        pub fn init(pointer: anytype, comptime fillFn: fn (ptr: *@TypeOf(pointer)) void) void {
234            _ = fillFn;
235        }
236        pub fn fill(self: *u32) void {
237            _ = self;
238        }
239    };
240    var rng: u32 = 2;
241    _ = &rng;
242    S.init(rng, S.fill);
243}
244
245test "generic function instantiation turns into comptime call" {
246    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
247    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
248    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
249
250    const S = struct {
251        fn doTheTest() !void {
252            const E1 = enum { A };
253            const e1f = fieldInfo(E1, .A);
254            try expect(std.mem.eql(u8, e1f.name, "A"));
255        }
256
257        pub fn fieldInfo(comptime T: type, comptime field: FieldEnum(T)) switch (@typeInfo(T)) {
258            .@"enum" => std.builtin.Type.EnumField,
259            else => void,
260        } {
261            return @typeInfo(T).@"enum".fields[@intFromEnum(field)];
262        }
263
264        pub fn FieldEnum(comptime T: type) type {
265            _ = T;
266            return @Enum(u0, .exhaustive, &.{"A"}, &.{0});
267        }
268    };
269    try S.doTheTest();
270}
271
272test "generic function with void and comptime parameter" {
273    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
274
275    const S = struct { x: i32 };
276    const namespace = struct {
277        fn foo(v: void, s: *S, comptime T: type) !void {
278            _ = @as(void, v);
279            try expect(s.x == 1234);
280            try expect(T == u8);
281        }
282    };
283    var s: S = .{ .x = 1234 };
284    try namespace.foo({}, &s, u8);
285}
286
287test "anonymous struct return type referencing comptime parameter" {
288    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
289
290    const S = struct {
291        pub fn extraData(comptime T: type, index: usize) struct { data: T, end: usize } {
292            return .{
293                .data = 1234,
294                .end = index,
295            };
296        }
297    };
298    const s = S.extraData(i32, 5678);
299    try expect(s.data == 1234);
300    try expect(s.end == 5678);
301}
302
303test "generic function instantiation non-duplicates" {
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    if (builtin.os.tag == .wasi) return error.SkipZigTest;
309
310    const S = struct {
311        fn copy(comptime T: type, dest: []T, source: []const T) void {
312            @export(&foo, .{ .name = "test_generic_instantiation_non_dupe" });
313            for (source, 0..) |s, i| dest[i] = s;
314        }
315
316        fn foo() callconv(.c) void {}
317    };
318    var buffer: [100]u8 = undefined;
319    S.copy(u8, &buffer, "hello");
320    S.copy(u8, &buffer, "hello2");
321}
322
323test "generic instantiation of tagged union with only one field" {
324    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
325
326    if (builtin.os.tag == .wasi) return error.SkipZigTest;
327
328    const S = struct {
329        const U = union(enum) {
330            s: []const u8,
331        };
332
333        fn foo(comptime u: U) usize {
334            return u.s.len;
335        }
336    };
337
338    try expect(S.foo(.{ .s = "a" }) == 1);
339    try expect(S.foo(.{ .s = "ab" }) == 2);
340}
341
342test "nested generic function" {
343    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
344
345    const S = struct {
346        fn foo(comptime T: type, callback: *const fn (user_data: T) anyerror!void, data: T) anyerror!void {
347            try callback(data);
348        }
349        fn bar(a: u32) anyerror!void {
350            try expect(a == 123);
351        }
352
353        fn g(_: *const fn (anytype) void) void {}
354    };
355    try expect(@typeInfo(@TypeOf(S.g)).@"fn".is_generic);
356    try S.foo(u32, S.bar, 123);
357}
358
359test "extern function used as generic parameter" {
360    const S = struct {
361        extern fn usedAsGenericParameterFoo() void;
362        extern fn usedAsGenericParameterBar() void;
363        inline fn usedAsGenericParameterBaz(comptime token: anytype) type {
364            return struct {
365                comptime {
366                    _ = token;
367                }
368            };
369        }
370    };
371    const E = struct {
372        export fn usedAsGenericParameterFoo() void {}
373        export fn usedAsGenericParameterBar() void {}
374    };
375    _ = E;
376    try expect(S.usedAsGenericParameterBaz(S.usedAsGenericParameterFoo) !=
377        S.usedAsGenericParameterBaz(S.usedAsGenericParameterBar));
378}
379
380test "generic struct as parameter type" {
381    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
382
383    const S = struct {
384        fn doTheTest(comptime Int: type, thing: struct { int: Int }) !void {
385            try expect(thing.int == 123);
386        }
387        fn doTheTest2(comptime Int: type, comptime thing: struct { int: Int }) !void {
388            try expect(thing.int == 456);
389        }
390    };
391    try S.doTheTest(u32, .{ .int = 123 });
392    try S.doTheTest2(i32, .{ .int = 456 });
393}
394
395test "slice as parameter type" {
396    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
397    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
398
399    const S = struct {
400        fn internComptimeString(comptime str: []const u8) *const []const u8 {
401            return &struct {
402                const intern: []const u8 = str;
403            }.intern;
404        }
405    };
406
407    const source_a = "this is a string";
408    try expect(S.internComptimeString(source_a[1..2]) == S.internComptimeString(source_a[1..2]));
409    try expect(S.internComptimeString(source_a[2..4]) != S.internComptimeString(source_a[5..7]));
410}
411
412test "null sentinel pointer passed as generic argument" {
413    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
414
415    const S = struct {
416        fn doTheTest(a: anytype) !void {
417            try std.testing.expect(@intFromPtr(a) == 8);
418        }
419    };
420    try S.doTheTest((@as([*:null]const [*c]const u8, @ptrFromInt(8))));
421}
422
423test "generic function passed as comptime argument" {
424    const S = struct {
425        fn doMath(comptime f: fn (comptime type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void {
426            const result = try f(i32, a, b);
427            try expect(result == 11);
428        }
429    };
430    try S.doMath(std.math.add, 5, 6);
431}
432
433test "return type of generic function is function pointer" {
434    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
435
436    const S = struct {
437        fn b(comptime T: type) ?*const fn () error{}!T {
438            return null;
439        }
440    };
441
442    try expect(null == S.b(void));
443}
444
445test "coerced function body has inequal value with its uncoerced body" {
446    const S = struct {
447        const A = B(i32, c);
448        fn c() !i32 {
449            return 1234;
450        }
451        fn B(comptime T: type, comptime d: ?fn () anyerror!T) type {
452            return struct {
453                fn do() T {
454                    return d.?() catch @panic("fail");
455                }
456            };
457        }
458    };
459    try expect(S.A.do() == 1234);
460}
461
462test "generic function returns value from callconv(.c) function" {
463    const S = struct {
464        fn getU8() callconv(.c) u8 {
465            return 123;
466        }
467
468        fn getGeneric(comptime T: type, supplier: fn () callconv(.c) T) T {
469            return supplier();
470        }
471    };
472
473    try testing.expect(S.getGeneric(u8, S.getU8) == 123);
474}
475
476test "union in struct captures argument" {
477    const S = struct {
478        fn BuildType(comptime T: type) type {
479            return struct {
480                val: union {
481                    b: T,
482                },
483            };
484        }
485    };
486    const TestStruct = S.BuildType(u32);
487    const c = TestStruct{ .val = .{ .b = 10 } };
488    try expect(c.val.b == 10);
489}
490
491test "function argument tuple used as struct field" {
492    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
493    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
494
495    const S = struct {
496        fn DeleagateWithContext(comptime Function: type) type {
497            const ArgArgs = std.meta.ArgsTuple(Function);
498            return struct {
499                t: ArgArgs,
500            };
501        }
502
503        const OnConfirm = DeleagateWithContext(fn (bool) void);
504        const CustomDraw = DeleagateWithContext(fn (?OnConfirm) void);
505    };
506
507    var c: S.CustomDraw = undefined;
508    c.t[0] = null;
509    try expect(c.t[0] == null);
510}
511
512test "comptime callconv(.c) function ptr uses comptime type argument" {
513    const S = struct {
514        fn A(
515            comptime T: type,
516            comptime destroycb: ?*const fn (?*T) callconv(.c) void,
517        ) !void {
518            try expect(destroycb == null);
519        }
520    };
521    try S.A(u32, null);
522}
523
524test "call generic function with from function called by the generic function" {
525    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
526    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
527    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
528
529    const GET = struct {
530        key: []const u8,
531        const GET = @This();
532        const Redis = struct {
533            const Command = struct {
534                fn serialize(self: GET, comptime RootSerializer: type) void {
535                    return RootSerializer.serializeCommand(.{ "GET", self.key });
536                }
537            };
538        };
539    };
540    const ArgSerializer = struct {
541        fn isCommand(comptime T: type) bool {
542            const tid = @typeInfo(T);
543            return (tid == .@"struct" or tid == .@"enum" or tid == .@"union") and
544                @hasDecl(T, "Redis") and @hasDecl(T.Redis, "Command");
545        }
546        fn serializeCommand(command: anytype) void {
547            const CmdT = @TypeOf(command);
548
549            if (comptime isCommand(CmdT)) {
550                return CmdT.Redis.Command.serialize(command, @This());
551            }
552        }
553    };
554
555    ArgSerializer.serializeCommand(GET{ .key = "banana" });
556}
557
558fn StructCapture(comptime T: type) type {
559    return struct {
560        pub fn foo(comptime x: usize) struct { T } {
561            return .{x};
562        }
563    };
564}
565
566test "call generic function that uses capture from function declaration's scope" {
567    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
568    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
569
570    const S = StructCapture(f64);
571    const s = S.foo(123);
572    try expectEqual(123.0, s[0]);
573}
574
575comptime {
576    // The same function parameter instruction being analyzed multiple times
577    // should override the result of the previous analysis.
578    for (0..2) |_| _ = fn (void) void;
579}
580
581test "generic parameter resolves to comptime-only type but is not marked comptime" {
582    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
583
584    const S = struct {
585        fn foo(comptime T: type, rt_false: bool, func: fn (T) void) T {
586            if (rt_false) _ = foo(T, rt_false, func);
587            return 123;
588        }
589        fn bar(_: u8) void {}
590    };
591
592    const rt_result = S.foo(u8, false, S.bar);
593    try expect(rt_result == 123);
594
595    const ct_result = comptime S.foo(u8, false, S.bar);
596    comptime std.debug.assert(ct_result == 123);
597}
598
599test "instantiate coerced generic function" {
600    const S = struct {
601        fn generic(comptime T: type, arg: *const u8) !void {
602            _ = T;
603            _ = arg;
604        }
605    };
606    const coerced: fn (comptime type, *u8) anyerror!void = S.generic;
607    var x: u8 = 20;
608    try coerced(u8, &x);
609}
610
611test "generic struct captures slice of another struct" {
612    const S = struct {
613        const Foo = struct { x: u32 };
614        const foo_array: [2]Foo = undefined;
615
616        fn Bar(foo_slice: []const Foo) type {
617            return struct {
618                const foo_ptr: [*]const Foo = foo_slice.ptr;
619            };
620        }
621    };
622    const T = S.Bar(&S.foo_array);
623    comptime std.debug.assert(T.foo_ptr == &S.foo_array);
624}
625
626test "noalias paramters with generic return type" {
627    const S = struct {
628        pub fn a(noalias _: *u8, im_noalias: usize) im_noalias {}
629        pub fn b(noalias _: *u8, im_noalias: usize, x: *isize) x {
630            _ = im_noalias;
631        }
632        pub fn c(noalias _: *u8, im_noalias: usize, x: isize) struct { x } {
633            _ = im_noalias;
634        }
635        pub fn d(noalias _: *u8, im_noalias: usize, _: anytype) struct { im_noalias } {}
636        pub fn e(noalias _: *u8, _: usize, im_noalias: [5]u9) switch (@TypeOf(im_noalias)) {
637            else => void,
638        } {}
639        pub fn f(noalias _: *u8, _: anytype, im_noalias: u8) switch (@TypeOf(im_noalias)) {
640            else => enum { x, y, z },
641        } {}
642    };
643    _ = S.a;
644    _ = S.b;
645    _ = S.c;
646    _ = S.d;
647    _ = S.e;
648    _ = S.f;
649}