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}