authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-18 18:10:15-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-18 18:22:48-07:00
log8375b71f75c8b8567bc7d97867716c4911dace65
treeaf72f900f284ea8bb99e975472113baee793773c
parentcd594d10bdb930afe0cd05f1fcc8a7ecf2af4554

Sema: implement declarations for `@typeInfo`

In the behavior test listings, I had to move type_info.zig test import to a section that did not include the x86 backend because it got to the point where adding another test to the file, even if it was an empty test that just returned immediately, caused a runtime failure when executing the test binary. Anyway, type info for opaques is implemented, and the declarations slice is shared between it, enums, and unions. Still TODO is the `data` field of a `Declaration`. I want to consider removing it from the data returned from `@typeInfo` and introducing `@declInfo` or similar for this data. This would avoid the complexity of a lazy mechanism.

5 files changed, 591 insertions(+), 457 deletions(-)

src/Sema.zig+94-13
......@@ -9677,12 +9677,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
96779677 break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);
96789678 };
96799679
9680 if (ty.getNamespace()) |namespace| {
9681 if (namespace.decls.count() != 0) {
9682 return sema.fail(block, src, "TODO: implement zirTypeInfo for Enum which has declarations", .{});
9683 }
9684 }
9685 const decls_val = Value.initTag(.empty_array);
9680 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace());
96869681
96879682 const field_values = try sema.arena.create([5]Value);
96889683 field_values.* = .{
......@@ -9773,12 +9768,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
97739768 break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);
97749769 };
97759770
9776 if (ty.getNamespace()) |namespace| {
9777 if (namespace.decls.count() != 0) {
9778 return sema.fail(block, src, "TODO: implement zirTypeInfo for Union which has declarations", .{});
9779 }
9780 }
9781 const decls_val = Value.initTag(.empty_array);
9771 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespace());
97829772
97839773 const enum_tag_ty_val = if (union_ty.unionTagType()) |tag_ty| v: {
97849774 const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty);
......@@ -9810,14 +9800,105 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
98109800 );
98119801 },
98129802 .Struct => return sema.fail(block, src, "TODO: implement zirTypeInfo for Struct", .{}),
9803 .Opaque => {
9804 // TODO: look into memoizing this result.
9805
9806 var fields_anon_decl = try block.startAnonDecl();
9807 defer fields_anon_decl.deinit();
9808
9809 const opaque_ty = try sema.resolveTypeFields(block, src, ty);
9810 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespace());
9811
9812 const field_values = try sema.arena.create([1]Value);
9813 field_values.* = .{
9814 // decls: []const Declaration,
9815 decls_val,
9816 };
9817
9818 return sema.addConstant(
9819 type_info_ty,
9820 try Value.Tag.@"union".create(sema.arena, .{
9821 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Opaque)),
9822 .val = try Value.Tag.@"struct".create(sema.arena, field_values),
9823 }),
9824 );
9825 },
98139826 .ErrorSet => return sema.fail(block, src, "TODO: implement zirTypeInfo for ErrorSet", .{}),
98149827 .BoundFn => @panic("TODO remove this type from the language and compiler"),
9815 .Opaque => return sema.fail(block, src, "TODO: implement zirTypeInfo for Opaque", .{}),
98169828 .Frame => return sema.fail(block, src, "TODO: implement zirTypeInfo for Frame", .{}),
98179829 .AnyFrame => return sema.fail(block, src, "TODO: implement zirTypeInfo for AnyFrame", .{}),
98189830 }
98199831}
98209832
9833fn typeInfoDecls(
9834 sema: *Sema,
9835 block: *Block,
9836 src: LazySrcLoc,
9837 type_info_ty: Type,
9838 opt_namespace: ?*Module.Namespace,
9839) CompileError!Value {
9840 const namespace = opt_namespace orelse return Value.initTag(.empty_array);
9841 const decls_len = namespace.decls.count();
9842 if (decls_len == 0) return Value.initTag(.empty_array);
9843
9844 var decls_anon_decl = try block.startAnonDecl();
9845 defer decls_anon_decl.deinit();
9846
9847 const declaration_ty = t: {
9848 const declaration_ty_decl = (try sema.namespaceLookup(
9849 block,
9850 src,
9851 type_info_ty.getNamespace().?,
9852 "EnumField",
9853 )).?;
9854 try sema.mod.declareDeclDependency(sema.owner_decl, declaration_ty_decl);
9855 try sema.ensureDeclAnalyzed(declaration_ty_decl);
9856 var buffer: Value.ToTypeBuffer = undefined;
9857 break :t try declaration_ty_decl.val.toType(&buffer).copy(decls_anon_decl.arena());
9858 };
9859
9860 const decls_vals = try decls_anon_decl.arena().alloc(Value, decls_len);
9861 for (decls_vals) |*decls_val, i| {
9862 const decl = namespace.decls.values()[i];
9863 const name = namespace.decls.keys()[i];
9864 const name_val = v: {
9865 var anon_decl = try block.startAnonDecl();
9866 defer anon_decl.deinit();
9867 const bytes = try anon_decl.arena().dupeZ(u8, name);
9868 const new_decl = try anon_decl.finish(
9869 try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
9870 try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
9871 );
9872 break :v try Value.Tag.decl_ref.create(decls_anon_decl.arena(), new_decl);
9873 };
9874
9875 const is_pub = if (decl.is_pub) Value.@"true" else Value.@"false";
9876
9877 const fields = try decls_anon_decl.arena().create([3]Value);
9878 fields.* = .{
9879 //name: []const u8,
9880 name_val,
9881 //is_pub: bool,
9882 is_pub,
9883 //data: Data,
9884 Value.undef, // TODO
9885 };
9886 decls_val.* = try Value.Tag.@"struct".create(decls_anon_decl.arena(), fields);
9887 }
9888
9889 const new_decl = try decls_anon_decl.finish(
9890 try Type.Tag.array.create(decls_anon_decl.arena(), .{
9891 .len = decls_vals.len,
9892 .elem_type = declaration_ty,
9893 }),
9894 try Value.Tag.array.create(
9895 decls_anon_decl.arena(),
9896 try decls_anon_decl.arena().dupe(Value, decls_vals),
9897 ),
9898 );
9899 return try Value.Tag.decl_ref.create(sema.arena, new_decl);
9900}
9901
98219902fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
98229903 _ = block;
98239904 const zir_datas = sema.code.instructions.items(.data);
src/value.zig+15-2
......@@ -768,7 +768,12 @@ pub const Value = extern union {
768768 return allocator.dupe(u8, adjusted_bytes);
769769 },
770770 .enum_literal => return allocator.dupe(u8, val.castTag(.enum_literal).?.data),
771 .repeated => @panic("TODO implement toAllocatedBytes for this Value tag"),
771 .repeated => {
772 const byte = @intCast(u8, val.castTag(.repeated).?.data.toUnsignedInt());
773 const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen()));
774 std.mem.set(u8, result, byte);
775 return result;
776 },
772777 .decl_ref => {
773778 const decl = val.castTag(.decl_ref).?.data;
774779 const decl_val = try decl.value();
......@@ -776,7 +781,15 @@ pub const Value = extern union {
776781 },
777782 .the_only_possible_value => return &[_]u8{},
778783 .slice => return toAllocatedBytes(val.castTag(.slice).?.data.ptr, ty, allocator),
779 else => unreachable,
784 else => {
785 const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen()));
786 var elem_value_buf: ElemValueBuffer = undefined;
787 for (result) |*elem, i| {
788 const elem_val = val.elemValueBuffer(i, &elem_value_buf);
789 elem.* = @intCast(u8, elem_val.toUnsignedInt());
790 }
791 return result;
792 },
780793 }
781794 }
782795
test/behavior.zig+1-2
......@@ -11,7 +11,6 @@ test {
1111 _ = @import("behavior/hasdecl.zig");
1212 _ = @import("behavior/hasfield.zig");
1313 _ = @import("behavior/pub_enum.zig");
14 _ = @import("behavior/type_info.zig");
1514 _ = @import("behavior/type.zig");
1615 _ = @import("behavior/bugs/655.zig");
1716 _ = @import("behavior/bool.zig");
......@@ -56,6 +55,7 @@ test {
5655 _ = @import("behavior/this.zig");
5756 _ = @import("behavior/truncate.zig");
5857 _ = @import("behavior/try.zig");
58 _ = @import("behavior/type_info.zig");
5959 _ = @import("behavior/undefined.zig");
6060 _ = @import("behavior/underscore.zig");
6161 _ = @import("behavior/usingnamespace.zig");
......@@ -194,7 +194,6 @@ test {
194194 _ = @import("behavior/truncate_stage1.zig");
195195 _ = @import("behavior/tuple.zig");
196196 _ = @import("behavior/type_stage1.zig");
197 _ = @import("behavior/type_info_stage1.zig");
198197 _ = @import("behavior/typename.zig");
199198 _ = @import("behavior/union_stage1.zig");
200199 _ = @import("behavior/union_with_members.zig");
test/behavior/type_info.zig+481
......@@ -57,3 +57,484 @@ test "type info: value is correctly copied" {
5757 try expect(@typeInfo([]u32).Pointer.size == .Slice);
5858 }
5959}
60
61test "type info: tag type, void info" {
62 try testBasic();
63 comptime try testBasic();
64}
65
66fn testBasic() !void {
67 try expect(@typeInfo(TypeInfo).Union.tag_type == TypeId);
68 const void_info = @typeInfo(void);
69 try expect(void_info == TypeId.Void);
70 try expect(void_info.Void == {});
71}
72
73test "type info: pointer type info" {
74 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
75
76 try testPointer();
77 comptime try testPointer();
78}
79
80fn testPointer() !void {
81 const u32_ptr_info = @typeInfo(*u32);
82 try expect(u32_ptr_info == .Pointer);
83 try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
84 try expect(u32_ptr_info.Pointer.is_const == false);
85 try expect(u32_ptr_info.Pointer.is_volatile == false);
86 try expect(u32_ptr_info.Pointer.alignment == @alignOf(u32));
87 try expect(u32_ptr_info.Pointer.child == u32);
88 try expect(u32_ptr_info.Pointer.sentinel == null);
89}
90
91test "type info: unknown length pointer type info" {
92 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
93
94 try testUnknownLenPtr();
95 comptime try testUnknownLenPtr();
96}
97
98fn testUnknownLenPtr() !void {
99 const u32_ptr_info = @typeInfo([*]const volatile f64);
100 try expect(u32_ptr_info == .Pointer);
101 try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
102 try expect(u32_ptr_info.Pointer.is_const == true);
103 try expect(u32_ptr_info.Pointer.is_volatile == true);
104 try expect(u32_ptr_info.Pointer.sentinel == null);
105 try expect(u32_ptr_info.Pointer.alignment == @alignOf(f64));
106 try expect(u32_ptr_info.Pointer.child == f64);
107}
108
109test "type info: null terminated pointer type info" {
110 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
111
112 try testNullTerminatedPtr();
113 comptime try testNullTerminatedPtr();
114}
115
116fn testNullTerminatedPtr() !void {
117 const ptr_info = @typeInfo([*:0]u8);
118 try expect(ptr_info == .Pointer);
119 try expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
120 try expect(ptr_info.Pointer.is_const == false);
121 try expect(ptr_info.Pointer.is_volatile == false);
122 try expect(ptr_info.Pointer.sentinel.? == 0);
123
124 try expect(@typeInfo([:0]u8).Pointer.sentinel != null);
125}
126
127test "type info: slice type info" {
128 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
129
130 try testSlice();
131 comptime try testSlice();
132}
133
134fn testSlice() !void {
135 const u32_slice_info = @typeInfo([]u32);
136 try expect(u32_slice_info == .Pointer);
137 try expect(u32_slice_info.Pointer.size == .Slice);
138 try expect(u32_slice_info.Pointer.is_const == false);
139 try expect(u32_slice_info.Pointer.is_volatile == false);
140 try expect(u32_slice_info.Pointer.alignment == 4);
141 try expect(u32_slice_info.Pointer.child == u32);
142}
143
144test "type info: array type info" {
145 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
146
147 try testArray();
148 comptime try testArray();
149}
150
151fn testArray() !void {
152 {
153 const info = @typeInfo([42]u8);
154 try expect(info == .Array);
155 try expect(info.Array.len == 42);
156 try expect(info.Array.child == u8);
157 try expect(info.Array.sentinel == null);
158 }
159
160 {
161 const info = @typeInfo([10:0]u8);
162 try expect(info.Array.len == 10);
163 try expect(info.Array.child == u8);
164 try expect(info.Array.sentinel.? == @as(u8, 0));
165 try expect(@sizeOf([10:0]u8) == info.Array.len + 1);
166 }
167}
168
169test "type info: error set, error union info" {
170 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
171
172 try testErrorSet();
173 comptime try testErrorSet();
174}
175
176fn testErrorSet() !void {
177 const TestErrorSet = error{
178 First,
179 Second,
180 Third,
181 };
182
183 const error_set_info = @typeInfo(TestErrorSet);
184 try expect(error_set_info == .ErrorSet);
185 try expect(error_set_info.ErrorSet.?.len == 3);
186 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "First"));
187
188 const error_union_info = @typeInfo(TestErrorSet!usize);
189 try expect(error_union_info == .ErrorUnion);
190 try expect(error_union_info.ErrorUnion.error_set == TestErrorSet);
191 try expect(error_union_info.ErrorUnion.payload == usize);
192
193 const global_info = @typeInfo(anyerror);
194 try expect(global_info == .ErrorSet);
195 try expect(global_info.ErrorSet == null);
196}
197
198test "type info: enum info" {
199 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
200
201 try testEnum();
202 comptime try testEnum();
203}
204
205fn testEnum() !void {
206 const Os = enum {
207 Windows,
208 Macos,
209 Linux,
210 FreeBSD,
211 };
212
213 const os_info = @typeInfo(Os);
214 try expect(os_info == .Enum);
215 try expect(os_info.Enum.layout == .Auto);
216 try expect(os_info.Enum.fields.len == 4);
217 try expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
218 try expect(os_info.Enum.fields[3].value == 3);
219 try expect(os_info.Enum.tag_type == u2);
220 try expect(os_info.Enum.decls.len == 0);
221}
222
223test "type info: union info" {
224 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
225
226 try testUnion();
227 comptime try testUnion();
228}
229
230fn testUnion() !void {
231 const typeinfo_info = @typeInfo(TypeInfo);
232 try expect(typeinfo_info == .Union);
233 try expect(typeinfo_info.Union.layout == .Auto);
234 try expect(typeinfo_info.Union.tag_type.? == TypeId);
235 try expect(typeinfo_info.Union.fields.len == 25);
236 try expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
237 try expect(typeinfo_info.Union.decls.len == 22);
238
239 const TestNoTagUnion = union {
240 Foo: void,
241 Bar: u32,
242 };
243
244 const notag_union_info = @typeInfo(TestNoTagUnion);
245 try expect(notag_union_info == .Union);
246 try expect(notag_union_info.Union.tag_type == null);
247 try expect(notag_union_info.Union.layout == .Auto);
248 try expect(notag_union_info.Union.fields.len == 2);
249 try expect(notag_union_info.Union.fields[0].alignment == @alignOf(void));
250 try expect(notag_union_info.Union.fields[1].field_type == u32);
251 try expect(notag_union_info.Union.fields[1].alignment == @alignOf(u32));
252
253 const TestExternUnion = extern union {
254 foo: *anyopaque,
255 };
256
257 const extern_union_info = @typeInfo(TestExternUnion);
258 try expect(extern_union_info.Union.layout == .Extern);
259 try expect(extern_union_info.Union.tag_type == null);
260 try expect(extern_union_info.Union.fields[0].field_type == *anyopaque);
261}
262
263test "type info: struct info" {
264 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
265
266 try testStruct();
267 comptime try testStruct();
268}
269
270fn testStruct() !void {
271 const unpacked_struct_info = @typeInfo(TestUnpackedStruct);
272 try expect(unpacked_struct_info.Struct.is_tuple == false);
273 try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
274 try expect(unpacked_struct_info.Struct.fields[0].default_value.? == 4);
275 try expectEqualStrings("foobar", unpacked_struct_info.Struct.fields[1].default_value.?);
276
277 const struct_info = @typeInfo(TestStruct);
278 try expect(struct_info == .Struct);
279 try expect(struct_info.Struct.is_tuple == false);
280 try expect(struct_info.Struct.layout == .Packed);
281 try expect(struct_info.Struct.fields.len == 4);
282 try expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize));
283 try expect(struct_info.Struct.fields[2].field_type == *TestStruct);
284 try expect(struct_info.Struct.fields[2].default_value == null);
285 try expect(struct_info.Struct.fields[3].default_value.? == 4);
286 try expect(struct_info.Struct.fields[3].alignment == 1);
287 try expect(struct_info.Struct.decls.len == 2);
288 try expect(struct_info.Struct.decls[0].is_pub);
289 try expect(!struct_info.Struct.decls[0].data.Fn.is_extern);
290 try expect(struct_info.Struct.decls[0].data.Fn.lib_name == null);
291 try expect(struct_info.Struct.decls[0].data.Fn.return_type == void);
292 try expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void);
293}
294
295const TestUnpackedStruct = struct {
296 fieldA: u32 = 4,
297 fieldB: *const [6:0]u8 = "foobar",
298};
299
300const TestStruct = packed struct {
301 fieldA: usize align(2 * @alignOf(usize)),
302 fieldB: void,
303 fieldC: *Self,
304 fieldD: u32 = 4,
305
306 pub fn foo(self: *const Self) void {
307 _ = self;
308 }
309 const Self = @This();
310};
311
312test "type info: opaque info" {
313 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
314
315 try testOpaque();
316 comptime try testOpaque();
317}
318
319fn testOpaque() !void {
320 const Foo = opaque {
321 const A = 1;
322 fn b() void {}
323 };
324
325 const foo_info = @typeInfo(Foo);
326 try expect(foo_info.Opaque.decls.len == 2);
327}
328
329test "type info: function type info" {
330 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
331
332 // wasm doesn't support align attributes on functions
333 if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
334 try testFunction();
335 comptime try testFunction();
336}
337
338fn testFunction() !void {
339 const fn_info = @typeInfo(@TypeOf(foo));
340 try expect(fn_info == .Fn);
341 try expect(fn_info.Fn.alignment > 0);
342 try expect(fn_info.Fn.calling_convention == .C);
343 try expect(!fn_info.Fn.is_generic);
344 try expect(fn_info.Fn.args.len == 2);
345 try expect(fn_info.Fn.is_var_args);
346 try expect(fn_info.Fn.return_type.? == usize);
347 const fn_aligned_info = @typeInfo(@TypeOf(fooAligned));
348 try expect(fn_aligned_info.Fn.alignment == 4);
349
350 const test_instance: TestStruct = undefined;
351 const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo));
352 try expect(bound_fn_info == .BoundFn);
353 try expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
354}
355
356extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
357extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize;
358
359test "typeInfo with comptime parameter in struct fn def" {
360 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
361
362 const S = struct {
363 pub fn func(comptime x: f32) void {
364 _ = x;
365 }
366 };
367 comptime var info = @typeInfo(S);
368 _ = info;
369}
370
371test "type info: vectors" {
372 try testVector();
373 comptime try testVector();
374}
375
376fn testVector() !void {
377 const vec_info = @typeInfo(std.meta.Vector(4, i32));
378 try expect(vec_info == .Vector);
379 try expect(vec_info.Vector.len == 4);
380 try expect(vec_info.Vector.child == i32);
381}
382
383test "type info: anyframe and anyframe->T" {
384 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
385
386 try testAnyFrame();
387 comptime try testAnyFrame();
388}
389
390fn testAnyFrame() !void {
391 {
392 const anyframe_info = @typeInfo(anyframe->i32);
393 try expect(anyframe_info == .AnyFrame);
394 try expect(anyframe_info.AnyFrame.child.? == i32);
395 }
396
397 {
398 const anyframe_info = @typeInfo(anyframe);
399 try expect(anyframe_info == .AnyFrame);
400 try expect(anyframe_info.AnyFrame.child == null);
401 }
402}
403
404test "type info: pass to function" {
405 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
406
407 _ = passTypeInfo(@typeInfo(void));
408 _ = comptime passTypeInfo(@typeInfo(void));
409}
410
411fn passTypeInfo(comptime info: TypeInfo) type {
412 _ = info;
413 return void;
414}
415
416test "type info: TypeId -> TypeInfo impl cast" {
417 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
418
419 _ = passTypeInfo(TypeId.Void);
420 _ = comptime passTypeInfo(TypeId.Void);
421}
422
423test "type info: extern fns with and without lib names" {
424 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
425
426 const S = struct {
427 extern fn bar1() void;
428 extern "cool" fn bar2() void;
429 };
430 const info = @typeInfo(S);
431 comptime {
432 for (info.Struct.decls) |decl| {
433 if (std.mem.eql(u8, decl.name, "bar1")) {
434 try expect(decl.data.Fn.lib_name == null);
435 } else {
436 try expectEqualStrings("cool", decl.data.Fn.lib_name.?);
437 }
438 }
439 }
440}
441
442test "data field is a compile-time value" {
443 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
444
445 const S = struct {
446 const Bar = @as(isize, -1);
447 };
448 comptime try expect(@typeInfo(S).Struct.decls[0].data.Var == isize);
449}
450
451test "sentinel of opaque pointer type" {
452 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
453
454 const c_void_info = @typeInfo(*anyopaque);
455 try expect(c_void_info.Pointer.sentinel == null);
456}
457
458test "@typeInfo does not force declarations into existence" {
459 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
460
461 const S = struct {
462 x: i32,
463
464 fn doNotReferenceMe() void {
465 @compileError("test failed");
466 }
467 };
468 comptime try expect(@typeInfo(S).Struct.fields.len == 1);
469}
470
471test "default value for a anytype field" {
472 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
473
474 const S = struct { x: anytype };
475 try expect(@typeInfo(S).Struct.fields[0].default_value == null);
476}
477
478fn add(a: i32, b: i32) i32 {
479 return a + b;
480}
481
482test "type info for async frames" {
483 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
484
485 switch (@typeInfo(@Frame(add))) {
486 .Frame => |frame| {
487 try expect(frame.function == add);
488 },
489 else => unreachable,
490 }
491}
492
493test "Declarations are returned in declaration order" {
494 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
495
496 const S = struct {
497 const a = 1;
498 const b = 2;
499 const c = 3;
500 const d = 4;
501 const e = 5;
502 };
503 const d = @typeInfo(S).Struct.decls;
504 try expect(std.mem.eql(u8, d[0].name, "a"));
505 try expect(std.mem.eql(u8, d[1].name, "b"));
506 try expect(std.mem.eql(u8, d[2].name, "c"));
507 try expect(std.mem.eql(u8, d[3].name, "d"));
508 try expect(std.mem.eql(u8, d[4].name, "e"));
509}
510
511test "Struct.is_tuple" {
512 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
513
514 try expect(@typeInfo(@TypeOf(.{0})).Struct.is_tuple);
515 try expect(!@typeInfo(@TypeOf(.{ .a = 0 })).Struct.is_tuple);
516}
517
518test "StructField.is_comptime" {
519 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
520
521 const info = @typeInfo(struct { x: u8 = 3, comptime y: u32 = 5 }).Struct;
522 try expect(!info.fields[0].is_comptime);
523 try expect(info.fields[1].is_comptime);
524}
525
526test "typeInfo resolves usingnamespace declarations" {
527 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
528
529 const A = struct {
530 pub const f1 = 42;
531 };
532
533 const B = struct {
534 const f0 = 42;
535 usingnamespace A;
536 };
537
538 try expect(@typeInfo(B).Struct.decls.len == 2);
539 //a
540}
test/behavior/type_info_stage1.zig deleted-440
......@@ -1,440 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const mem = std.mem;
4
5const TypeInfo = std.builtin.TypeInfo;
6const TypeId = std.builtin.TypeId;
7
8const expect = std.testing.expect;
9const expectEqualStrings = std.testing.expectEqualStrings;
10
11test "type info: tag type, void info" {
12 try testBasic();
13 comptime try testBasic();
14}
15
16fn testBasic() !void {
17 try expect(@typeInfo(TypeInfo).Union.tag_type == TypeId);
18 const void_info = @typeInfo(void);
19 try expect(void_info == TypeId.Void);
20 try expect(void_info.Void == {});
21}
22
23test "type info: pointer type info" {
24 try testPointer();
25 comptime try testPointer();
26}
27
28fn testPointer() !void {
29 const u32_ptr_info = @typeInfo(*u32);
30 try expect(u32_ptr_info == .Pointer);
31 try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
32 try expect(u32_ptr_info.Pointer.is_const == false);
33 try expect(u32_ptr_info.Pointer.is_volatile == false);
34 try expect(u32_ptr_info.Pointer.alignment == @alignOf(u32));
35 try expect(u32_ptr_info.Pointer.child == u32);
36 try expect(u32_ptr_info.Pointer.sentinel == null);
37}
38
39test "type info: unknown length pointer type info" {
40 try testUnknownLenPtr();
41 comptime try testUnknownLenPtr();
42}
43
44fn testUnknownLenPtr() !void {
45 const u32_ptr_info = @typeInfo([*]const volatile f64);
46 try expect(u32_ptr_info == .Pointer);
47 try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
48 try expect(u32_ptr_info.Pointer.is_const == true);
49 try expect(u32_ptr_info.Pointer.is_volatile == true);
50 try expect(u32_ptr_info.Pointer.sentinel == null);
51 try expect(u32_ptr_info.Pointer.alignment == @alignOf(f64));
52 try expect(u32_ptr_info.Pointer.child == f64);
53}
54
55test "type info: null terminated pointer type info" {
56 try testNullTerminatedPtr();
57 comptime try testNullTerminatedPtr();
58}
59
60fn testNullTerminatedPtr() !void {
61 const ptr_info = @typeInfo([*:0]u8);
62 try expect(ptr_info == .Pointer);
63 try expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
64 try expect(ptr_info.Pointer.is_const == false);
65 try expect(ptr_info.Pointer.is_volatile == false);
66 try expect(ptr_info.Pointer.sentinel.? == 0);
67
68 try expect(@typeInfo([:0]u8).Pointer.sentinel != null);
69}
70
71test "type info: slice type info" {
72 try testSlice();
73 comptime try testSlice();
74}
75
76fn testSlice() !void {
77 const u32_slice_info = @typeInfo([]u32);
78 try expect(u32_slice_info == .Pointer);
79 try expect(u32_slice_info.Pointer.size == .Slice);
80 try expect(u32_slice_info.Pointer.is_const == false);
81 try expect(u32_slice_info.Pointer.is_volatile == false);
82 try expect(u32_slice_info.Pointer.alignment == 4);
83 try expect(u32_slice_info.Pointer.child == u32);
84}
85
86test "type info: array type info" {
87 try testArray();
88 comptime try testArray();
89}
90
91fn testArray() !void {
92 {
93 const info = @typeInfo([42]u8);
94 try expect(info == .Array);
95 try expect(info.Array.len == 42);
96 try expect(info.Array.child == u8);
97 try expect(info.Array.sentinel == null);
98 }
99
100 {
101 const info = @typeInfo([10:0]u8);
102 try expect(info.Array.len == 10);
103 try expect(info.Array.child == u8);
104 try expect(info.Array.sentinel.? == @as(u8, 0));
105 try expect(@sizeOf([10:0]u8) == info.Array.len + 1);
106 }
107}
108
109test "type info: error set, error union info" {
110 try testErrorSet();
111 comptime try testErrorSet();
112}
113
114fn testErrorSet() !void {
115 const TestErrorSet = error{
116 First,
117 Second,
118 Third,
119 };
120
121 const error_set_info = @typeInfo(TestErrorSet);
122 try expect(error_set_info == .ErrorSet);
123 try expect(error_set_info.ErrorSet.?.len == 3);
124 try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "First"));
125
126 const error_union_info = @typeInfo(TestErrorSet!usize);
127 try expect(error_union_info == .ErrorUnion);
128 try expect(error_union_info.ErrorUnion.error_set == TestErrorSet);
129 try expect(error_union_info.ErrorUnion.payload == usize);
130
131 const global_info = @typeInfo(anyerror);
132 try expect(global_info == .ErrorSet);
133 try expect(global_info.ErrorSet == null);
134}
135
136test "type info: enum info" {
137 try testEnum();
138 comptime try testEnum();
139}
140
141fn testEnum() !void {
142 const Os = enum {
143 Windows,
144 Macos,
145 Linux,
146 FreeBSD,
147 };
148
149 const os_info = @typeInfo(Os);
150 try expect(os_info == .Enum);
151 try expect(os_info.Enum.layout == .Auto);
152 try expect(os_info.Enum.fields.len == 4);
153 try expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
154 try expect(os_info.Enum.fields[3].value == 3);
155 try expect(os_info.Enum.tag_type == u2);
156 try expect(os_info.Enum.decls.len == 0);
157}
158
159test "type info: union info" {
160 try testUnion();
161 comptime try testUnion();
162}
163
164fn testUnion() !void {
165 const typeinfo_info = @typeInfo(TypeInfo);
166 try expect(typeinfo_info == .Union);
167 try expect(typeinfo_info.Union.layout == .Auto);
168 try expect(typeinfo_info.Union.tag_type.? == TypeId);
169 try expect(typeinfo_info.Union.fields.len == 25);
170 try expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
171 try expect(typeinfo_info.Union.decls.len == 22);
172
173 const TestNoTagUnion = union {
174 Foo: void,
175 Bar: u32,
176 };
177
178 const notag_union_info = @typeInfo(TestNoTagUnion);
179 try expect(notag_union_info == .Union);
180 try expect(notag_union_info.Union.tag_type == null);
181 try expect(notag_union_info.Union.layout == .Auto);
182 try expect(notag_union_info.Union.fields.len == 2);
183 try expect(notag_union_info.Union.fields[0].alignment == @alignOf(void));
184 try expect(notag_union_info.Union.fields[1].field_type == u32);
185 try expect(notag_union_info.Union.fields[1].alignment == @alignOf(u32));
186
187 const TestExternUnion = extern union {
188 foo: *anyopaque,
189 };
190
191 const extern_union_info = @typeInfo(TestExternUnion);
192 try expect(extern_union_info.Union.layout == .Extern);
193 try expect(extern_union_info.Union.tag_type == null);
194 try expect(extern_union_info.Union.fields[0].field_type == *anyopaque);
195}
196
197test "type info: struct info" {
198 try testStruct();
199 comptime try testStruct();
200}
201
202fn testStruct() !void {
203 const unpacked_struct_info = @typeInfo(TestUnpackedStruct);
204 try expect(unpacked_struct_info.Struct.is_tuple == false);
205 try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
206 try expect(unpacked_struct_info.Struct.fields[0].default_value.? == 4);
207 try expectEqualStrings("foobar", unpacked_struct_info.Struct.fields[1].default_value.?);
208
209 const struct_info = @typeInfo(TestStruct);
210 try expect(struct_info == .Struct);
211 try expect(struct_info.Struct.is_tuple == false);
212 try expect(struct_info.Struct.layout == .Packed);
213 try expect(struct_info.Struct.fields.len == 4);
214 try expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize));
215 try expect(struct_info.Struct.fields[2].field_type == *TestStruct);
216 try expect(struct_info.Struct.fields[2].default_value == null);
217 try expect(struct_info.Struct.fields[3].default_value.? == 4);
218 try expect(struct_info.Struct.fields[3].alignment == 1);
219 try expect(struct_info.Struct.decls.len == 2);
220 try expect(struct_info.Struct.decls[0].is_pub);
221 try expect(!struct_info.Struct.decls[0].data.Fn.is_extern);
222 try expect(struct_info.Struct.decls[0].data.Fn.lib_name == null);
223 try expect(struct_info.Struct.decls[0].data.Fn.return_type == void);
224 try expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void);
225}
226
227const TestUnpackedStruct = struct {
228 fieldA: u32 = 4,
229 fieldB: *const [6:0]u8 = "foobar",
230};
231
232const TestStruct = packed struct {
233 fieldA: usize align(2 * @alignOf(usize)),
234 fieldB: void,
235 fieldC: *Self,
236 fieldD: u32 = 4,
237
238 pub fn foo(self: *const Self) void {
239 _ = self;
240 }
241 const Self = @This();
242};
243
244test "type info: opaque info" {
245 try testOpaque();
246 comptime try testOpaque();
247}
248
249fn testOpaque() !void {
250 const Foo = opaque {
251 const A = 1;
252 fn b() void {}
253 };
254
255 const foo_info = @typeInfo(Foo);
256 try expect(foo_info.Opaque.decls.len == 2);
257}
258
259test "type info: function type info" {
260 // wasm doesn't support align attributes on functions
261 if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
262 try testFunction();
263 comptime try testFunction();
264}
265
266fn testFunction() !void {
267 const fn_info = @typeInfo(@TypeOf(foo));
268 try expect(fn_info == .Fn);
269 try expect(fn_info.Fn.alignment > 0);
270 try expect(fn_info.Fn.calling_convention == .C);
271 try expect(!fn_info.Fn.is_generic);
272 try expect(fn_info.Fn.args.len == 2);
273 try expect(fn_info.Fn.is_var_args);
274 try expect(fn_info.Fn.return_type.? == usize);
275 const fn_aligned_info = @typeInfo(@TypeOf(fooAligned));
276 try expect(fn_aligned_info.Fn.alignment == 4);
277
278 const test_instance: TestStruct = undefined;
279 const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo));
280 try expect(bound_fn_info == .BoundFn);
281 try expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
282}
283
284extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
285extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize;
286
287test "typeInfo with comptime parameter in struct fn def" {
288 const S = struct {
289 pub fn func(comptime x: f32) void {
290 _ = x;
291 }
292 };
293 comptime var info = @typeInfo(S);
294 _ = info;
295}
296
297test "type info: vectors" {
298 try testVector();
299 comptime try testVector();
300}
301
302fn testVector() !void {
303 const vec_info = @typeInfo(std.meta.Vector(4, i32));
304 try expect(vec_info == .Vector);
305 try expect(vec_info.Vector.len == 4);
306 try expect(vec_info.Vector.child == i32);
307}
308
309test "type info: anyframe and anyframe->T" {
310 try testAnyFrame();
311 comptime try testAnyFrame();
312}
313
314fn testAnyFrame() !void {
315 {
316 const anyframe_info = @typeInfo(anyframe->i32);
317 try expect(anyframe_info == .AnyFrame);
318 try expect(anyframe_info.AnyFrame.child.? == i32);
319 }
320
321 {
322 const anyframe_info = @typeInfo(anyframe);
323 try expect(anyframe_info == .AnyFrame);
324 try expect(anyframe_info.AnyFrame.child == null);
325 }
326}
327
328test "type info: pass to function" {
329 _ = passTypeInfo(@typeInfo(void));
330 _ = comptime passTypeInfo(@typeInfo(void));
331}
332
333fn passTypeInfo(comptime info: TypeInfo) type {
334 _ = info;
335 return void;
336}
337
338test "type info: TypeId -> TypeInfo impl cast" {
339 _ = passTypeInfo(TypeId.Void);
340 _ = comptime passTypeInfo(TypeId.Void);
341}
342
343test "type info: extern fns with and without lib names" {
344 const S = struct {
345 extern fn bar1() void;
346 extern "cool" fn bar2() void;
347 };
348 const info = @typeInfo(S);
349 comptime {
350 for (info.Struct.decls) |decl| {
351 if (std.mem.eql(u8, decl.name, "bar1")) {
352 try expect(decl.data.Fn.lib_name == null);
353 } else {
354 try expectEqualStrings("cool", decl.data.Fn.lib_name.?);
355 }
356 }
357 }
358}
359
360test "data field is a compile-time value" {
361 const S = struct {
362 const Bar = @as(isize, -1);
363 };
364 comptime try expect(@typeInfo(S).Struct.decls[0].data.Var == isize);
365}
366
367test "sentinel of opaque pointer type" {
368 const c_void_info = @typeInfo(*anyopaque);
369 try expect(c_void_info.Pointer.sentinel == null);
370}
371
372test "@typeInfo does not force declarations into existence" {
373 const S = struct {
374 x: i32,
375
376 fn doNotReferenceMe() void {
377 @compileError("test failed");
378 }
379 };
380 comptime try expect(@typeInfo(S).Struct.fields.len == 1);
381}
382
383test "default value for a var-typed field" {
384 const S = struct { x: anytype };
385 try expect(@typeInfo(S).Struct.fields[0].default_value == null);
386}
387
388fn add(a: i32, b: i32) i32 {
389 return a + b;
390}
391
392test "type info for async frames" {
393 switch (@typeInfo(@Frame(add))) {
394 .Frame => |frame| {
395 try expect(frame.function == add);
396 },
397 else => unreachable,
398 }
399}
400
401test "Declarations are returned in declaration order" {
402 const S = struct {
403 const a = 1;
404 const b = 2;
405 const c = 3;
406 const d = 4;
407 const e = 5;
408 };
409 const d = @typeInfo(S).Struct.decls;
410 try expect(std.mem.eql(u8, d[0].name, "a"));
411 try expect(std.mem.eql(u8, d[1].name, "b"));
412 try expect(std.mem.eql(u8, d[2].name, "c"));
413 try expect(std.mem.eql(u8, d[3].name, "d"));
414 try expect(std.mem.eql(u8, d[4].name, "e"));
415}
416
417test "Struct.is_tuple" {
418 try expect(@typeInfo(@TypeOf(.{0})).Struct.is_tuple);
419 try expect(!@typeInfo(@TypeOf(.{ .a = 0 })).Struct.is_tuple);
420}
421
422test "StructField.is_comptime" {
423 const info = @typeInfo(struct { x: u8 = 3, comptime y: u32 = 5 }).Struct;
424 try expect(!info.fields[0].is_comptime);
425 try expect(info.fields[1].is_comptime);
426}
427
428test "typeInfo resolves usingnamespace declarations" {
429 const A = struct {
430 pub const f1 = 42;
431 };
432
433 const B = struct {
434 const f0 = 42;
435 usingnamespace A;
436 };
437
438 try expect(@typeInfo(B).Struct.decls.len == 2);
439 //a
440}