blob 556a8c99 (21035B) - Raw
1 const std = @import("std"); 2 const builtin = @import("builtin"); 3 const Type = std.builtin.Type; 4 const testing = std.testing; 5 6 fn testTypes(comptime types: []const type) !void { 7 inline for (types) |testType| { 8 try testing.expect(testType == @Type(@typeInfo(testType))); 9 } 10 } 11 12 test "Type.MetaType" { 13 try testing.expect(type == @Type(.{ .Type = {} })); 14 try testTypes(&[_]type{type}); 15 } 16 17 test "Type.Void" { 18 try testing.expect(void == @Type(.{ .Void = {} })); 19 try testTypes(&[_]type{void}); 20 } 21 22 test "Type.Bool" { 23 try testing.expect(bool == @Type(.{ .Bool = {} })); 24 try testTypes(&[_]type{bool}); 25 } 26 27 test "Type.NoReturn" { 28 try testing.expect(noreturn == @Type(.{ .NoReturn = {} })); 29 try testTypes(&[_]type{noreturn}); 30 } 31 32 test "Type.Int" { 33 try testing.expect(u1 == @Type(.{ .Int = .{ .signedness = .unsigned, .bits = 1 } })); 34 try testing.expect(i1 == @Type(.{ .Int = .{ .signedness = .signed, .bits = 1 } })); 35 try testing.expect(u8 == @Type(.{ .Int = .{ .signedness = .unsigned, .bits = 8 } })); 36 try testing.expect(i8 == @Type(.{ .Int = .{ .signedness = .signed, .bits = 8 } })); 37 try testing.expect(u64 == @Type(.{ .Int = .{ .signedness = .unsigned, .bits = 64 } })); 38 try testing.expect(i64 == @Type(.{ .Int = .{ .signedness = .signed, .bits = 64 } })); 39 try testTypes(&[_]type{ u8, u32, i64 }); 40 } 41 42 test "Type.ComptimeFloat" { 43 try testTypes(&[_]type{comptime_float}); 44 } 45 test "Type.ComptimeInt" { 46 try testTypes(&[_]type{comptime_int}); 47 } 48 test "Type.Undefined" { 49 try testTypes(&[_]type{@TypeOf(undefined)}); 50 } 51 test "Type.Null" { 52 try testTypes(&[_]type{@TypeOf(null)}); 53 } 54 55 test "Type.EnumLiteral" { 56 try testTypes(&[_]type{ 57 @TypeOf(.Dummy), 58 }); 59 } 60 61 test "Type.Pointer" { 62 try testTypes(&[_]type{ 63 // One Value Pointer Types 64 *u8, *const u8, 65 *volatile u8, *const volatile u8, 66 *align(4) u8, *align(4) const u8, 67 *align(4) volatile u8, *align(4) const volatile u8, 68 *align(8) u8, *align(8) const u8, 69 *align(8) volatile u8, *align(8) const volatile u8, 70 *allowzero u8, *allowzero const u8, 71 *allowzero volatile u8, *allowzero const volatile u8, 72 *allowzero align(4) u8, *allowzero align(4) const u8, 73 *allowzero align(4) volatile u8, *allowzero align(4) const volatile u8, 74 // Many Values Pointer Types 75 [*]u8, [*]const u8, 76 [*]volatile u8, [*]const volatile u8, 77 [*]align(4) u8, [*]align(4) const u8, 78 [*]align(4) volatile u8, [*]align(4) const volatile u8, 79 [*]align(8) u8, [*]align(8) const u8, 80 [*]align(8) volatile u8, [*]align(8) const volatile u8, 81 [*]allowzero u8, [*]allowzero const u8, 82 [*]allowzero volatile u8, [*]allowzero const volatile u8, 83 [*]allowzero align(4) u8, [*]allowzero align(4) const u8, 84 [*]allowzero align(4) volatile u8, [*]allowzero align(4) const volatile u8, 85 // Slice Types 86 []u8, []const u8, 87 []volatile u8, []const volatile u8, 88 []align(4) u8, []align(4) const u8, 89 []align(4) volatile u8, []align(4) const volatile u8, 90 []align(8) u8, []align(8) const u8, 91 []align(8) volatile u8, []align(8) const volatile u8, 92 []allowzero u8, []allowzero const u8, 93 []allowzero volatile u8, []allowzero const volatile u8, 94 []allowzero align(4) u8, []allowzero align(4) const u8, 95 []allowzero align(4) volatile u8, []allowzero align(4) const volatile u8, 96 // C Pointer Types 97 [*c]u8, [*c]const u8, 98 [*c]volatile u8, [*c]const volatile u8, 99 [*c]align(4) u8, [*c]align(4) const u8, 100 [*c]align(4) volatile u8, [*c]align(4) const volatile u8, 101 [*c]align(8) u8, [*c]align(8) const u8, 102 [*c]align(8) volatile u8, [*c]align(8) const volatile u8, 103 }); 104 } 105 106 test "Type.Float" { 107 try testing.expect(f16 == @Type(.{ .Float = .{ .bits = 16 } })); 108 try testing.expect(f32 == @Type(.{ .Float = .{ .bits = 32 } })); 109 try testing.expect(f64 == @Type(.{ .Float = .{ .bits = 64 } })); 110 try testing.expect(f80 == @Type(.{ .Float = .{ .bits = 80 } })); 111 try testing.expect(f128 == @Type(.{ .Float = .{ .bits = 128 } })); 112 try testTypes(&[_]type{ f16, f32, f64, f80, f128 }); 113 } 114 115 test "Type.Array" { 116 try testing.expect([123]u8 == @Type(.{ 117 .Array = .{ 118 .len = 123, 119 .child = u8, 120 .sentinel = null, 121 }, 122 })); 123 try testing.expect([2]u32 == @Type(.{ 124 .Array = .{ 125 .len = 2, 126 .child = u32, 127 .sentinel = null, 128 }, 129 })); 130 try testing.expect([2:0]u32 == @Type(.{ 131 .Array = .{ 132 .len = 2, 133 .child = u32, 134 .sentinel = &@as(u32, 0), 135 }, 136 })); 137 try testTypes(&[_]type{ [1]u8, [30]usize, [7]bool }); 138 } 139 140 test "@Type create slice with null sentinel" { 141 const Slice = @Type(.{ 142 .Pointer = .{ 143 .size = .Slice, 144 .is_const = true, 145 .is_volatile = false, 146 .is_allowzero = false, 147 .alignment = 8, 148 .address_space = .generic, 149 .child = *i32, 150 .sentinel = null, 151 }, 152 }); 153 try testing.expect(Slice == []align(8) const *i32); 154 } 155 156 test "@Type picks up the sentinel value from Type" { 157 try testTypes(&[_]type{ 158 [11:0]u8, [4:10]u8, 159 [*:0]u8, [*:0]const u8, 160 [*:0]volatile u8, [*:0]const volatile u8, 161 [*:0]align(4) u8, [*:0]align(4) const u8, 162 [*:0]align(4) volatile u8, [*:0]align(4) const volatile u8, 163 [*:0]align(8) u8, [*:0]align(8) const u8, 164 [*:0]align(8) volatile u8, [*:0]align(8) const volatile u8, 165 [*:0]allowzero u8, [*:0]allowzero const u8, 166 [*:0]allowzero volatile u8, [*:0]allowzero const volatile u8, 167 [*:0]allowzero align(4) u8, [*:0]allowzero align(4) const u8, 168 [*:0]allowzero align(4) volatile u8, [*:0]allowzero align(4) const volatile u8, 169 [*:5]allowzero align(4) volatile u8, [*:5]allowzero align(4) const volatile u8, 170 [:0]u8, [:0]const u8, 171 [:0]volatile u8, [:0]const volatile u8, 172 [:0]align(4) u8, [:0]align(4) const u8, 173 [:0]align(4) volatile u8, [:0]align(4) const volatile u8, 174 [:0]align(8) u8, [:0]align(8) const u8, 175 [:0]align(8) volatile u8, [:0]align(8) const volatile u8, 176 [:0]allowzero u8, [:0]allowzero const u8, 177 [:0]allowzero volatile u8, [:0]allowzero const volatile u8, 178 [:0]allowzero align(4) u8, [:0]allowzero align(4) const u8, 179 [:0]allowzero align(4) volatile u8, [:0]allowzero align(4) const volatile u8, 180 [:4]allowzero align(4) volatile u8, [:4]allowzero align(4) const volatile u8, 181 }); 182 } 183 184 test "Type.Optional" { 185 try testTypes(&[_]type{ 186 ?u8, 187 ?*u8, 188 ?[]u8, 189 ?[*]u8, 190 ?[*c]u8, 191 }); 192 } 193 194 test "Type.ErrorUnion" { 195 try testTypes(&[_]type{ 196 error{}!void, 197 error{Error}!void, 198 }); 199 } 200 201 test "Type.Opaque" { 202 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO 203 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO 204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO 205 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO 206 207 const Opaque = @Type(.{ 208 .Opaque = .{ 209 .decls = &.{}, 210 }, 211 }); 212 try testing.expect(Opaque != opaque {}); 213 try testing.expectEqualSlices( 214 Type.Declaration, 215 &.{}, 216 @typeInfo(Opaque).Opaque.decls, 217 ); 218 } 219 220 test "Type.Vector" { 221 try testTypes(&[_]type{ 222 @Vector(0, u8), 223 @Vector(4, u8), 224 @Vector(8, *u8), 225 @Vector(0, u8), 226 @Vector(4, u8), 227 @Vector(8, *u8), 228 }); 229 } 230 231 test "Type.AnyFrame" { 232 if (builtin.zig_backend != .stage1) { 233 // https://github.com/ziglang/zig/issues/6025 234 return error.SkipZigTest; 235 } 236 237 try testTypes(&[_]type{ 238 anyframe, 239 anyframe->u8, 240 anyframe->anyframe->u8, 241 }); 242 } 243 244 fn add(a: i32, b: i32) i32 { 245 return a + b; 246 } 247 248 test "Type.ErrorSet" { 249 if (builtin.zig_backend == .stage1) return error.SkipZigTest; 250 251 try testing.expect(@Type(.{ .ErrorSet = null }) == anyerror); 252 253 // error sets don't compare equal so just check if they compile 254 inline for (.{ error{}, error{A}, error{ A, B, C } }) |T| { 255 const info = @typeInfo(T); 256 const T2 = @Type(info); 257 try testing.expect(T == T2); 258 } 259 } 260 261 test "Type.Struct" { 262 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO 263 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO 264 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO 265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO 266 267 const A = @Type(@typeInfo(struct { x: u8, y: u32 })); 268 const infoA = @typeInfo(A).Struct; 269 try testing.expectEqual(Type.ContainerLayout.Auto, infoA.layout); 270 try testing.expectEqualSlices(u8, "x", infoA.fields[0].name); 271 try testing.expectEqual(u8, infoA.fields[0].field_type); 272 try testing.expectEqual(@as(?*const anyopaque, null), infoA.fields[0].default_value); 273 try testing.expectEqualSlices(u8, "y", infoA.fields[1].name); 274 try testing.expectEqual(u32, infoA.fields[1].field_type); 275 try testing.expectEqual(@as(?*const anyopaque, null), infoA.fields[1].default_value); 276 try testing.expectEqualSlices(Type.Declaration, &.{}, infoA.decls); 277 try testing.expectEqual(@as(bool, false), infoA.is_tuple); 278 279 var a = A{ .x = 0, .y = 1 }; 280 try testing.expectEqual(@as(u8, 0), a.x); 281 try testing.expectEqual(@as(u32, 1), a.y); 282 a.y += 1; 283 try testing.expectEqual(@as(u32, 2), a.y); 284 285 const B = @Type(@typeInfo(extern struct { x: u8, y: u32 = 5 })); 286 const infoB = @typeInfo(B).Struct; 287 try testing.expectEqual(Type.ContainerLayout.Extern, infoB.layout); 288 try testing.expectEqualSlices(u8, "x", infoB.fields[0].name); 289 try testing.expectEqual(u8, infoB.fields[0].field_type); 290 try testing.expectEqual(@as(?*const anyopaque, null), infoB.fields[0].default_value); 291 try testing.expectEqualSlices(u8, "y", infoB.fields[1].name); 292 try testing.expectEqual(u32, infoB.fields[1].field_type); 293 try testing.expectEqual(@as(u32, 5), @ptrCast(*align(1) const u32, infoB.fields[1].default_value.?).*); 294 try testing.expectEqual(@as(usize, 0), infoB.decls.len); 295 try testing.expectEqual(@as(bool, false), infoB.is_tuple); 296 297 const C = @Type(@typeInfo(packed struct { x: u8 = 3, y: u32 = 5 })); 298 const infoC = @typeInfo(C).Struct; 299 try testing.expectEqual(Type.ContainerLayout.Packed, infoC.layout); 300 try testing.expectEqualSlices(u8, "x", infoC.fields[0].name); 301 try testing.expectEqual(u8, infoC.fields[0].field_type); 302 try testing.expectEqual(@as(u8, 3), @ptrCast(*const u8, infoC.fields[0].default_value.?).*); 303 try testing.expectEqualSlices(u8, "y", infoC.fields[1].name); 304 try testing.expectEqual(u32, infoC.fields[1].field_type); 305 try testing.expectEqual(@as(u32, 5), @ptrCast(*align(1) const u32, infoC.fields[1].default_value.?).*); 306 try testing.expectEqual(@as(usize, 0), infoC.decls.len); 307 try testing.expectEqual(@as(bool, false), infoC.is_tuple); 308 309 // anon structs 310 const D = @Type(@typeInfo(@TypeOf(.{ .x = 3, .y = 5 }))); 311 const infoD = @typeInfo(D).Struct; 312 try testing.expectEqual(Type.ContainerLayout.Auto, infoD.layout); 313 try testing.expectEqualSlices(u8, "x", infoD.fields[0].name); 314 try testing.expectEqual(comptime_int, infoD.fields[0].field_type); 315 try testing.expectEqual(@as(comptime_int, 3), @ptrCast(*const comptime_int, infoD.fields[0].default_value.?).*); 316 try testing.expectEqualSlices(u8, "y", infoD.fields[1].name); 317 try testing.expectEqual(comptime_int, infoD.fields[1].field_type); 318 try testing.expectEqual(@as(comptime_int, 5), @ptrCast(*const comptime_int, infoD.fields[1].default_value.?).*); 319 try testing.expectEqual(@as(usize, 0), infoD.decls.len); 320 try testing.expectEqual(@as(bool, false), infoD.is_tuple); 321 322 // tuples 323 const E = @Type(@typeInfo(@TypeOf(.{ 1, 2 }))); 324 const infoE = @typeInfo(E).Struct; 325 try testing.expectEqual(Type.ContainerLayout.Auto, infoE.layout); 326 try testing.expectEqualSlices(u8, "0", infoE.fields[0].name); 327 try testing.expectEqual(comptime_int, infoE.fields[0].field_type); 328 try testing.expectEqual(@as(comptime_int, 1), @ptrCast(*const comptime_int, infoE.fields[0].default_value.?).*); 329 try testing.expectEqualSlices(u8, "1", infoE.fields[1].name); 330 try testing.expectEqual(comptime_int, infoE.fields[1].field_type); 331 try testing.expectEqual(@as(comptime_int, 2), @ptrCast(*const comptime_int, infoE.fields[1].default_value.?).*); 332 try testing.expectEqual(@as(usize, 0), infoE.decls.len); 333 try testing.expectEqual(@as(bool, true), infoE.is_tuple); 334 335 // empty struct 336 const F = @Type(@typeInfo(struct {})); 337 const infoF = @typeInfo(F).Struct; 338 try testing.expectEqual(Type.ContainerLayout.Auto, infoF.layout); 339 try testing.expect(infoF.fields.len == 0); 340 try testing.expectEqual(@as(bool, false), infoF.is_tuple); 341 342 // empty tuple 343 const G = @Type(@typeInfo(@TypeOf(.{}))); 344 const infoG = @typeInfo(G).Struct; 345 try testing.expectEqual(Type.ContainerLayout.Auto, infoG.layout); 346 try testing.expect(infoG.fields.len == 0); 347 try testing.expectEqual(@as(bool, true), infoG.is_tuple); 348 } 349 350 test "Type.Enum" { 351 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO 352 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO 353 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO 354 355 const Foo = @Type(.{ 356 .Enum = .{ 357 .layout = .Auto, 358 .tag_type = u8, 359 .fields = &.{ 360 .{ .name = "a", .value = 1 }, 361 .{ .name = "b", .value = 5 }, 362 }, 363 .decls = &.{}, 364 .is_exhaustive = true, 365 }, 366 }); 367 try testing.expectEqual(true, @typeInfo(Foo).Enum.is_exhaustive); 368 try testing.expectEqual(@as(u8, 1), @enumToInt(Foo.a)); 369 try testing.expectEqual(@as(u8, 5), @enumToInt(Foo.b)); 370 const Bar = @Type(.{ 371 .Enum = .{ 372 // stage2 only has auto layouts 373 .layout = if (builtin.zig_backend == .stage1) 374 .Extern 375 else 376 .Auto, 377 378 .tag_type = u32, 379 .fields = &.{ 380 .{ .name = "a", .value = 1 }, 381 .{ .name = "b", .value = 5 }, 382 }, 383 .decls = &.{}, 384 .is_exhaustive = false, 385 }, 386 }); 387 try testing.expectEqual(false, @typeInfo(Bar).Enum.is_exhaustive); 388 try testing.expectEqual(@as(u32, 1), @enumToInt(Bar.a)); 389 try testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b)); 390 try testing.expectEqual(@as(u32, 6), @enumToInt(@intToEnum(Bar, 6))); 391 } 392 393 test "Type.Union" { 394 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO 395 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO 396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO 397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO 398 399 const Untagged = @Type(.{ 400 .Union = .{ 401 .layout = .Extern, 402 .tag_type = null, 403 .fields = &.{ 404 .{ .name = "int", .field_type = i32, .alignment = @alignOf(f32) }, 405 .{ .name = "float", .field_type = f32, .alignment = @alignOf(f32) }, 406 }, 407 .decls = &.{}, 408 }, 409 }); 410 var untagged = Untagged{ .int = 1 }; 411 untagged.float = 2.0; 412 untagged.int = 3; 413 try testing.expectEqual(@as(i32, 3), untagged.int); 414 415 const PackedUntagged = @Type(.{ 416 .Union = .{ 417 .layout = .Packed, 418 .tag_type = null, 419 .fields = &.{ 420 .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, 421 .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, 422 }, 423 .decls = &.{}, 424 }, 425 }); 426 var packed_untagged = PackedUntagged{ .signed = -1 }; 427 try testing.expectEqual(@as(i32, -1), packed_untagged.signed); 428 try testing.expectEqual(~@as(u32, 0), packed_untagged.unsigned); 429 430 const Tag = @Type(.{ 431 .Enum = .{ 432 .layout = .Auto, 433 .tag_type = u1, 434 .fields = &.{ 435 .{ .name = "signed", .value = 0 }, 436 .{ .name = "unsigned", .value = 1 }, 437 }, 438 .decls = &.{}, 439 .is_exhaustive = true, 440 }, 441 }); 442 const Tagged = @Type(.{ 443 .Union = .{ 444 .layout = .Auto, 445 .tag_type = Tag, 446 .fields = &.{ 447 .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, 448 .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, 449 }, 450 .decls = &.{}, 451 }, 452 }); 453 var tagged = Tagged{ .signed = -1 }; 454 try testing.expectEqual(Tag.signed, tagged); 455 tagged = .{ .unsigned = 1 }; 456 try testing.expectEqual(Tag.unsigned, tagged); 457 } 458 459 test "Type.Union from Type.Enum" { 460 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO 461 462 const Tag = @Type(.{ 463 .Enum = .{ 464 .layout = .Auto, 465 .tag_type = u0, 466 .fields = &.{ 467 .{ .name = "working_as_expected", .value = 0 }, 468 }, 469 .decls = &.{}, 470 .is_exhaustive = true, 471 }, 472 }); 473 const T = @Type(.{ 474 .Union = .{ 475 .layout = .Auto, 476 .tag_type = Tag, 477 .fields = &.{ 478 .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) }, 479 }, 480 .decls = &.{}, 481 }, 482 }); 483 _ = @typeInfo(T).Union; 484 } 485 486 test "Type.Union from regular enum" { 487 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO 488 489 const E = enum { working_as_expected }; 490 const T = @Type(.{ 491 .Union = .{ 492 .layout = .Auto, 493 .tag_type = E, 494 .fields = &.{ 495 .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) }, 496 }, 497 .decls = &.{}, 498 }, 499 }); 500 _ = @typeInfo(T).Union; 501 } 502 503 test "Type.Fn" { 504 if (builtin.zig_backend == .stage1) return error.SkipZigTest; 505 506 if (true) { 507 // https://github.com/ziglang/zig/issues/12360 508 return error.SkipZigTest; 509 } 510 511 const some_opaque = opaque {}; 512 const some_ptr = *some_opaque; 513 const T = fn (c_int, some_ptr) callconv(.C) void; 514 515 { 516 const fn_info = std.builtin.Type{ .Fn = .{ 517 .calling_convention = .C, 518 .alignment = 0, 519 .is_generic = false, 520 .is_var_args = false, 521 .return_type = void, 522 .args = &.{ 523 .{ .is_generic = false, .is_noalias = false, .arg_type = c_int }, 524 .{ .is_generic = false, .is_noalias = false, .arg_type = some_ptr }, 525 }, 526 } }; 527 528 const fn_type = @Type(fn_info); 529 try std.testing.expectEqual(T, fn_type); 530 } 531 532 { 533 const fn_info = @typeInfo(T); 534 const fn_type = @Type(fn_info); 535 try std.testing.expectEqual(T, fn_type); 536 } 537 } 538 539 test "reified struct field name from optional payload" { 540 comptime { 541 const m_name: ?[1]u8 = "a".*; 542 if (m_name) |*name| { 543 const T = @Type(.{ .Struct = .{ 544 .layout = .Auto, 545 .fields = &.{.{ 546 .name = name, 547 .field_type = u8, 548 .default_value = null, 549 .is_comptime = false, 550 .alignment = 1, 551 }}, 552 .decls = &.{}, 553 .is_tuple = false, 554 } }); 555 var t: T = .{ .a = 123 }; 556 try std.testing.expect(t.a == 123); 557 } 558 } 559 }