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}