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 }