zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob 6bd627df (17901B) - Raw


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