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.attrs.@"align");
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" => struct { name: [:0]const u8, value: comptime_int },
259 else => void,
260 } {
261 return .{
262 .name = @typeInfo(T).@"enum".field_names[@backingInt(field)],
263 .value = @typeInfo(T).@"enum".field_values[@backingInt(field)],
264 };
265 }
266
267 pub fn FieldEnum(comptime T: type) type {
268 _ = T;
269 return @Enum(u0, .exhaustive, &.{"A"}, &.{0});
270 }
271 };
272 try S.doTheTest();
273}
274
275test "generic function with void and comptime parameter" {
276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
277
278 const S = struct { x: i32 };
279 const namespace = struct {
280 fn foo(v: void, s: *S, comptime T: type) !void {
281 _ = @as(void, v);
282 try expect(s.x == 1234);
283 try expect(T == u8);
284 }
285 };
286 var s: S = .{ .x = 1234 };
287 try namespace.foo({}, &s, u8);
288}
289
290test "anonymous struct return type referencing comptime parameter" {
291 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
292
293 const S = struct {
294 pub fn extraData(comptime T: type, index: usize) struct { data: T, end: usize } {
295 return .{
296 .data = 1234,
297 .end = index,
298 };
299 }
300 };
301 const s = S.extraData(i32, 5678);
302 try expect(s.data == 1234);
303 try expect(s.end == 5678);
304}
305
306test "generic function instantiation non-duplicates" {
307 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
308 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
309 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
310
311 const S = struct {
312 fn copy(comptime T: type, dest: []T, source: []const T) void {
313 @export(&foo, .{ .name = "test_generic_instantiation_non_dupe" });
314 for (source, 0..) |s, i| dest[i] = s;
315 }
316
317 fn foo() callconv(.c) void {}
318 };
319 var buffer: [100]u8 = undefined;
320 S.copy(u8, &buffer, "hello");
321 S.copy(u8, &buffer, "hello2");
322}
323
324test "generic instantiation of tagged union with only one field" {
325 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
326
327 const S = struct {
328 const U = union(enum) {
329 s: []const u8,
330 };
331
332 fn foo(comptime u: U) usize {
333 return u.s.len;
334 }
335 };
336
337 try expect(S.foo(.{ .s = "a" }) == 1);
338 try expect(S.foo(.{ .s = "ab" }) == 2);
339}
340
341test "generic parameter type is function type" {
342 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
343
344 const S = struct {
345 fn foo(comptime T: type, callback: *const fn (user_data: T) anyerror!void, data: T) anyerror!void {
346 try callback(data);
347 }
348 fn bar(a: u32) anyerror!void {
349 try expect(a == 123);
350 }
351 };
352 try S.foo(u32, S.bar, 123);
353}
354
355test "extern function used as generic parameter" {
356 const S = struct {
357 extern fn usedAsGenericParameterFoo() void;
358 extern fn usedAsGenericParameterBar() void;
359 inline fn usedAsGenericParameterBaz(comptime token: anytype) type {
360 return struct {
361 comptime {
362 _ = token;
363 }
364 };
365 }
366 };
367 const E = struct {
368 export fn usedAsGenericParameterFoo() void {}
369 export fn usedAsGenericParameterBar() void {}
370 };
371 _ = E;
372 try expect(S.usedAsGenericParameterBaz(S.usedAsGenericParameterFoo) !=
373 S.usedAsGenericParameterBaz(S.usedAsGenericParameterBar));
374}
375
376test "generic struct as parameter type" {
377 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
378
379 const S = struct {
380 fn doTheTest(comptime Int: type, thing: struct { int: Int }) !void {
381 try expect(thing.int == 123);
382 }
383 fn doTheTest2(comptime Int: type, comptime thing: struct { int: Int }) !void {
384 try expect(thing.int == 456);
385 }
386 };
387 try S.doTheTest(u32, .{ .int = 123 });
388 try S.doTheTest2(i32, .{ .int = 456 });
389}
390
391test "slice as parameter type" {
392 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
393 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
394
395 const S = struct {
396 fn internComptimeString(comptime str: []const u8) *const []const u8 {
397 return &struct {
398 const intern: []const u8 = str;
399 }.intern;
400 }
401 };
402
403 const source_a = "this is a string";
404 try expect(S.internComptimeString(source_a[1..2]) == S.internComptimeString(source_a[1..2]));
405 try expect(S.internComptimeString(source_a[2..4]) != S.internComptimeString(source_a[5..7]));
406}
407
408test "null sentinel pointer passed as generic argument" {
409 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
410
411 const S = struct {
412 fn doTheTest(a: anytype) !void {
413 try std.testing.expect(@intFromPtr(a) == 8);
414 }
415 };
416 try S.doTheTest((@as([*:null]const [*c]const u8, @ptrFromInt(8))));
417}
418
419test "generic function passed as comptime argument" {
420 const S = struct {
421 fn doMath(comptime f: fn (comptime type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void {
422 const result = try f(i32, a, b);
423 try expect(result == 11);
424 }
425 };
426 try S.doMath(std.math.add, 5, 6);
427}
428
429test "return type of generic function is function pointer" {
430 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
431
432 const S = struct {
433 fn b(comptime T: type) ?*const fn () error{}!T {
434 return null;
435 }
436 };
437
438 try expect(null == S.b(void));
439}
440
441test "coerced function body has inequal value with its uncoerced body" {
442 const S = struct {
443 const A = B(i32, c);
444 fn c() !i32 {
445 return 1234;
446 }
447 fn B(comptime T: type, comptime d: ?fn () anyerror!T) type {
448 return struct {
449 fn do() T {
450 return d.?() catch @panic("fail");
451 }
452 };
453 }
454 };
455 try expect(S.A.do() == 1234);
456}
457
458test "generic function returns value from callconv(.c) function" {
459 const S = struct {
460 fn getU8() callconv(.c) u8 {
461 return 123;
462 }
463
464 fn getGeneric(comptime T: type, supplier: fn () callconv(.c) T) T {
465 return supplier();
466 }
467 };
468
469 try testing.expect(S.getGeneric(u8, S.getU8) == 123);
470}
471
472test "union in struct captures argument" {
473 const S = struct {
474 fn BuildType(comptime T: type) type {
475 return struct {
476 val: union {
477 b: T,
478 },
479 };
480 }
481 };
482 const TestStruct = S.BuildType(u32);
483 const c = TestStruct{ .val = .{ .b = 10 } };
484 try expect(c.val.b == 10);
485}
486
487test "function argument tuple used as struct field" {
488 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
489 const S = struct {
490 fn DeleagateWithContext(comptime Function: type) type {
491 const ArgArgs = std.meta.ArgsTuple(Function);
492 return struct {
493 t: ArgArgs,
494 };
495 }
496
497 const OnConfirm = DeleagateWithContext(fn (bool) void);
498 const CustomDraw = DeleagateWithContext(fn (?OnConfirm) void);
499 };
500
501 var c: S.CustomDraw = undefined;
502 c.t[0] = null;
503 try expect(c.t[0] == null);
504}
505
506test "comptime callconv(.c) function ptr uses comptime type argument" {
507 const S = struct {
508 fn A(
509 comptime T: type,
510 comptime destroycb: ?*const fn (?*T) callconv(.c) void,
511 ) !void {
512 try expect(destroycb == null);
513 }
514 };
515 try S.A(u32, null);
516}
517
518test "call generic function with from function called by the generic function" {
519 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
520 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
521 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
522
523 const GET = struct {
524 key: []const u8,
525 const GET = @This();
526 const Redis = struct {
527 const Command = struct {
528 fn serialize(self: GET, comptime RootSerializer: type) void {
529 return RootSerializer.serializeCommand(.{ "GET", self.key });
530 }
531 };
532 };
533 };
534 const ArgSerializer = struct {
535 fn isCommand(comptime T: type) bool {
536 const tid = @typeInfo(T);
537 return (tid == .@"struct" or tid == .@"enum" or tid == .@"union") and
538 @hasDecl(T, "Redis") and @hasDecl(T.Redis, "Command");
539 }
540 fn serializeCommand(command: anytype) void {
541 const CmdT = @TypeOf(command);
542
543 if (comptime isCommand(CmdT)) {
544 return CmdT.Redis.Command.serialize(command, @This());
545 }
546 }
547 };
548
549 ArgSerializer.serializeCommand(GET{ .key = "banana" });
550}
551
552fn StructCapture(comptime T: type) type {
553 return struct {
554 pub fn foo(comptime x: usize) struct { T } {
555 return .{x};
556 }
557 };
558}
559
560test "call generic function that uses capture from function declaration's scope" {
561 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
562
563 const S = StructCapture(f64);
564 const s = S.foo(123);
565 try expectEqual(123.0, s[0]);
566}
567
568comptime {
569 // The same function parameter instruction being analyzed multiple times
570 // should override the result of the previous analysis.
571 for (0..2) |_| _ = fn (void) void;
572}
573
574test "generic parameter resolves to comptime-only type but is not marked comptime" {
575 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
576
577 const S = struct {
578 fn foo(comptime T: type, rt_false: bool, func: fn (T) void) T {
579 if (rt_false) _ = foo(T, rt_false, func);
580 return 123;
581 }
582 fn bar(_: u8) void {}
583 };
584
585 const rt_result = S.foo(u8, false, S.bar);
586 try expect(rt_result == 123);
587
588 const ct_result = comptime S.foo(u8, false, S.bar);
589 comptime std.debug.assert(ct_result == 123);
590}
591
592test "instantiate coerced generic function" {
593 const S = struct {
594 fn generic(comptime T: type, arg: *const u8) !void {
595 _ = T;
596 _ = arg;
597 }
598 };
599 const coerced: fn (comptime type, *u8) anyerror!void = S.generic;
600 var x: u8 = 20;
601 try coerced(u8, &x);
602}
603
604test "generic struct captures slice of another struct" {
605 const S = struct {
606 const Foo = struct { x: u32 };
607 const foo_array: [2]Foo = undefined;
608
609 fn Bar(foo_slice: []const Foo) type {
610 return struct {
611 const foo_ptr: [*]const Foo = foo_slice.ptr;
612 };
613 }
614 };
615 const T = S.Bar(&S.foo_array);
616 comptime std.debug.assert(T.foo_ptr == &S.foo_array);
617}
618
619test "noalias paramters with generic return type" {
620 const S = struct {
621 pub fn a(noalias _: *u8, im_noalias: usize) im_noalias {}
622 pub fn b(noalias _: *u8, im_noalias: usize, x: *isize) x {
623 _ = im_noalias;
624 }
625 pub fn c(noalias _: *u8, im_noalias: usize, x: isize) struct { x } {
626 _ = im_noalias;
627 }
628 pub fn d(noalias _: *u8, im_noalias: usize, _: anytype) struct { im_noalias } {}
629 pub fn e(noalias _: *u8, _: usize, im_noalias: [5]u9) switch (@TypeOf(im_noalias)) {
630 else => void,
631 } {}
632 pub fn f(noalias _: *u8, _: anytype, im_noalias: u8) switch (@TypeOf(im_noalias)) {
633 else => enum { x, y, z },
634 } {}
635 };
636 _ = S.a;
637 _ = S.b;
638 _ = S.c;
639 _ = S.d;
640 _ = S.e;
641 _ = S.f;
642}