master
1const std = @import("std");
2const builtin = @import("builtin");
3const mem = std.mem;
4
5const Type = std.builtin.Type;
6const TypeId = std.builtin.TypeId;
7
8const assert = std.debug.assert;
9const expect = std.testing.expect;
10const expectEqualStrings = std.testing.expectEqualStrings;
11
12test "type info: integer, floating point type info" {
13 try testIntFloat();
14 try comptime testIntFloat();
15}
16
17fn 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
28test "type info: optional type info" {
29 try testOptional();
30 try comptime testOptional();
31}
32
33fn testOptional() !void {
34 const null_info = @typeInfo(?void);
35 try expect(null_info == .optional);
36 try expect(null_info.optional.child == void);
37}
38
39test "type info: C pointer type info" {
40 try testCPtr();
41 try comptime testCPtr();
42}
43
44fn 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.is_const);
49 try expect(!ptr_info.pointer.is_volatile);
50 try expect(ptr_info.pointer.alignment == 4);
51 try expect(ptr_info.pointer.child == i8);
52}
53
54test "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
62test "type info: tag type, void info" {
63 try testBasic();
64 try comptime testBasic();
65}
66
67fn 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
74test "type info: pointer type info" {
75 try testPointer();
76 try comptime testPointer();
77}
78
79fn 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.is_const == false);
84 try expect(u32_ptr_info.pointer.is_volatile == false);
85 try expect(u32_ptr_info.pointer.alignment == @alignOf(u32));
86 try expect(u32_ptr_info.pointer.child == u32);
87 try expect(u32_ptr_info.pointer.sentinel() == null);
88}
89
90test "type info: unknown length pointer type info" {
91 try testUnknownLenPtr();
92 try comptime testUnknownLenPtr();
93}
94
95fn 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.is_const == true);
100 try expect(u32_ptr_info.pointer.is_volatile == true);
101 try expect(u32_ptr_info.pointer.sentinel() == null);
102 try expect(u32_ptr_info.pointer.alignment == @alignOf(f64));
103 try expect(u32_ptr_info.pointer.child == f64);
104}
105
106test "type info: null terminated pointer type info" {
107 try testNullTerminatedPtr();
108 try comptime testNullTerminatedPtr();
109}
110
111fn 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.is_const == false);
116 try expect(ptr_info.pointer.is_volatile == false);
117 try expect(ptr_info.pointer.sentinel().? == 0);
118
119 try expect(@typeInfo([:0]u8).pointer.sentinel() != null);
120}
121
122test "type info: slice type info" {
123 try testSlice();
124 try comptime testSlice();
125}
126
127fn 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.is_const == false);
132 try expect(u32_slice_info.pointer.is_volatile == false);
133 try expect(u32_slice_info.pointer.alignment == 4);
134 try expect(u32_slice_info.pointer.child == u32);
135}
136
137test "type info: array type info" {
138 try testArray();
139 try comptime testArray();
140}
141
142fn 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
160test "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
169fn 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.?.len == 3);
179 try expect(mem.eql(u8, error_set_info.error_set.?[0].name, "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 == null);
189}
190
191test "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.?.len == 1);
201 try expect(mem.eql(u8, error_set_info.error_set.?[0].name, "One"));
202}
203
204test "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.?.len == 3);
214 try expect(mem.eql(u8, error_set_info.error_set.?[0].name, "One"));
215 try expect(mem.eql(u8, error_set_info.error_set.?[1].name, "Two"));
216 try expect(mem.eql(u8, error_set_info.error_set.?[2].name, "Three"));
217}
218
219test "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
228fn 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".fields.len == 4);
239 try expect(mem.eql(u8, os_info.@"enum".fields[1].name, "Macos"));
240 try expect(os_info.@"enum".fields[3].value == 3);
241 try expect(os_info.@"enum".tag_type == u2);
242 try expect(os_info.@"enum".decls.len == 0);
243}
244
245test "type info: union info" {
246 try testUnion();
247 try comptime testUnion();
248}
249
250fn testUnion() !void {
251 const typeinfo_info = @typeInfo(Type);
252 try expect(typeinfo_info == .@"union");
253 try expect(typeinfo_info.@"union".layout == .auto);
254 try expect(typeinfo_info.@"union".tag_type.? == TypeId);
255 try expect(typeinfo_info.@"union".fields.len == 24);
256 try expect(typeinfo_info.@"union".fields[4].type == @TypeOf(@typeInfo(u8).int));
257 try expect(typeinfo_info.@"union".decls.len == 21);
258
259 const TestNoTagUnion = union {
260 Foo: void,
261 Bar: u32,
262 };
263
264 const notag_union_info = @typeInfo(TestNoTagUnion);
265 try expect(notag_union_info == .@"union");
266 try expect(notag_union_info.@"union".tag_type == null);
267 try expect(notag_union_info.@"union".layout == .auto);
268 try expect(notag_union_info.@"union".fields.len == 2);
269 try expect(notag_union_info.@"union".fields[0].alignment == @alignOf(void));
270 try expect(notag_union_info.@"union".fields[1].type == u32);
271 try expect(notag_union_info.@"union".fields[1].alignment == @alignOf(u32));
272
273 const TestExternUnion = extern union {
274 foo: *anyopaque,
275 };
276
277 const extern_union_info = @typeInfo(TestExternUnion);
278 try expect(extern_union_info.@"union".layout == .@"extern");
279 try expect(extern_union_info.@"union".tag_type == null);
280 try expect(extern_union_info.@"union".fields[0].type == *anyopaque);
281}
282
283test "type info: struct info" {
284 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
286
287 try testStruct();
288 try comptime testStruct();
289}
290
291fn testStruct() !void {
292 const unpacked_struct_info = @typeInfo(TestStruct);
293 try expect(unpacked_struct_info.@"struct".is_tuple == false);
294 try expect(unpacked_struct_info.@"struct".backing_integer == null);
295 try expect(unpacked_struct_info.@"struct".fields[0].alignment == @alignOf(u32));
296 try expect(unpacked_struct_info.@"struct".fields[0].defaultValue().? == 4);
297 try expect(mem.eql(u8, "foobar", unpacked_struct_info.@"struct".fields[1].defaultValue().?));
298}
299
300const TestStruct = struct {
301 fieldA: u32 = 4,
302 fieldB: *const [6:0]u8 = "foobar",
303};
304
305test "type info: packed struct info" {
306 try testPackedStruct();
307 try comptime testPackedStruct();
308}
309
310fn testPackedStruct() !void {
311 const struct_info = @typeInfo(TestPackedStruct);
312 try expect(struct_info == .@"struct");
313 try expect(struct_info.@"struct".is_tuple == false);
314 try expect(struct_info.@"struct".layout == .@"packed");
315 try expect(struct_info.@"struct".backing_integer == u128);
316 try expect(struct_info.@"struct".fields.len == 4);
317 try expect(struct_info.@"struct".fields[0].alignment == 0);
318 try expect(struct_info.@"struct".fields[2].type == f32);
319 try expect(struct_info.@"struct".fields[2].defaultValue() == null);
320 try expect(struct_info.@"struct".fields[3].defaultValue().? == 4);
321 try expect(struct_info.@"struct".fields[3].alignment == 0);
322 try expect(struct_info.@"struct".decls.len == 1);
323}
324
325const TestPackedStruct = packed struct {
326 fieldA: u64,
327 fieldB: void,
328 fieldC: f32,
329 fieldD: u32 = 4,
330
331 pub fn foo(self: *const Self) void {
332 _ = self;
333 }
334 const Self = @This();
335};
336
337test "type info: opaque info" {
338 try testOpaque();
339 try comptime testOpaque();
340}
341
342fn testOpaque() !void {
343 const Foo = opaque {
344 pub const A = 1;
345 pub fn b() void {}
346 };
347
348 const foo_info = @typeInfo(Foo);
349 try expect(foo_info.@"opaque".decls.len == 2);
350}
351
352test "type info: function type info" {
353 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
354 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
355
356 try testFunction();
357 try comptime testFunction();
358}
359
360fn testFunction() !void {
361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
362
363 const S = struct {
364 export fn typeInfoFoo() callconv(.c) usize {
365 unreachable;
366 }
367 export fn typeInfoFooAligned() callconv(.c) usize {
368 unreachable;
369 }
370 };
371 _ = S;
372 const foo_fn_type = @TypeOf(typeInfoFoo);
373 const foo_fn_info = @typeInfo(foo_fn_type);
374 try expect(foo_fn_info.@"fn".calling_convention.eql(.c));
375 try expect(!foo_fn_info.@"fn".is_generic);
376 try expect(foo_fn_info.@"fn".params.len == 2);
377 try expect(foo_fn_info.@"fn".is_var_args);
378 try expect(foo_fn_info.@"fn".return_type.? == usize);
379 const foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFoo));
380 try expect(foo_ptr_fn_info.pointer.size == .one);
381 try expect(foo_ptr_fn_info.pointer.is_const);
382 try expect(!foo_ptr_fn_info.pointer.is_volatile);
383 try expect(foo_ptr_fn_info.pointer.address_space == .generic);
384 try expect(foo_ptr_fn_info.pointer.child == foo_fn_type);
385 try expect(!foo_ptr_fn_info.pointer.is_allowzero);
386 try expect(foo_ptr_fn_info.pointer.sentinel() == null);
387
388 // Avoid looking at `typeInfoFooAligned` on targets which don't support function alignment.
389 switch (builtin.target.cpu.arch) {
390 .spirv32,
391 .spirv64,
392 .wasm32,
393 .wasm64,
394 => return,
395 else => {},
396 }
397
398 const aligned_foo_fn_type = @TypeOf(typeInfoFooAligned);
399 const aligned_foo_fn_info = @typeInfo(aligned_foo_fn_type);
400 try expect(aligned_foo_fn_info.@"fn".calling_convention.eql(.c));
401 try expect(!aligned_foo_fn_info.@"fn".is_generic);
402 try expect(aligned_foo_fn_info.@"fn".params.len == 2);
403 try expect(aligned_foo_fn_info.@"fn".is_var_args);
404 try expect(aligned_foo_fn_info.@"fn".return_type.? == usize);
405 const aligned_foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFooAligned));
406 try expect(aligned_foo_ptr_fn_info.pointer.size == .one);
407 try expect(aligned_foo_ptr_fn_info.pointer.is_const);
408 try expect(!aligned_foo_ptr_fn_info.pointer.is_volatile);
409 try expect(aligned_foo_ptr_fn_info.pointer.alignment == 4);
410 try expect(aligned_foo_ptr_fn_info.pointer.address_space == .generic);
411 try expect(aligned_foo_ptr_fn_info.pointer.child == aligned_foo_fn_type);
412 try expect(!aligned_foo_ptr_fn_info.pointer.is_allowzero);
413 try expect(aligned_foo_ptr_fn_info.pointer.sentinel() == null);
414}
415
416extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.c) usize;
417extern fn typeInfoFooAligned(a: usize, b: bool, ...) align(4) callconv(.c) usize;
418
419test "type info: generic function types" {
420 const G1 = @typeInfo(@TypeOf(generic1));
421 try expect(G1.@"fn".params.len == 1);
422 try expect(G1.@"fn".params[0].is_generic == true);
423 try expect(G1.@"fn".params[0].type == null);
424 try expect(G1.@"fn".return_type == void);
425
426 const G2 = @typeInfo(@TypeOf(generic2));
427 try expect(G2.@"fn".params.len == 3);
428 try expect(G2.@"fn".params[0].is_generic == false);
429 try expect(G2.@"fn".params[0].type == type);
430 try expect(G2.@"fn".params[1].is_generic == true);
431 try expect(G2.@"fn".params[1].type == null);
432 try expect(G2.@"fn".params[2].is_generic == false);
433 try expect(G2.@"fn".params[2].type == u8);
434 try expect(G2.@"fn".return_type == void);
435
436 const G3 = @typeInfo(@TypeOf(generic3));
437 try expect(G3.@"fn".params.len == 1);
438 try expect(G3.@"fn".params[0].is_generic == true);
439 try expect(G3.@"fn".params[0].type == null);
440 try expect(G3.@"fn".return_type == null);
441
442 const G4 = @typeInfo(@TypeOf(generic4));
443 try expect(G4.@"fn".params.len == 1);
444 try expect(G4.@"fn".params[0].is_generic == true);
445 try expect(G4.@"fn".params[0].type == null);
446 try expect(G4.@"fn".return_type == null);
447}
448
449fn generic1(param: anytype) void {
450 _ = param;
451}
452fn generic2(comptime T: type, param: T, param2: u8) void {
453 _ = param;
454 _ = param2;
455}
456fn generic3(param: anytype) @TypeOf(param) {}
457fn generic4(comptime param: anytype) @TypeOf(param) {}
458
459test "typeInfo with comptime parameter in struct fn def" {
460 const S = struct {
461 pub fn func(comptime x: f32) void {
462 _ = x;
463 }
464 };
465 comptime var info = @typeInfo(S);
466 _ = &info;
467}
468
469test "type info: vectors" {
470 try testVector();
471 try comptime testVector();
472}
473
474fn testVector() !void {
475 const vec_info = @typeInfo(@Vector(4, i32));
476 try expect(vec_info == .vector);
477 try expect(vec_info.vector.len == 4);
478 try expect(vec_info.vector.child == i32);
479}
480
481test "type info: anyframe and anyframe->T" {
482 if (true) {
483 // https://github.com/ziglang/zig/issues/6025
484 return error.SkipZigTest;
485 }
486
487 try testAnyFrame();
488 try comptime testAnyFrame();
489}
490
491fn testAnyFrame() !void {
492 {
493 const anyframe_info = @typeInfo(anyframe->i32);
494 try expect(anyframe_info == .@"anyframe");
495 try expect(anyframe_info.@"anyframe".child.? == i32);
496 }
497
498 {
499 const anyframe_info = @typeInfo(anyframe);
500 try expect(anyframe_info == .@"anyframe");
501 try expect(anyframe_info.@"anyframe".child == null);
502 }
503}
504
505test "type info: pass to function" {
506 _ = passTypeInfo(@typeInfo(void));
507 _ = comptime passTypeInfo(@typeInfo(void));
508}
509
510fn passTypeInfo(comptime info: Type) type {
511 _ = info;
512 return void;
513}
514
515test "type info: TypeId -> Type impl cast" {
516 _ = passTypeInfo(TypeId.void);
517 _ = comptime passTypeInfo(TypeId.void);
518}
519
520test "sentinel of opaque pointer type" {
521 const c_void_info = @typeInfo(*anyopaque);
522 try expect(c_void_info.pointer.sentinel_ptr == null);
523}
524
525test "@typeInfo does not force declarations into existence" {
526 const S = struct {
527 x: i32,
528
529 fn doNotReferenceMe() void {
530 @compileError("test failed");
531 }
532 };
533 comptime assert(@typeInfo(S).@"struct".fields.len == 1);
534}
535
536fn add(a: i32, b: i32) i32 {
537 return a + b;
538}
539
540test "Declarations are returned in declaration order" {
541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
542 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
543
544 const S = struct {
545 pub const a = 1;
546 pub const b = 2;
547 pub const c = 3;
548 pub const d = 4;
549 pub const e = 5;
550 };
551 const d = @typeInfo(S).@"struct".decls;
552 try expect(std.mem.eql(u8, d[0].name, "a"));
553 try expect(std.mem.eql(u8, d[1].name, "b"));
554 try expect(std.mem.eql(u8, d[2].name, "c"));
555 try expect(std.mem.eql(u8, d[3].name, "d"));
556 try expect(std.mem.eql(u8, d[4].name, "e"));
557}
558
559test "Struct.is_tuple for anon list literal" {
560 try expect(@typeInfo(@TypeOf(.{0})).@"struct".is_tuple);
561}
562
563test "Struct.is_tuple for anon struct literal" {
564 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
565
566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
567
568 const info = @typeInfo(@TypeOf(.{ .a = 0 }));
569 try expect(!info.@"struct".is_tuple);
570 try expect(std.mem.eql(u8, info.@"struct".fields[0].name, "a"));
571}
572
573test "StructField.is_comptime" {
574 const info = @typeInfo(struct { x: u8 = 3, comptime y: u32 = 5 }).@"struct";
575 try expect(!info.fields[0].is_comptime);
576 try expect(info.fields[1].is_comptime);
577}
578
579test "value from struct @typeInfo default_value_ptr can be loaded at comptime" {
580 comptime {
581 const a = @typeInfo(@TypeOf(.{ .foo = @as(u8, 1) })).@"struct".fields[0].default_value_ptr;
582 try expect(@as(*const u8, @ptrCast(a)).* == 1);
583 }
584}
585
586test "type info of tuple of string literal default value" {
587 const struct_field = @typeInfo(@TypeOf(.{"hi"})).@"struct".fields[0];
588 const value = struct_field.defaultValue().?;
589 comptime std.debug.assert(value[0] == 'h');
590}
591
592test "@typeInfo function with generic return type and inferred error set" {
593 const S = struct {
594 fn testFn(comptime T: type) !T {}
595 };
596
597 const ret_ty = @typeInfo(@TypeOf(S.testFn)).@"fn".return_type;
598 comptime assert(ret_ty == null);
599}