| 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); |
| 3 | const mem = std.mem; |
| 4 | |
| 5 | const Type = std.builtin.Type; |
| 6 | const TypeId = std.builtin.TypeId; |
| 7 | |
| 8 | const assert = std.debug.assert; |
| 9 | const expect = std.testing.expect; |
| 10 | const expectEqualStrings = std.testing.expectEqualStrings; |
| 11 | |
| 12 | test "type info: integer, floating point type info" { |
| 13 | try testIntFloat(); |
| 14 | try comptime testIntFloat(); |
| 15 | } |
| 16 | |
| 17 | fn testIntFloat() !void { |
| 18 | const u8_info = @typeInfo(u8); |
| 19 | try expect(u8_info == .int); |
| 20 | try expect(u8_info.int.signedness == .unsigned); |
| 21 | try expect(u8_info.int.bits == 8); |
| 22 | |
| 23 | const f64_info = @typeInfo(f64); |
| 24 | try expect(f64_info == .float); |
| 25 | try expect(f64_info.float.bits == 64); |
| 26 | } |
| 27 | |
| 28 | test "type info: optional type info" { |
| 29 | try testOptional(); |
| 30 | try comptime testOptional(); |
| 31 | } |
| 32 | |
| 33 | fn testOptional() !void { |
| 34 | const null_info = @typeInfo(?void); |
| 35 | try expect(null_info == .optional); |
| 36 | try expect(null_info.optional.child == void); |
| 37 | } |
| 38 | |
| 39 | test "type info: C pointer type info" { |
| 40 | try testCPtr(); |
| 41 | try comptime testCPtr(); |
| 42 | } |
| 43 | |
| 44 | fn testCPtr() !void { |
| 45 | const ptr_info = @typeInfo([*c]align(4) const i8); |
| 46 | try expect(ptr_info == .pointer); |
| 47 | try expect(ptr_info.pointer.size == .c); |
| 48 | try expect(ptr_info.pointer.attrs.@"const"); |
| 49 | try expect(!ptr_info.pointer.attrs.@"volatile"); |
| 50 | try expect(ptr_info.pointer.attrs.@"align" == 4); |
| 51 | try expect(ptr_info.pointer.child == i8); |
| 52 | } |
| 53 | |
| 54 | test "type info: value is correctly copied" { |
| 55 | comptime { |
| 56 | var ptrInfo = @typeInfo([]u32); |
| 57 | ptrInfo.pointer.size = .one; |
| 58 | try expect(@typeInfo([]u32).pointer.size == .slice); |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | test "type info: tag type, void info" { |
| 63 | try testBasic(); |
| 64 | try comptime testBasic(); |
| 65 | } |
| 66 | |
| 67 | fn testBasic() !void { |
| 68 | try expect(@typeInfo(Type).@"union".tag_type == TypeId); |
| 69 | const void_info = @typeInfo(void); |
| 70 | try expect(void_info == TypeId.void); |
| 71 | try expect(void_info.void == {}); |
| 72 | } |
| 73 | |
| 74 | test "type info: pointer type info" { |
| 75 | try testPointer(); |
| 76 | try comptime testPointer(); |
| 77 | } |
| 78 | |
| 79 | fn testPointer() !void { |
| 80 | const u32_ptr_info = @typeInfo(*u32); |
| 81 | try expect(u32_ptr_info == .pointer); |
| 82 | try expect(u32_ptr_info.pointer.size == .one); |
| 83 | try expect(u32_ptr_info.pointer.attrs.@"const" == false); |
| 84 | try expect(u32_ptr_info.pointer.attrs.@"volatile" == false); |
| 85 | try expect(u32_ptr_info.pointer.attrs.@"align" == null); |
| 86 | try expect(u32_ptr_info.pointer.child == u32); |
| 87 | try expect(u32_ptr_info.pointer.sentinel() == null); |
| 88 | } |
| 89 | |
| 90 | test "type info: unknown length pointer type info" { |
| 91 | try testUnknownLenPtr(); |
| 92 | try comptime testUnknownLenPtr(); |
| 93 | } |
| 94 | |
| 95 | fn testUnknownLenPtr() !void { |
| 96 | const u32_ptr_info = @typeInfo([*]const volatile f64); |
| 97 | try expect(u32_ptr_info == .pointer); |
| 98 | try expect(u32_ptr_info.pointer.size == .many); |
| 99 | try expect(u32_ptr_info.pointer.attrs.@"const" == true); |
| 100 | try expect(u32_ptr_info.pointer.attrs.@"volatile" == true); |
| 101 | try expect(u32_ptr_info.pointer.attrs.@"align" == null); |
| 102 | try expect(u32_ptr_info.pointer.child == f64); |
| 103 | try expect(u32_ptr_info.pointer.sentinel() == null); |
| 104 | } |
| 105 | |
| 106 | test "type info: null terminated pointer type info" { |
| 107 | try testNullTerminatedPtr(); |
| 108 | try comptime testNullTerminatedPtr(); |
| 109 | } |
| 110 | |
| 111 | fn testNullTerminatedPtr() !void { |
| 112 | const ptr_info = @typeInfo([*:0]u8); |
| 113 | try expect(ptr_info == .pointer); |
| 114 | try expect(ptr_info.pointer.size == .many); |
| 115 | try expect(ptr_info.pointer.attrs.@"const" == false); |
| 116 | try expect(ptr_info.pointer.attrs.@"volatile" == false); |
| 117 | try expect(ptr_info.pointer.sentinel().? == 0); |
| 118 | |
| 119 | try expect(@typeInfo([:0]u8).pointer.sentinel() != null); |
| 120 | } |
| 121 | |
| 122 | test "type info: slice type info" { |
| 123 | try testSlice(); |
| 124 | try comptime testSlice(); |
| 125 | } |
| 126 | |
| 127 | fn testSlice() !void { |
| 128 | const u32_slice_info = @typeInfo([]u32); |
| 129 | try expect(u32_slice_info == .pointer); |
| 130 | try expect(u32_slice_info.pointer.size == .slice); |
| 131 | try expect(u32_slice_info.pointer.attrs.@"const" == false); |
| 132 | try expect(u32_slice_info.pointer.attrs.@"volatile" == false); |
| 133 | try expect(u32_slice_info.pointer.attrs.@"align" == null); |
| 134 | try expect(u32_slice_info.pointer.child == u32); |
| 135 | } |
| 136 | |
| 137 | test "type info: array type info" { |
| 138 | try testArray(); |
| 139 | try comptime testArray(); |
| 140 | } |
| 141 | |
| 142 | fn testArray() !void { |
| 143 | { |
| 144 | const info = @typeInfo([42]u8); |
| 145 | try expect(info == .array); |
| 146 | try expect(info.array.len == 42); |
| 147 | try expect(info.array.child == u8); |
| 148 | try expect(info.array.sentinel() == null); |
| 149 | } |
| 150 | |
| 151 | { |
| 152 | const info = @typeInfo([10:0]u8); |
| 153 | try expect(info.array.len == 10); |
| 154 | try expect(info.array.child == u8); |
| 155 | try expect(info.array.sentinel().? == @as(u8, 0)); |
| 156 | try expect(@sizeOf([10:0]u8) == info.array.len + 1); |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | test "type info: error set, error union info, anyerror" { |
| 161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 163 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 164 | |
| 165 | try testErrorSet(); |
| 166 | try comptime testErrorSet(); |
| 167 | } |
| 168 | |
| 169 | fn testErrorSet() !void { |
| 170 | const TestErrorSet = error{ |
| 171 | First, |
| 172 | Second, |
| 173 | Third, |
| 174 | }; |
| 175 | |
| 176 | const error_set_info = @typeInfo(TestErrorSet); |
| 177 | try expect(error_set_info == .error_set); |
| 178 | try expect(error_set_info.error_set.error_names.?.len == 3); |
| 179 | try expect(mem.eql(u8, error_set_info.error_set.error_names.?[0], "First")); |
| 180 | |
| 181 | const error_union_info = @typeInfo(TestErrorSet!usize); |
| 182 | try expect(error_union_info == .error_union); |
| 183 | try expect(error_union_info.error_union.error_set == TestErrorSet); |
| 184 | try expect(error_union_info.error_union.payload == usize); |
| 185 | |
| 186 | const global_info = @typeInfo(anyerror); |
| 187 | try expect(global_info == .error_set); |
| 188 | try expect(global_info.error_set.error_names == null); |
| 189 | } |
| 190 | |
| 191 | test "type info: error set single value" { |
| 192 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 193 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 194 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 195 | |
| 196 | const TestSet = error.One; |
| 197 | |
| 198 | const error_set_info = @typeInfo(@TypeOf(TestSet)); |
| 199 | try expect(error_set_info == .error_set); |
| 200 | try expect(error_set_info.error_set.error_names.?.len == 1); |
| 201 | try expect(mem.eql(u8, error_set_info.error_set.error_names.?[0], "One")); |
| 202 | } |
| 203 | |
| 204 | test "type info: error set merged" { |
| 205 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 206 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 207 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 208 | |
| 209 | const TestSet = error{ One, Two } || error{Three}; |
| 210 | |
| 211 | const error_set_info = @typeInfo(TestSet); |
| 212 | try expect(error_set_info == .error_set); |
| 213 | try expect(error_set_info.error_set.error_names.?.len == 3); |
| 214 | try expect(mem.eql(u8, error_set_info.error_set.error_names.?[0], "One")); |
| 215 | try expect(mem.eql(u8, error_set_info.error_set.error_names.?[1], "Two")); |
| 216 | try expect(mem.eql(u8, error_set_info.error_set.error_names.?[2], "Three")); |
| 217 | } |
| 218 | |
| 219 | test "type info: enum info" { |
| 220 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 221 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 222 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 223 | |
| 224 | try testEnum(); |
| 225 | try comptime testEnum(); |
| 226 | } |
| 227 | |
| 228 | fn testEnum() !void { |
| 229 | const Os = enum { |
| 230 | Windows, |
| 231 | Macos, |
| 232 | Linux, |
| 233 | FreeBSD, |
| 234 | }; |
| 235 | |
| 236 | const os_info = @typeInfo(Os); |
| 237 | try expect(os_info == .@"enum"); |
| 238 | try expect(os_info.@"enum".field_names.len == 4); |
| 239 | try expect(os_info.@"enum".field_values.len == os_info.@"enum".field_names.len); |
| 240 | try expect(mem.eql(u8, os_info.@"enum".field_names[1], "Macos")); |
| 241 | try expect(os_info.@"enum".field_values[3] == 3); |
| 242 | try expect(os_info.@"enum".tag_type == u2); |
| 243 | try expect(os_info.@"enum".decl_names.len == 0); |
| 244 | } |
| 245 | |
| 246 | test "type info: union info" { |
| 247 | try testUnion(); |
| 248 | try comptime testUnion(); |
| 249 | } |
| 250 | |
| 251 | fn testUnion() !void { |
| 252 | const typeinfo_info = @typeInfo(Type); |
| 253 | try expect(typeinfo_info == .@"union"); |
| 254 | try expect(typeinfo_info.@"union".layout == .auto); |
| 255 | try expect(typeinfo_info.@"union".tag_type.? == TypeId); |
| 256 | try expect(typeinfo_info.@"union".field_names.len == 25); |
| 257 | try expect(typeinfo_info.@"union".field_names.len == typeinfo_info.@"union".field_types.len); |
| 258 | try expect(typeinfo_info.@"union".field_names.len == typeinfo_info.@"union".field_attrs.len); |
| 259 | try expect(typeinfo_info.@"union".field_types[4] == @TypeOf(@typeInfo(u8).int)); |
| 260 | try expect(typeinfo_info.@"union".decl_names.len == 17); |
| 261 | |
| 262 | const TestNoTagUnion = union { |
| 263 | Foo: void, |
| 264 | Bar: u32, |
| 265 | }; |
| 266 | |
| 267 | const notag_union_info = @typeInfo(TestNoTagUnion); |
| 268 | try expect(notag_union_info == .@"union"); |
| 269 | try expect(notag_union_info.@"union".tag_type == null); |
| 270 | try expect(notag_union_info.@"union".layout == .auto); |
| 271 | try expect(notag_union_info.@"union".field_names.len == 2); |
| 272 | try expect(notag_union_info.@"union".field_names.len == notag_union_info.@"union".field_types.len); |
| 273 | try expect(notag_union_info.@"union".field_names.len == notag_union_info.@"union".field_attrs.len); |
| 274 | try expect(notag_union_info.@"union".field_attrs[0].@"align" == null); |
| 275 | try expect(notag_union_info.@"union".field_types[1] == u32); |
| 276 | try expect(notag_union_info.@"union".field_attrs[1].@"align" == null); |
| 277 | |
| 278 | const TestExternUnion = extern union { |
| 279 | foo: *anyopaque, |
| 280 | }; |
| 281 | |
| 282 | const extern_union_info = @typeInfo(TestExternUnion); |
| 283 | try expect(extern_union_info.@"union".layout == .@"extern"); |
| 284 | try expect(extern_union_info.@"union".tag_type == null); |
| 285 | try expect(extern_union_info.@"union".field_types[0] == *anyopaque); |
| 286 | } |
| 287 | |
| 288 | test "type info: struct info" { |
| 289 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 290 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 291 | |
| 292 | try testStruct(); |
| 293 | try comptime testStruct(); |
| 294 | } |
| 295 | |
| 296 | fn testStruct() !void { |
| 297 | const unpacked_struct_info = @typeInfo(TestStruct); |
| 298 | try expect(unpacked_struct_info.@"struct".is_tuple == false); |
| 299 | try expect(unpacked_struct_info.@"struct".backing_integer == null); |
| 300 | try expect(unpacked_struct_info.@"struct".field_attrs[0].@"align" == null); |
| 301 | const field_0_type = unpacked_struct_info.@"struct".field_types[0]; |
| 302 | try expect(unpacked_struct_info.@"struct".field_attrs[0].defaultValue(field_0_type).? == 4); |
| 303 | const field_1_type = unpacked_struct_info.@"struct".field_types[1]; |
| 304 | try expect(mem.eql(u8, "foobar", unpacked_struct_info.@"struct".field_attrs[1].defaultValue(field_1_type).?)); |
| 305 | } |
| 306 | |
| 307 | const TestStruct = struct { |
| 308 | fieldA: u32 = 4, |
| 309 | fieldB: *const [6:0]u8 = "foobar", |
| 310 | }; |
| 311 | |
| 312 | test "type info: packed struct info" { |
| 313 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 314 | |
| 315 | try testPackedStruct(); |
| 316 | try comptime testPackedStruct(); |
| 317 | } |
| 318 | |
| 319 | fn testPackedStruct() !void { |
| 320 | const struct_info = @typeInfo(TestPackedStruct); |
| 321 | try expect(struct_info == .@"struct"); |
| 322 | try expect(struct_info.@"struct".is_tuple == false); |
| 323 | try expect(struct_info.@"struct".layout == .@"packed"); |
| 324 | try expect(struct_info.@"struct".backing_integer == u128); |
| 325 | try expect(struct_info.@"struct".field_names.len == 4); |
| 326 | try expect(struct_info.@"struct".field_names.len == struct_info.@"struct".field_types.len); |
| 327 | try expect(struct_info.@"struct".field_names.len == struct_info.@"struct".field_attrs.len); |
| 328 | try expect(struct_info.@"struct".field_attrs[0].@"align" == null); |
| 329 | try expect(struct_info.@"struct".field_types[2] == f32); |
| 330 | const field_2_type = struct_info.@"struct".field_types[2]; |
| 331 | try expect(struct_info.@"struct".field_attrs[2].defaultValue(field_2_type) == null); |
| 332 | const field_3_type = struct_info.@"struct".field_types[3]; |
| 333 | try expect(struct_info.@"struct".field_attrs[3].defaultValue(field_3_type).? == 4); |
| 334 | try expect(struct_info.@"struct".field_attrs[3].@"align" == null); |
| 335 | try expect(struct_info.@"struct".decl_names.len == 1); |
| 336 | } |
| 337 | |
| 338 | const TestPackedStruct = packed struct { |
| 339 | fieldA: u64, |
| 340 | fieldB: void, |
| 341 | fieldC: f32, |
| 342 | fieldD: u32 = 4, |
| 343 | |
| 344 | pub fn foo(self: *const Self) void { |
| 345 | _ = self; |
| 346 | } |
| 347 | const Self = @This(); |
| 348 | }; |
| 349 | |
| 350 | test "type info: opaque info" { |
| 351 | try testOpaque(); |
| 352 | try comptime testOpaque(); |
| 353 | } |
| 354 | |
| 355 | fn testOpaque() !void { |
| 356 | const Foo = opaque { |
| 357 | pub const A = 1; |
| 358 | pub fn b() void {} |
| 359 | }; |
| 360 | |
| 361 | const foo_info = @typeInfo(Foo); |
| 362 | try expect(foo_info.@"opaque".decl_names.len == 2); |
| 363 | } |
| 364 | |
| 365 | test "type info: function type info" { |
| 366 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 367 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 368 | |
| 369 | try testFunction(); |
| 370 | try comptime testFunction(); |
| 371 | } |
| 372 | |
| 373 | fn testFunction() !void { |
| 374 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 375 | |
| 376 | const S = struct { |
| 377 | export fn typeInfoFoo() callconv(.c) usize { |
| 378 | unreachable; |
| 379 | } |
| 380 | export fn typeInfoFooAligned() callconv(.c) usize { |
| 381 | unreachable; |
| 382 | } |
| 383 | }; |
| 384 | _ = S; |
| 385 | const foo_fn_type = @TypeOf(typeInfoFoo); |
| 386 | const foo_fn_info = @typeInfo(foo_fn_type); |
| 387 | try expect(foo_fn_info.@"fn".attrs.@"callconv".eql(.c)); |
| 388 | try expect(!foo_fn_info.@"fn".is_generic); |
| 389 | try expect(foo_fn_info.@"fn".param_types.len == 2); |
| 390 | try expect(foo_fn_info.@"fn".attrs.varargs); |
| 391 | try expect(foo_fn_info.@"fn".return_type.? == usize); |
| 392 | const foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFoo)); |
| 393 | try expect(foo_ptr_fn_info.pointer.size == .one); |
| 394 | try expect(foo_ptr_fn_info.pointer.attrs.@"const"); |
| 395 | try expect(!foo_ptr_fn_info.pointer.attrs.@"volatile"); |
| 396 | try expect(foo_ptr_fn_info.pointer.attrs.@"addrspace" == .generic); |
| 397 | try expect(foo_ptr_fn_info.pointer.child == foo_fn_type); |
| 398 | try expect(!foo_ptr_fn_info.pointer.attrs.@"allowzero"); |
| 399 | try expect(foo_ptr_fn_info.pointer.sentinel() == null); |
| 400 | |
| 401 | // Avoid looking at `typeInfoFooAligned` on targets which don't support function alignment. |
| 402 | switch (builtin.target.cpu.arch) { |
| 403 | .spirv32, |
| 404 | .spirv64, |
| 405 | .wasm32, |
| 406 | .wasm64, |
| 407 | => return, |
| 408 | else => {}, |
| 409 | } |
| 410 | |
| 411 | const aligned_foo_fn_type = @TypeOf(typeInfoFooAligned); |
| 412 | const aligned_foo_fn_info = @typeInfo(aligned_foo_fn_type); |
| 413 | try expect(aligned_foo_fn_info.@"fn".attrs.@"callconv".eql(.c)); |
| 414 | try expect(!aligned_foo_fn_info.@"fn".is_generic); |
| 415 | try expect(aligned_foo_fn_info.@"fn".param_types.len == 2); |
| 416 | try expect(aligned_foo_fn_info.@"fn".param_types.len == aligned_foo_fn_info.@"fn".param_attrs.len); |
| 417 | try expect(aligned_foo_fn_info.@"fn".attrs.varargs); |
| 418 | try expect(aligned_foo_fn_info.@"fn".return_type.? == usize); |
| 419 | const aligned_foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFooAligned)); |
| 420 | try expect(aligned_foo_ptr_fn_info.pointer.size == .one); |
| 421 | try expect(aligned_foo_ptr_fn_info.pointer.attrs.@"const"); |
| 422 | try expect(!aligned_foo_ptr_fn_info.pointer.attrs.@"volatile"); |
| 423 | try expect(aligned_foo_ptr_fn_info.pointer.attrs.@"align" == 4); |
| 424 | try expect(aligned_foo_ptr_fn_info.pointer.attrs.@"addrspace" == .generic); |
| 425 | try expect(aligned_foo_ptr_fn_info.pointer.child == aligned_foo_fn_type); |
| 426 | try expect(!aligned_foo_ptr_fn_info.pointer.attrs.@"allowzero"); |
| 427 | try expect(aligned_foo_ptr_fn_info.pointer.sentinel() == null); |
| 428 | } |
| 429 | |
| 430 | extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.c) usize; |
| 431 | extern fn typeInfoFooAligned(a: usize, b: bool, ...) align(4) callconv(.c) usize; |
| 432 | |
| 433 | test "type info: generic function types" { |
| 434 | const G1 = @typeInfo(@TypeOf(generic1)); |
| 435 | try expect(G1.@"fn".param_types.len == 1); |
| 436 | try expect(G1.@"fn".param_types.len == G1.@"fn".param_attrs.len); |
| 437 | try expect(G1.@"fn".param_types[0] == null); |
| 438 | try expect(G1.@"fn".return_type == void); |
| 439 | |
| 440 | const G2 = @typeInfo(@TypeOf(generic2)); |
| 441 | try expect(G2.@"fn".param_types.len == 3); |
| 442 | try expect(G2.@"fn".param_types.len == G2.@"fn".param_attrs.len); |
| 443 | try expect(G2.@"fn".param_types[0] == type); |
| 444 | try expect(G2.@"fn".param_types[1] == null); |
| 445 | try expect(G2.@"fn".param_types[2] == u8); |
| 446 | try expect(G2.@"fn".return_type == void); |
| 447 | |
| 448 | const G3 = @typeInfo(@TypeOf(generic3)); |
| 449 | try expect(G3.@"fn".param_types.len == 1); |
| 450 | try expect(G3.@"fn".param_types.len == G3.@"fn".param_attrs.len); |
| 451 | try expect(G3.@"fn".param_types[0] == null); |
| 452 | try expect(G3.@"fn".return_type == null); |
| 453 | |
| 454 | const G4 = @typeInfo(@TypeOf(generic4)); |
| 455 | try expect(G4.@"fn".param_types.len == 1); |
| 456 | try expect(G4.@"fn".param_types.len == G4.@"fn".param_attrs.len); |
| 457 | try expect(G4.@"fn".param_types[0] == null); |
| 458 | try expect(G4.@"fn".return_type == null); |
| 459 | } |
| 460 | |
| 461 | fn generic1(param: anytype) void { |
| 462 | _ = param; |
| 463 | } |
| 464 | fn generic2(comptime T: type, param: T, param2: u8) void { |
| 465 | _ = param; |
| 466 | _ = param2; |
| 467 | } |
| 468 | fn generic3(param: anytype) @TypeOf(param) {} |
| 469 | fn generic4(comptime param: anytype) @TypeOf(param) {} |
| 470 | |
| 471 | test "typeInfo with comptime parameter in struct fn def" { |
| 472 | const S = struct { |
| 473 | pub fn func(comptime x: f32) void { |
| 474 | _ = x; |
| 475 | } |
| 476 | }; |
| 477 | comptime var info = @typeInfo(S); |
| 478 | _ = &info; |
| 479 | } |
| 480 | |
| 481 | test "type info: vectors" { |
| 482 | try testVector(); |
| 483 | try comptime testVector(); |
| 484 | } |
| 485 | |
| 486 | fn testVector() !void { |
| 487 | const vec_info = @typeInfo(@Vector(4, i32)); |
| 488 | try expect(vec_info == .vector); |
| 489 | try expect(vec_info.vector.len == 4); |
| 490 | try expect(vec_info.vector.child == i32); |
| 491 | } |
| 492 | |
| 493 | test "type info: anyframe and anyframe->T" { |
| 494 | if (true) { |
| 495 | // https://github.com/ziglang/zig/issues/6025 |
| 496 | return error.SkipZigTest; |
| 497 | } |
| 498 | |
| 499 | try testAnyFrame(); |
| 500 | try comptime testAnyFrame(); |
| 501 | } |
| 502 | |
| 503 | fn testAnyFrame() !void { |
| 504 | { |
| 505 | const anyframe_info = @typeInfo(anyframe->i32); |
| 506 | try expect(anyframe_info == .@"anyframe"); |
| 507 | try expect(anyframe_info.@"anyframe".child.? == i32); |
| 508 | } |
| 509 | |
| 510 | { |
| 511 | const anyframe_info = @typeInfo(anyframe); |
| 512 | try expect(anyframe_info == .@"anyframe"); |
| 513 | try expect(anyframe_info.@"anyframe".child == null); |
| 514 | } |
| 515 | } |
| 516 | |
| 517 | test "type info: pass to function" { |
| 518 | _ = passTypeInfo(@typeInfo(void)); |
| 519 | _ = comptime passTypeInfo(@typeInfo(void)); |
| 520 | } |
| 521 | |
| 522 | fn passTypeInfo(comptime info: Type) type { |
| 523 | _ = info; |
| 524 | return void; |
| 525 | } |
| 526 | |
| 527 | test "type info: TypeId -> Type impl cast" { |
| 528 | _ = passTypeInfo(TypeId.void); |
| 529 | _ = comptime passTypeInfo(TypeId.void); |
| 530 | } |
| 531 | |
| 532 | test "sentinel of opaque pointer type" { |
| 533 | const c_void_info = @typeInfo(*anyopaque); |
| 534 | try expect(c_void_info.pointer.sentinel_ptr == null); |
| 535 | } |
| 536 | |
| 537 | test "@typeInfo does not force declarations into existence" { |
| 538 | const S = struct { |
| 539 | x: i32, |
| 540 | |
| 541 | fn doNotReferenceMe() void { |
| 542 | @compileError("test failed"); |
| 543 | } |
| 544 | }; |
| 545 | comptime assert(@typeInfo(S).@"struct".field_names.len == 1); |
| 546 | } |
| 547 | |
| 548 | fn add(a: i32, b: i32) i32 { |
| 549 | return a + b; |
| 550 | } |
| 551 | |
| 552 | test "Declarations are returned in declaration order" { |
| 553 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 554 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 555 | |
| 556 | const S = struct { |
| 557 | pub const a = 1; |
| 558 | pub const b = 2; |
| 559 | pub const c = 3; |
| 560 | pub const d = 4; |
| 561 | pub const e = 5; |
| 562 | }; |
| 563 | const d = @typeInfo(S).@"struct".decl_names; |
| 564 | try expect(std.mem.eql(u8, d[0], "a")); |
| 565 | try expect(std.mem.eql(u8, d[1], "b")); |
| 566 | try expect(std.mem.eql(u8, d[2], "c")); |
| 567 | try expect(std.mem.eql(u8, d[3], "d")); |
| 568 | try expect(std.mem.eql(u8, d[4], "e")); |
| 569 | } |
| 570 | |
| 571 | test "Struct.is_tuple for anon list literal" { |
| 572 | try expect(@typeInfo(@TypeOf(.{0})).@"struct".is_tuple); |
| 573 | } |
| 574 | |
| 575 | test "Struct.is_tuple for anon struct literal" { |
| 576 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 577 | |
| 578 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 579 | |
| 580 | const info = @typeInfo(@TypeOf(.{ .a = 0 })); |
| 581 | try expect(!info.@"struct".is_tuple); |
| 582 | try expect(std.mem.eql(u8, info.@"struct".field_names[0], "a")); |
| 583 | } |
| 584 | |
| 585 | test "StructField.is_comptime" { |
| 586 | const info = @typeInfo(struct { x: u8 = 3, comptime y: u32 = 5 }).@"struct"; |
| 587 | try expect(!info.field_attrs[0].@"comptime"); |
| 588 | try expect(info.field_attrs[1].@"comptime"); |
| 589 | } |
| 590 | |
| 591 | test "value from struct @typeInfo default_value_ptr can be loaded at comptime" { |
| 592 | comptime { |
| 593 | const a = @typeInfo(@TypeOf(.{ .foo = @as(u8, 1) })).@"struct".field_attrs[0].default_value_ptr; |
| 594 | try expect(@as(*const u8, @ptrCast(a)).* == 1); |
| 595 | } |
| 596 | } |
| 597 | |
| 598 | test "type info of tuple of string literal default value" { |
| 599 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 600 | |
| 601 | const struct_info = @typeInfo(@TypeOf(.{"hi"})).@"struct"; |
| 602 | const struct_field_attrs = struct_info.field_attrs[0]; |
| 603 | const struct_field_type = struct_info.field_types[0]; |
| 604 | const value = struct_field_attrs.defaultValue(struct_field_type).?; |
| 605 | comptime std.debug.assert(value[0] == 'h'); |
| 606 | } |
| 607 | |
| 608 | test "@typeInfo function with generic return type and inferred error set" { |
| 609 | const S = struct { |
| 610 | fn testFn(comptime T: type) !T {} |
| 611 | }; |
| 612 | |
| 613 | const ret_ty = @typeInfo(@TypeOf(S.testFn)).@"fn".return_type; |
| 614 | comptime assert(ret_ty == null); |
| 615 | } |
| 616 | |
| 617 | test "type info: spirv info" { |
| 618 | if (builtin.zig_backend != .stage2_spirv) return error.SkipZigTest; |
| 619 | |
| 620 | try testSpirv(); |
| 621 | try comptime testSpirv(); |
| 622 | } |
| 623 | |
| 624 | fn testSpirv() !void { |
| 625 | const image_info = @typeInfo(Image); |
| 626 | try expect(image_info.spirv.image.usage.sampled == f32); |
| 627 | try expect(image_info.spirv.image.format == .unknown); |
| 628 | try expect(image_info.spirv.image.dim == .@"2d"); |
| 629 | try expect(image_info.spirv.image.depth == .not_depth); |
| 630 | try expect(image_info.spirv.image.arrayed == false); |
| 631 | try expect(image_info.spirv.image.multisampled == false); |
| 632 | try expect(image_info.spirv.image.access == .unknown); |
| 633 | |
| 634 | const sampled_image_info = @typeInfo(SampledImage); |
| 635 | try expect(sampled_image_info.spirv.sampled_image == Image); |
| 636 | |
| 637 | const sampler_info = @typeInfo(Sampler); |
| 638 | try expect(sampler_info.spirv.sampler == {}); |
| 639 | |
| 640 | const runtime_array_info = @typeInfo(RuntimeArray); |
| 641 | try expect(runtime_array_info.spirv.runtime_array == f32); |
| 642 | } |
| 643 | |
| 644 | pub const Image = @SpirvType(.{ .image = .{ |
| 645 | .usage = .{ .sampled = f32 }, |
| 646 | .format = .unknown, |
| 647 | .dim = .@"2d", |
| 648 | .depth = .not_depth, |
| 649 | .arrayed = false, |
| 650 | .multisampled = false, |
| 651 | .access = .unknown, |
| 652 | } }); |
| 653 | pub const SampledImage = @SpirvType(.{ .sampled_image = Image }); |
| 654 | pub const Sampler = @SpirvType(.sampler); |
| 655 | pub const RuntimeArray = @SpirvType(.{ .runtime_array = f32 }); |