aboutsummaryrefslogtreecommitdiff
path: root/test/behavior/type.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-04-29 15:54:04 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-29 15:54:04 -0700
commit4307436b9945f814ff5731981df1d19febf3ba0a (patch)
treeefaaec94a41d632d45f255d464d9787eb02c4c9b /test/behavior/type.zig
parent5a02c938dafdf2bb11b2350b6ad3161ef93744f0 (diff)
downloadzig-4307436b9945f814ff5731981df1d19febf3ba0a.tar.gz
zig-4307436b9945f814ff5731981df1d19febf3ba0a.zip
move behavior tests from test/stage1/ to test/
And fix test cases to make them pass. This is in preparation for starting to pass behavior tests with self-hosted.
Diffstat (limited to 'test/behavior/type.zig')
-rw-r--r--test/behavior/type.zig453
1 files changed, 453 insertions, 0 deletions
diff --git a/test/behavior/type.zig b/test/behavior/type.zig
new file mode 100644
index 0000000000..60c9117991
--- /dev/null
+++ b/test/behavior/type.zig
@@ -0,0 +1,453 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const TypeInfo = std.builtin.TypeInfo;
+const testing = std.testing;
+
+fn testTypes(comptime types: []const type) void {
+ inline for (types) |testType| {
+ testing.expect(testType == @Type(@typeInfo(testType)));
+ }
+}
+
+test "Type.MetaType" {
+ testing.expect(type == @Type(TypeInfo{ .Type = undefined }));
+ testTypes(&[_]type{type});
+}
+
+test "Type.Void" {
+ testing.expect(void == @Type(TypeInfo{ .Void = undefined }));
+ testTypes(&[_]type{void});
+}
+
+test "Type.Bool" {
+ testing.expect(bool == @Type(TypeInfo{ .Bool = undefined }));
+ testTypes(&[_]type{bool});
+}
+
+test "Type.NoReturn" {
+ testing.expect(noreturn == @Type(TypeInfo{ .NoReturn = undefined }));
+ testTypes(&[_]type{noreturn});
+}
+
+test "Type.Int" {
+ testing.expect(u1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .unsigned, .bits = 1 } }));
+ testing.expect(i1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .signed, .bits = 1 } }));
+ testing.expect(u8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .unsigned, .bits = 8 } }));
+ testing.expect(i8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .signed, .bits = 8 } }));
+ testing.expect(u64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .unsigned, .bits = 64 } }));
+ testing.expect(i64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .signedness = .signed, .bits = 64 } }));
+ testTypes(&[_]type{ u8, u32, i64 });
+}
+
+test "Type.Float" {
+ testing.expect(f16 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 16 } }));
+ testing.expect(f32 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 32 } }));
+ testing.expect(f64 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 64 } }));
+ testing.expect(f128 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 128 } }));
+ testTypes(&[_]type{ f16, f32, f64, f128 });
+}
+
+test "Type.Pointer" {
+ testTypes(&[_]type{
+ // One Value Pointer Types
+ *u8, *const u8,
+ *volatile u8, *const volatile u8,
+ *align(4) u8, *align(4) const u8,
+ *align(4) volatile u8, *align(4) const volatile u8,
+ *align(8) u8, *align(8) const u8,
+ *align(8) volatile u8, *align(8) const volatile u8,
+ *allowzero u8, *allowzero const u8,
+ *allowzero volatile u8, *allowzero const volatile u8,
+ *allowzero align(4) u8, *allowzero align(4) const u8,
+ *allowzero align(4) volatile u8, *allowzero align(4) const volatile u8,
+ // Many Values Pointer Types
+ [*]u8, [*]const u8,
+ [*]volatile u8, [*]const volatile u8,
+ [*]align(4) u8, [*]align(4) const u8,
+ [*]align(4) volatile u8, [*]align(4) const volatile u8,
+ [*]align(8) u8, [*]align(8) const u8,
+ [*]align(8) volatile u8, [*]align(8) const volatile u8,
+ [*]allowzero u8, [*]allowzero const u8,
+ [*]allowzero volatile u8, [*]allowzero const volatile u8,
+ [*]allowzero align(4) u8, [*]allowzero align(4) const u8,
+ [*]allowzero align(4) volatile u8, [*]allowzero align(4) const volatile u8,
+ // Slice Types
+ []u8, []const u8,
+ []volatile u8, []const volatile u8,
+ []align(4) u8, []align(4) const u8,
+ []align(4) volatile u8, []align(4) const volatile u8,
+ []align(8) u8, []align(8) const u8,
+ []align(8) volatile u8, []align(8) const volatile u8,
+ []allowzero u8, []allowzero const u8,
+ []allowzero volatile u8, []allowzero const volatile u8,
+ []allowzero align(4) u8, []allowzero align(4) const u8,
+ []allowzero align(4) volatile u8, []allowzero align(4) const volatile u8,
+ // C Pointer Types
+ [*c]u8, [*c]const u8,
+ [*c]volatile u8, [*c]const volatile u8,
+ [*c]align(4) u8, [*c]align(4) const u8,
+ [*c]align(4) volatile u8, [*c]align(4) const volatile u8,
+ [*c]align(8) u8, [*c]align(8) const u8,
+ [*c]align(8) volatile u8, [*c]align(8) const volatile u8,
+ });
+}
+
+test "Type.Array" {
+ testing.expect([123]u8 == @Type(TypeInfo{
+ .Array = TypeInfo.Array{
+ .len = 123,
+ .child = u8,
+ .sentinel = null,
+ },
+ }));
+ testing.expect([2]u32 == @Type(TypeInfo{
+ .Array = TypeInfo.Array{
+ .len = 2,
+ .child = u32,
+ .sentinel = null,
+ },
+ }));
+ testing.expect([2:0]u32 == @Type(TypeInfo{
+ .Array = TypeInfo.Array{
+ .len = 2,
+ .child = u32,
+ .sentinel = 0,
+ },
+ }));
+ testTypes(&[_]type{ [1]u8, [30]usize, [7]bool });
+}
+
+test "Type.ComptimeFloat" {
+ testTypes(&[_]type{comptime_float});
+}
+test "Type.ComptimeInt" {
+ testTypes(&[_]type{comptime_int});
+}
+test "Type.Undefined" {
+ testTypes(&[_]type{@TypeOf(undefined)});
+}
+test "Type.Null" {
+ testTypes(&[_]type{@TypeOf(null)});
+}
+test "@Type create slice with null sentinel" {
+ const Slice = @Type(TypeInfo{
+ .Pointer = .{
+ .size = .Slice,
+ .is_const = true,
+ .is_volatile = false,
+ .is_allowzero = false,
+ .alignment = 8,
+ .child = *i32,
+ .sentinel = null,
+ },
+ });
+ testing.expect(Slice == []align(8) const *i32);
+}
+test "@Type picks up the sentinel value from TypeInfo" {
+ testTypes(&[_]type{
+ [11:0]u8, [4:10]u8,
+ [*:0]u8, [*:0]const u8,
+ [*:0]volatile u8, [*:0]const volatile u8,
+ [*:0]align(4) u8, [*:0]align(4) const u8,
+ [*:0]align(4) volatile u8, [*:0]align(4) const volatile u8,
+ [*:0]align(8) u8, [*:0]align(8) const u8,
+ [*:0]align(8) volatile u8, [*:0]align(8) const volatile u8,
+ [*:0]allowzero u8, [*:0]allowzero const u8,
+ [*:0]allowzero volatile u8, [*:0]allowzero const volatile u8,
+ [*:0]allowzero align(4) u8, [*:0]allowzero align(4) const u8,
+ [*:0]allowzero align(4) volatile u8, [*:0]allowzero align(4) const volatile u8,
+ [*:5]allowzero align(4) volatile u8, [*:5]allowzero align(4) const volatile u8,
+ [:0]u8, [:0]const u8,
+ [:0]volatile u8, [:0]const volatile u8,
+ [:0]align(4) u8, [:0]align(4) const u8,
+ [:0]align(4) volatile u8, [:0]align(4) const volatile u8,
+ [:0]align(8) u8, [:0]align(8) const u8,
+ [:0]align(8) volatile u8, [:0]align(8) const volatile u8,
+ [:0]allowzero u8, [:0]allowzero const u8,
+ [:0]allowzero volatile u8, [:0]allowzero const volatile u8,
+ [:0]allowzero align(4) u8, [:0]allowzero align(4) const u8,
+ [:0]allowzero align(4) volatile u8, [:0]allowzero align(4) const volatile u8,
+ [:4]allowzero align(4) volatile u8, [:4]allowzero align(4) const volatile u8,
+ });
+}
+
+test "Type.Optional" {
+ testTypes(&[_]type{
+ ?u8,
+ ?*u8,
+ ?[]u8,
+ ?[*]u8,
+ ?[*c]u8,
+ });
+}
+
+test "Type.ErrorUnion" {
+ testTypes(&[_]type{
+ error{}!void,
+ error{Error}!void,
+ });
+}
+
+test "Type.Opaque" {
+ const Opaque = @Type(.{
+ .Opaque = .{
+ .decls = &[_]TypeInfo.Declaration{},
+ },
+ });
+ testing.expect(Opaque != opaque {});
+ testing.expectEqualSlices(
+ TypeInfo.Declaration,
+ &[_]TypeInfo.Declaration{},
+ @typeInfo(Opaque).Opaque.decls,
+ );
+}
+
+test "Type.Vector" {
+ testTypes(&[_]type{
+ @Vector(0, u8),
+ @Vector(4, u8),
+ @Vector(8, *u8),
+ std.meta.Vector(0, u8),
+ std.meta.Vector(4, u8),
+ std.meta.Vector(8, *u8),
+ });
+}
+
+test "Type.AnyFrame" {
+ testTypes(&[_]type{
+ anyframe,
+ anyframe->u8,
+ anyframe->anyframe->u8,
+ });
+}
+
+test "Type.EnumLiteral" {
+ testTypes(&[_]type{
+ @TypeOf(.Dummy),
+ });
+}
+
+fn add(a: i32, b: i32) i32 {
+ return a + b;
+}
+
+test "Type.Frame" {
+ testTypes(&[_]type{
+ @Frame(add),
+ });
+}
+
+test "Type.ErrorSet" {
+ // error sets don't compare equal so just check if they compile
+ _ = @Type(@typeInfo(error{}));
+ _ = @Type(@typeInfo(error{A}));
+ _ = @Type(@typeInfo(error{ A, B, C }));
+}
+
+test "Type.Struct" {
+ const A = @Type(@typeInfo(struct { x: u8, y: u32 }));
+ const infoA = @typeInfo(A).Struct;
+ testing.expectEqual(TypeInfo.ContainerLayout.Auto, infoA.layout);
+ testing.expectEqualSlices(u8, "x", infoA.fields[0].name);
+ testing.expectEqual(u8, infoA.fields[0].field_type);
+ testing.expectEqual(@as(?u8, null), infoA.fields[0].default_value);
+ testing.expectEqualSlices(u8, "y", infoA.fields[1].name);
+ testing.expectEqual(u32, infoA.fields[1].field_type);
+ testing.expectEqual(@as(?u32, null), infoA.fields[1].default_value);
+ testing.expectEqualSlices(TypeInfo.Declaration, &[_]TypeInfo.Declaration{}, infoA.decls);
+ testing.expectEqual(@as(bool, false), infoA.is_tuple);
+
+ var a = A{ .x = 0, .y = 1 };
+ testing.expectEqual(@as(u8, 0), a.x);
+ testing.expectEqual(@as(u32, 1), a.y);
+ a.y += 1;
+ testing.expectEqual(@as(u32, 2), a.y);
+
+ const B = @Type(@typeInfo(extern struct { x: u8, y: u32 = 5 }));
+ const infoB = @typeInfo(B).Struct;
+ testing.expectEqual(TypeInfo.ContainerLayout.Extern, infoB.layout);
+ testing.expectEqualSlices(u8, "x", infoB.fields[0].name);
+ testing.expectEqual(u8, infoB.fields[0].field_type);
+ testing.expectEqual(@as(?u8, null), infoB.fields[0].default_value);
+ testing.expectEqualSlices(u8, "y", infoB.fields[1].name);
+ testing.expectEqual(u32, infoB.fields[1].field_type);
+ testing.expectEqual(@as(?u32, 5), infoB.fields[1].default_value);
+ testing.expectEqual(@as(usize, 0), infoB.decls.len);
+ testing.expectEqual(@as(bool, false), infoB.is_tuple);
+
+ const C = @Type(@typeInfo(packed struct { x: u8 = 3, y: u32 = 5 }));
+ const infoC = @typeInfo(C).Struct;
+ testing.expectEqual(TypeInfo.ContainerLayout.Packed, infoC.layout);
+ testing.expectEqualSlices(u8, "x", infoC.fields[0].name);
+ testing.expectEqual(u8, infoC.fields[0].field_type);
+ testing.expectEqual(@as(?u8, 3), infoC.fields[0].default_value);
+ testing.expectEqualSlices(u8, "y", infoC.fields[1].name);
+ testing.expectEqual(u32, infoC.fields[1].field_type);
+ testing.expectEqual(@as(?u32, 5), infoC.fields[1].default_value);
+ testing.expectEqual(@as(usize, 0), infoC.decls.len);
+ testing.expectEqual(@as(bool, false), infoC.is_tuple);
+}
+
+test "Type.Enum" {
+ const Foo = @Type(.{
+ .Enum = .{
+ .layout = .Auto,
+ .tag_type = u8,
+ .fields = &[_]TypeInfo.EnumField{
+ .{ .name = "a", .value = 1 },
+ .{ .name = "b", .value = 5 },
+ },
+ .decls = &[_]TypeInfo.Declaration{},
+ .is_exhaustive = true,
+ },
+ });
+ testing.expectEqual(true, @typeInfo(Foo).Enum.is_exhaustive);
+ testing.expectEqual(@as(u8, 1), @enumToInt(Foo.a));
+ testing.expectEqual(@as(u8, 5), @enumToInt(Foo.b));
+ const Bar = @Type(.{
+ .Enum = .{
+ .layout = .Extern,
+ .tag_type = u32,
+ .fields = &[_]TypeInfo.EnumField{
+ .{ .name = "a", .value = 1 },
+ .{ .name = "b", .value = 5 },
+ },
+ .decls = &[_]TypeInfo.Declaration{},
+ .is_exhaustive = false,
+ },
+ });
+ testing.expectEqual(false, @typeInfo(Bar).Enum.is_exhaustive);
+ testing.expectEqual(@as(u32, 1), @enumToInt(Bar.a));
+ testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b));
+ testing.expectEqual(@as(u32, 6), @enumToInt(@intToEnum(Bar, 6)));
+}
+
+test "Type.Union" {
+ const Untagged = @Type(.{
+ .Union = .{
+ .layout = .Auto,
+ .tag_type = null,
+ .fields = &[_]TypeInfo.UnionField{
+ .{ .name = "int", .field_type = i32, .alignment = @alignOf(f32) },
+ .{ .name = "float", .field_type = f32, .alignment = @alignOf(f32) },
+ },
+ .decls = &[_]TypeInfo.Declaration{},
+ },
+ });
+ var untagged = Untagged{ .int = 1 };
+ untagged.float = 2.0;
+ untagged.int = 3;
+ testing.expectEqual(@as(i32, 3), untagged.int);
+
+ const PackedUntagged = @Type(.{
+ .Union = .{
+ .layout = .Packed,
+ .tag_type = null,
+ .fields = &[_]TypeInfo.UnionField{
+ .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) },
+ .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) },
+ },
+ .decls = &[_]TypeInfo.Declaration{},
+ },
+ });
+ var packed_untagged = PackedUntagged{ .signed = -1 };
+ testing.expectEqual(@as(i32, -1), packed_untagged.signed);
+ testing.expectEqual(~@as(u32, 0), packed_untagged.unsigned);
+
+ const Tag = @Type(.{
+ .Enum = .{
+ .layout = .Auto,
+ .tag_type = u1,
+ .fields = &[_]TypeInfo.EnumField{
+ .{ .name = "signed", .value = 0 },
+ .{ .name = "unsigned", .value = 1 },
+ },
+ .decls = &[_]TypeInfo.Declaration{},
+ .is_exhaustive = true,
+ },
+ });
+ const Tagged = @Type(.{
+ .Union = .{
+ .layout = .Auto,
+ .tag_type = Tag,
+ .fields = &[_]TypeInfo.UnionField{
+ .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) },
+ .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) },
+ },
+ .decls = &[_]TypeInfo.Declaration{},
+ },
+ });
+ var tagged = Tagged{ .signed = -1 };
+ testing.expectEqual(Tag.signed, tagged);
+ tagged = .{ .unsigned = 1 };
+ testing.expectEqual(Tag.unsigned, tagged);
+}
+
+test "Type.Union from Type.Enum" {
+ const Tag = @Type(.{
+ .Enum = .{
+ .layout = .Auto,
+ .tag_type = u0,
+ .fields = &[_]TypeInfo.EnumField{
+ .{ .name = "working_as_expected", .value = 0 },
+ },
+ .decls = &[_]TypeInfo.Declaration{},
+ .is_exhaustive = true,
+ },
+ });
+ const T = @Type(.{
+ .Union = .{
+ .layout = .Auto,
+ .tag_type = Tag,
+ .fields = &[_]TypeInfo.UnionField{
+ .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) },
+ },
+ .decls = &[_]TypeInfo.Declaration{},
+ },
+ });
+ _ = T;
+ _ = @typeInfo(T).Union;
+}
+
+test "Type.Union from regular enum" {
+ const E = enum { working_as_expected = 0 };
+ const T = @Type(.{
+ .Union = .{
+ .layout = .Auto,
+ .tag_type = E,
+ .fields = &[_]TypeInfo.UnionField{
+ .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) },
+ },
+ .decls = &[_]TypeInfo.Declaration{},
+ },
+ });
+ _ = T;
+ _ = @typeInfo(T).Union;
+}
+
+test "Type.Fn" {
+ // wasm doesn't support align attributes on functions
+ if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
+
+ const foo = struct {
+ fn func(a: usize, b: bool) align(4) callconv(.C) usize {
+ return 0;
+ }
+ }.func;
+ const Foo = @Type(@typeInfo(@TypeOf(foo)));
+ const foo_2: Foo = foo;
+}
+
+test "Type.BoundFn" {
+ // wasm doesn't support align attributes on functions
+ if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
+
+ const TestStruct = packed struct {
+ pub fn foo(self: *const @This()) align(4) callconv(.Unspecified) void {}
+ };
+ const test_instance: TestStruct = undefined;
+ testing.expect(std.meta.eql(
+ @typeName(@TypeOf(test_instance.foo)),
+ @typeName(@Type(@typeInfo(@TypeOf(test_instance.foo)))),
+ ));
+}