master
1const std = @import("std");
2const builtin = @import("builtin");
3const Type = std.builtin.Type;
4const testing = std.testing;
5const assert = std.debug.assert;
6
7test "Type.Int" {
8 try testing.expect(u1 == @Int(.unsigned, 1));
9 try testing.expect(i1 == @Int(.signed, 1));
10 try testing.expect(u8 == @Int(.unsigned, 8));
11 try testing.expect(i8 == @Int(.signed, 8));
12 try testing.expect(u64 == @Int(.unsigned, 64));
13 try testing.expect(i64 == @Int(.signed, 64));
14}
15
16test "Type.Pointer" {
17 inline for (&[_]type{
18 // One Value Pointer Types
19 *u8, *const u8,
20 *volatile u8, *const volatile u8,
21 *align(4) u8, *align(4) const u8,
22 *align(4) volatile u8, *align(4) const volatile u8,
23 *align(8) u8, *align(8) const u8,
24 *align(8) volatile u8, *align(8) const volatile u8,
25 *allowzero u8, *allowzero const u8,
26 *allowzero volatile u8, *allowzero const volatile u8,
27 *allowzero align(4) u8, *allowzero align(4) const u8,
28 *allowzero align(4) volatile u8, *allowzero align(4) const volatile u8,
29 // Many Values Pointer Types
30 [*]u8, [*]const u8,
31 [*]volatile u8, [*]const volatile u8,
32 [*]align(4) u8, [*]align(4) const u8,
33 [*]align(4) volatile u8, [*]align(4) const volatile u8,
34 [*]align(8) u8, [*]align(8) const u8,
35 [*]align(8) volatile u8, [*]align(8) const volatile u8,
36 [*]allowzero u8, [*]allowzero const u8,
37 [*]allowzero volatile u8, [*]allowzero const volatile u8,
38 [*]allowzero align(4) u8, [*]allowzero align(4) const u8,
39 [*]allowzero align(4) volatile u8, [*]allowzero align(4) const volatile u8,
40 // Slice Types
41 []u8, []const u8,
42 []volatile u8, []const volatile u8,
43 []align(4) u8, []align(4) const u8,
44 []align(4) volatile u8, []align(4) const volatile u8,
45 []align(8) u8, []align(8) const u8,
46 []align(8) volatile u8, []align(8) const volatile u8,
47 []allowzero u8, []allowzero const u8,
48 []allowzero volatile u8, []allowzero const volatile u8,
49 []allowzero align(4) u8, []allowzero align(4) const u8,
50 []allowzero align(4) volatile u8, []allowzero align(4) const volatile u8,
51 // C Pointer Types
52 [*c]u8, [*c]const u8,
53 [*c]volatile u8, [*c]const volatile u8,
54 [*c]align(4) u8, [*c]align(4) const u8,
55 [*c]align(4) volatile u8, [*c]align(4) const volatile u8,
56 [*c]align(8) u8, [*c]align(8) const u8,
57 [*c]align(8) volatile u8, [*c]align(8) const volatile u8,
58 }) |testType| {
59 const ptr = @typeInfo(testType).pointer;
60 try testing.expect(testType == @Pointer(ptr.size, .{
61 .@"const" = ptr.is_const,
62 .@"volatile" = ptr.is_volatile,
63 .@"allowzero" = ptr.is_allowzero,
64 .@"align" = ptr.alignment,
65 .@"addrspace" = ptr.address_space,
66 }, ptr.child, ptr.sentinel()));
67 }
68}
69
70test "@Pointer create slice without sentinel" {
71 const Slice = @Pointer(.slice, .{ .@"const" = true, .@"align" = 8 }, ?*i32, null);
72 try testing.expect(Slice == []align(8) const ?*i32);
73}
74
75test "@Pointer create slice with null sentinel" {
76 const Slice = @Pointer(.slice, .{ .@"const" = true, .@"align" = 8 }, ?*i32, @as(?*i32, null));
77 try testing.expect(Slice == [:null]align(8) const ?*i32);
78}
79
80test "@Pointer on @typeInfo round-trips sentinels" {
81 inline for (&[_]type{
82 [*:0]u8, [*:0]const u8,
83 [*:0]volatile u8, [*:0]const volatile u8,
84 [*:0]align(4) u8, [*:0]align(4) const u8,
85 [*:0]align(4) volatile u8, [*:0]align(4) const volatile u8,
86 [*:0]align(8) u8, [*:0]align(8) const u8,
87 [*:0]align(8) volatile u8, [*:0]align(8) const volatile u8,
88 [*:0]allowzero u8, [*:0]allowzero const u8,
89 [*:0]allowzero volatile u8, [*:0]allowzero const volatile u8,
90 [*:0]allowzero align(4) u8, [*:0]allowzero align(4) const u8,
91 [*:0]allowzero align(4) volatile u8, [*:0]allowzero align(4) const volatile u8,
92 [*:5]allowzero align(4) volatile u8, [*:5]allowzero align(4) const volatile u8,
93 [:0]u8, [:0]const u8,
94 [:0]volatile u8, [:0]const volatile u8,
95 [:0]align(4) u8, [:0]align(4) const u8,
96 [:0]align(4) volatile u8, [:0]align(4) const volatile u8,
97 [:0]align(8) u8, [:0]align(8) const u8,
98 [:0]align(8) volatile u8, [:0]align(8) const volatile u8,
99 [:0]allowzero u8, [:0]allowzero const u8,
100 [:0]allowzero volatile u8, [:0]allowzero const volatile u8,
101 [:0]allowzero align(4) u8, [:0]allowzero align(4) const u8,
102 [:0]allowzero align(4) volatile u8, [:0]allowzero align(4) const volatile u8,
103 [:4]allowzero align(4) volatile u8, [:4]allowzero align(4) const volatile u8,
104 }) |TestType| {
105 const ptr = @typeInfo(TestType).pointer;
106 try testing.expect(TestType == @Pointer(ptr.size, .{
107 .@"const" = ptr.is_const,
108 .@"volatile" = ptr.is_volatile,
109 .@"allowzero" = ptr.is_allowzero,
110 .@"align" = ptr.alignment,
111 .@"addrspace" = ptr.address_space,
112 }, ptr.child, ptr.sentinel()));
113 }
114}
115
116test "Type.Opaque" {
117 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
118 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
121
122 const Opaque = opaque {};
123 try testing.expect(Opaque != opaque {});
124 try testing.expectEqualSlices(
125 Type.Declaration,
126 &.{},
127 @typeInfo(Opaque).@"opaque".decls,
128 );
129}
130
131fn add(a: i32, b: i32) i32 {
132 return a + b;
133}
134
135test "Type.Struct" {
136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
140
141 const A = @Struct(.auto, null, &.{ "x", "y" }, &.{ u8, u32 }, &@splat(.{}));
142 const infoA = @typeInfo(A).@"struct";
143 try testing.expectEqual(Type.ContainerLayout.auto, infoA.layout);
144 try testing.expectEqualSlices(u8, "x", infoA.fields[0].name);
145 try testing.expectEqual(u8, infoA.fields[0].type);
146 try testing.expectEqual(@as(?*const anyopaque, null), infoA.fields[0].default_value_ptr);
147 try testing.expectEqualSlices(u8, "y", infoA.fields[1].name);
148 try testing.expectEqual(u32, infoA.fields[1].type);
149 try testing.expectEqual(@as(?*const anyopaque, null), infoA.fields[1].default_value_ptr);
150 try testing.expectEqualSlices(Type.Declaration, &.{}, infoA.decls);
151 try testing.expectEqual(@as(bool, false), infoA.is_tuple);
152
153 var a = A{ .x = 0, .y = 1 };
154 try testing.expectEqual(@as(u8, 0), a.x);
155 try testing.expectEqual(@as(u32, 1), a.y);
156 a.y += 1;
157 try testing.expectEqual(@as(u32, 2), a.y);
158
159 const B = @Struct(
160 .@"extern",
161 null,
162 &.{ "x", "y" },
163 &.{ u8, u32 },
164 &.{ .{}, .{ .default_value_ptr = &@as(u32, 5) } },
165 );
166 const infoB = @typeInfo(B).@"struct";
167 try testing.expectEqual(Type.ContainerLayout.@"extern", infoB.layout);
168 try testing.expectEqualSlices(u8, "x", infoB.fields[0].name);
169 try testing.expectEqual(u8, infoB.fields[0].type);
170 try testing.expectEqual(@as(?*const anyopaque, null), infoB.fields[0].default_value_ptr);
171 try testing.expectEqualSlices(u8, "y", infoB.fields[1].name);
172 try testing.expectEqual(u32, infoB.fields[1].type);
173 try testing.expectEqual(@as(u32, 5), infoB.fields[1].defaultValue().?);
174 try testing.expectEqual(@as(usize, 0), infoB.decls.len);
175 try testing.expectEqual(@as(bool, false), infoB.is_tuple);
176
177 const C = @Struct(
178 .@"packed",
179 null,
180 &.{ "x", "y" },
181 &.{ u8, u32 },
182 &.{
183 .{ .default_value_ptr = &@as(u8, 3) },
184 .{ .default_value_ptr = &@as(u32, 5) },
185 },
186 );
187 const infoC = @typeInfo(C).@"struct";
188 try testing.expectEqual(Type.ContainerLayout.@"packed", infoC.layout);
189 try testing.expectEqualSlices(u8, "x", infoC.fields[0].name);
190 try testing.expectEqual(u8, infoC.fields[0].type);
191 try testing.expectEqual(@as(u8, 3), infoC.fields[0].defaultValue().?);
192 try testing.expectEqualSlices(u8, "y", infoC.fields[1].name);
193 try testing.expectEqual(u32, infoC.fields[1].type);
194 try testing.expectEqual(@as(u32, 5), infoC.fields[1].defaultValue().?);
195 try testing.expectEqual(@as(usize, 0), infoC.decls.len);
196 try testing.expectEqual(@as(bool, false), infoC.is_tuple);
197
198 // empty struct
199 const F = @Struct(.auto, null, &.{}, &.{}, &.{});
200 const infoF = @typeInfo(F).@"struct";
201 try testing.expectEqual(Type.ContainerLayout.auto, infoF.layout);
202 try testing.expect(infoF.fields.len == 0);
203 try testing.expectEqual(@as(bool, false), infoF.is_tuple);
204}
205
206test "Type.Enum" {
207 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
208 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
209
210 const Foo = @Enum(u8, .exhaustive, &.{ "a", "b" }, &.{ 1, 5 });
211 try testing.expectEqual(true, @typeInfo(Foo).@"enum".is_exhaustive);
212 try testing.expectEqual(@as(u8, 1), @intFromEnum(Foo.a));
213 try testing.expectEqual(@as(u8, 5), @intFromEnum(Foo.b));
214 const Bar = @Enum(u32, .nonexhaustive, &.{ "a", "b" }, &.{ 1, 5 });
215 try testing.expectEqual(false, @typeInfo(Bar).@"enum".is_exhaustive);
216 try testing.expectEqual(@as(u32, 1), @intFromEnum(Bar.a));
217 try testing.expectEqual(@as(u32, 5), @intFromEnum(Bar.b));
218 try testing.expectEqual(@as(u32, 6), @intFromEnum(@as(Bar, @enumFromInt(6))));
219
220 { // from https://github.com/ziglang/zig/issues/19985
221 { // enum with single field can be initialized.
222 const E = @Enum(u0, .exhaustive, &.{"foo"}, &.{0});
223 const s: struct { E } = .{.foo};
224 try testing.expectEqual(.foo, s[0]);
225 }
226
227 { // meta.FieldEnum() with single field
228 const S = struct { foo: u8 };
229 const Fe = std.meta.FieldEnum(S);
230 var s: S = undefined;
231 const fe = std.meta.stringToEnum(Fe, "foo") orelse return error.InvalidField;
232 switch (fe) {
233 inline else => |tag| {
234 @field(s, @tagName(tag)) = 42;
235 },
236 }
237 try testing.expectEqual(42, s.foo);
238 }
239 }
240}
241
242test "Type.Union" {
243 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
244 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
245
246 const Untagged = @Union(.@"extern", null, &.{ "int", "float" }, &.{ i32, f32 }, &.{ .{}, .{} });
247 var untagged = Untagged{ .int = 1 };
248 untagged.float = 2.0;
249 untagged.int = 3;
250 try testing.expectEqual(@as(i32, 3), untagged.int);
251
252 const PackedUntagged = @Union(.@"packed", null, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &.{ .{}, .{} });
253 var packed_untagged: PackedUntagged = .{ .signed = -1 };
254 _ = &packed_untagged;
255 try testing.expectEqual(@as(i32, -1), packed_untagged.signed);
256 try testing.expectEqual(~@as(u32, 0), packed_untagged.unsigned);
257
258 const Tag = @Enum(u1, .exhaustive, &.{ "signed", "unsigned" }, &.{ 0, 1 });
259 const Tagged = @Union(.auto, Tag, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &.{ .{}, .{} });
260 var tagged = Tagged{ .signed = -1 };
261 try testing.expectEqual(Tag.signed, @as(Tag, tagged));
262 tagged = .{ .unsigned = 1 };
263 try testing.expectEqual(Tag.unsigned, @as(Tag, tagged));
264}
265
266test "Type.Union from Type.Enum" {
267 const Tag = @Enum(u0, .exhaustive, &.{"working_as_expected"}, &.{0});
268 const T = @Union(.auto, Tag, &.{"working_as_expected"}, &.{u32}, &.{.{}});
269 _ = @typeInfo(T).@"union";
270}
271
272test "Type.Union from regular enum" {
273 const E = enum { working_as_expected };
274 const T = @Union(.auto, E, &.{"working_as_expected"}, &.{u32}, &.{.{}});
275 _ = @typeInfo(T).@"union";
276}
277
278test "Type.Union from empty regular enum" {
279 const E = enum {};
280 const U = @Union(.auto, E, &.{}, &.{}, &.{});
281 try testing.expectEqual(@sizeOf(U), 0);
282}
283
284test "Type.Union from empty Type.Enum" {
285 const E = @Enum(u0, .exhaustive, &.{}, &.{});
286 const U = @Union(.auto, E, &.{}, &.{}, &.{});
287 try testing.expectEqual(@sizeOf(U), 0);
288}
289
290test "Type.Fn" {
291 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
292
293 const some_opaque = opaque {};
294 const some_ptr = *some_opaque;
295
296 const A = @Fn(&.{ c_int, some_ptr }, &@splat(.{}), void, .{ .@"callconv" = .c });
297 comptime assert(A == fn (c_int, some_ptr) callconv(.c) void);
298
299 const B = @Fn(&.{ c_int, some_ptr, u32 }, &.{ .{}, .{ .@"noalias" = true }, .{} }, u64, .{});
300 comptime assert(B == fn (c_int, noalias some_ptr, u32) u64);
301
302 const C = @Fn(&.{?[*]u8}, &.{.{}}, *const anyopaque, .{ .@"callconv" = .c, .varargs = true });
303 comptime assert(C == fn (?[*]u8, ...) callconv(.c) *const anyopaque);
304}
305
306test "reified struct field name from optional payload" {
307 comptime {
308 const m_name: ?[1:0]u8 = "a".*;
309 if (m_name) |*name| {
310 const T = @Struct(.auto, null, &.{name}, &.{u8}, &.{.{}});
311 const t: T = .{ .a = 123 };
312 try std.testing.expect(t.a == 123);
313 }
314 }
315}
316
317test "reified union uses @alignOf" {
318 const S = struct {
319 fn CreateUnion(comptime T: type) type {
320 return @Union(.auto, null, &.{"field"}, &.{T}, &.{.{}});
321 }
322 };
323 _ = S.CreateUnion(struct {});
324}
325
326test "reified struct uses @alignOf" {
327 const S = struct {
328 fn NamespacedGlobals(comptime modules: anytype) type {
329 return @Struct(
330 .auto,
331 null,
332 &.{"globals"},
333 &.{modules.mach.globals},
334 &.{.{ .@"align" = @alignOf(modules.mach.globals) }},
335 );
336 }
337 };
338 _ = S.NamespacedGlobals(.{
339 .mach = .{
340 .globals = struct {},
341 },
342 });
343}
344
345test "empty struct assigned to reified struct field" {
346 const S = struct {
347 fn NamespacedComponents(comptime modules: anytype) type {
348 return @Struct(.auto, null, &.{"components"}, &.{@TypeOf(modules.components)}, &.{.{}});
349 }
350
351 fn namespacedComponents(comptime modules: anytype) NamespacedComponents(modules) {
352 var x: NamespacedComponents(modules) = undefined;
353 x.components = modules.components;
354 return x;
355 }
356 };
357 _ = S.namespacedComponents(.{
358 .components = .{
359 .location = struct {},
360 },
361 });
362}
363
364test "struct field names sliced at comptime from larger string" {
365 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
366
367 const text =
368 \\f1
369 \\f2
370 \\f3
371 ;
372 comptime {
373 var field_names: []const []const u8 = &.{};
374
375 var it = std.mem.tokenizeScalar(u8, text, '\n');
376 while (it.next()) |name| {
377 field_names = field_names ++ @as([]const []const u8, &.{name});
378 }
379
380 const T = @Struct(.auto, null, field_names, &@splat(usize), &@splat(.{}));
381 const gen_fields = @typeInfo(T).@"struct".fields;
382 try testing.expectEqual(3, gen_fields.len);
383 try testing.expectEqualStrings("f1", gen_fields[0].name);
384 try testing.expectEqualStrings("f2", gen_fields[1].name);
385 try testing.expectEqualStrings("f3", gen_fields[2].name);
386 }
387}
388
389test "matching captures causes opaque equivalence" {
390 const S = struct {
391 fn UnsignedId(comptime I: type) type {
392 const U = @Int(.unsigned, @typeInfo(I).int.bits);
393 return opaque {
394 fn id(x: U) U {
395 return x;
396 }
397 };
398 }
399 };
400
401 comptime assert(S.UnsignedId(u8) == S.UnsignedId(i8));
402 comptime assert(S.UnsignedId(u16) == S.UnsignedId(i16));
403 comptime assert(S.UnsignedId(u8) != S.UnsignedId(u16));
404
405 const a = S.UnsignedId(u8).id(123);
406 const b = S.UnsignedId(i8).id(123);
407 comptime assert(@TypeOf(a) == @TypeOf(b));
408 try testing.expect(a == b);
409}
410
411test "reify enum where fields refers to part of array" {
412 const field_names: [3][]const u8 = .{ "foo", "bar", undefined };
413 const field_values: [3]u8 = .{ undefined, 0, 1 };
414 const E = @Enum(u8, .exhaustive, field_names[0..2], field_values[1..3]);
415 var a: E = undefined;
416 var b: E = undefined;
417 a = .foo;
418 b = .bar;
419 try testing.expect(a == .foo);
420 try testing.expect(b == .bar);
421 try testing.expect(a != b);
422}
423
424test "undefined type value" {
425 const S = struct {
426 const undef_type: type = undefined;
427 };
428 comptime assert(@TypeOf(S.undef_type) == type);
429}
430
431test "reify struct with zero fields through const arrays" {
432 const names: [0][]const u8 = .{};
433 const types: [0]type = .{};
434 const attrs: [0]std.builtin.Type.StructField.Attributes = .{};
435 const S = @Struct(.auto, null, &names, &types, &attrs);
436 comptime assert(@typeInfo(S) == .@"struct");
437 comptime assert(@typeInfo(S).@"struct".fields.len == 0);
438}