diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-04-29 15:54:04 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-04-29 15:54:04 -0700 |
| commit | 4307436b9945f814ff5731981df1d19febf3ba0a (patch) | |
| tree | efaaec94a41d632d45f255d464d9787eb02c4c9b /test/behavior/type.zig | |
| parent | 5a02c938dafdf2bb11b2350b6ad3161ef93744f0 (diff) | |
| download | zig-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.zig | 453 |
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)))), + )); +} |
