mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
compiler_rt: move more functions to the stage2 section
also move more already-passing behavior tests to the passing section.
This commit is contained in:
parent
efb7148a45
commit
be5130ec53
@ -159,6 +159,18 @@ comptime {
|
||||
@export(__umodti3, .{ .name = "__umodti3", .linkage = linkage });
|
||||
}
|
||||
|
||||
const __truncdfhf2 = @import("compiler_rt/truncXfYf2.zig").__truncdfhf2;
|
||||
@export(__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = linkage });
|
||||
const __trunctfhf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfhf2;
|
||||
@export(__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = linkage });
|
||||
const __trunctfdf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfdf2;
|
||||
@export(__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = linkage });
|
||||
const __trunctfsf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfsf2;
|
||||
@export(__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = linkage });
|
||||
|
||||
const __truncdfsf2 = @import("compiler_rt/truncXfYf2.zig").__truncdfsf2;
|
||||
@export(__truncdfsf2, .{ .name = "__truncdfsf2", .linkage = linkage });
|
||||
|
||||
if (!builtin.zig_is_stage2) {
|
||||
if (!long_double_is_f128) {
|
||||
// TODO implement these
|
||||
@ -318,18 +330,6 @@ comptime {
|
||||
if (!is_test) {
|
||||
@export(__truncsfhf2, .{ .name = "__gnu_f2h_ieee", .linkage = linkage });
|
||||
}
|
||||
const __truncdfhf2 = @import("compiler_rt/truncXfYf2.zig").__truncdfhf2;
|
||||
@export(__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = linkage });
|
||||
const __trunctfhf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfhf2;
|
||||
@export(__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = linkage });
|
||||
const __trunctfdf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfdf2;
|
||||
@export(__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = linkage });
|
||||
const __trunctfsf2 = @import("compiler_rt/truncXfYf2.zig").__trunctfsf2;
|
||||
@export(__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = linkage });
|
||||
|
||||
const __truncdfsf2 = @import("compiler_rt/truncXfYf2.zig").__truncdfsf2;
|
||||
@export(__truncdfsf2, .{ .name = "__truncdfsf2", .linkage = linkage });
|
||||
|
||||
const __extendsfdf2 = @import("compiler_rt/extendXfYf2.zig").__extendsfdf2;
|
||||
@export(__extendsfdf2, .{ .name = "__extendsfdf2", .linkage = linkage });
|
||||
|
||||
|
||||
@ -7,23 +7,23 @@ const native_arch = builtin.cpu.arch;
|
||||
pub const F16T = if (native_arch.isAARCH64()) f16 else u16;
|
||||
|
||||
pub fn __truncsfhf2(a: f32) callconv(.C) F16T {
|
||||
return @bitCast(F16T, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f32, a }));
|
||||
return @bitCast(F16T, truncXfYf2(f16, f32, a));
|
||||
}
|
||||
|
||||
pub fn __truncdfhf2(a: f64) callconv(.C) F16T {
|
||||
return @bitCast(F16T, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f64, a }));
|
||||
return @bitCast(F16T, truncXfYf2(f16, f64, a));
|
||||
}
|
||||
|
||||
pub fn __trunctfhf2(a: f128) callconv(.C) F16T {
|
||||
return @bitCast(F16T, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f128, a }));
|
||||
return @bitCast(F16T, truncXfYf2(f16, f128, a));
|
||||
}
|
||||
|
||||
pub fn __trunctfsf2(a: f128) callconv(.C) f32 {
|
||||
return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f32, f128, a });
|
||||
return truncXfYf2(f32, f128, a);
|
||||
}
|
||||
|
||||
pub fn __trunctfdf2(a: f128) callconv(.C) f64 {
|
||||
return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f64, f128, a });
|
||||
return truncXfYf2(f64, f128, a);
|
||||
}
|
||||
|
||||
pub fn __trunctfxf2(a: f128) callconv(.C) c_longdouble {
|
||||
@ -32,25 +32,25 @@ pub fn __trunctfxf2(a: f128) callconv(.C) c_longdouble {
|
||||
}
|
||||
|
||||
pub fn __truncdfsf2(a: f64) callconv(.C) f32 {
|
||||
return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f32, f64, a });
|
||||
return truncXfYf2(f32, f64, a);
|
||||
}
|
||||
|
||||
pub fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 {
|
||||
@setRuntimeSafety(false);
|
||||
return @call(.{ .modifier = .always_inline }, __truncdfsf2, .{a});
|
||||
return truncXfYf2(f32, f64, a);
|
||||
}
|
||||
|
||||
pub fn __aeabi_d2h(a: f64) callconv(.AAPCS) u16 {
|
||||
@setRuntimeSafety(false);
|
||||
return @call(.{ .modifier = .always_inline }, __truncdfhf2, .{a});
|
||||
return @bitCast(F16T, truncXfYf2(f16, f64, a));
|
||||
}
|
||||
|
||||
pub fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 {
|
||||
@setRuntimeSafety(false);
|
||||
return @call(.{ .modifier = .always_inline }, __truncsfhf2, .{a});
|
||||
return @bitCast(F16T, truncXfYf2(f16, f32, a));
|
||||
}
|
||||
|
||||
fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
|
||||
inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
|
||||
const src_rep_t = std.meta.Int(.unsigned, @typeInfo(src_t).Float.bits);
|
||||
const dst_rep_t = std.meta.Int(.unsigned, @typeInfo(dst_t).Float.bits);
|
||||
const srcSigBits = std.math.floatMantissaBits(src_t);
|
||||
|
||||
@ -18,6 +18,8 @@ test {
|
||||
_ = @import("behavior/pub_enum.zig");
|
||||
_ = @import("behavior/slice_sentinel_comptime.zig");
|
||||
_ = @import("behavior/truncate.zig");
|
||||
_ = @import("behavior/type.zig");
|
||||
_ = @import("behavior/type_info.zig");
|
||||
_ = @import("behavior/usingnamespace.zig");
|
||||
|
||||
// Tests that pass for stage1, stage2 and the C backend, but not for the wasm backend
|
||||
@ -124,7 +126,6 @@ test {
|
||||
_ = @import("behavior/bugs/1025.zig");
|
||||
_ = @import("behavior/bugs/1076.zig");
|
||||
_ = @import("behavior/bugs/1120.zig");
|
||||
_ = @import("behavior/bugs/1322.zig");
|
||||
_ = @import("behavior/bugs/1421.zig");
|
||||
_ = @import("behavior/bugs/1442.zig");
|
||||
_ = @import("behavior/bugs/1607.zig");
|
||||
@ -186,8 +187,8 @@ test {
|
||||
_ = @import("behavior/truncate_stage1.zig");
|
||||
_ = @import("behavior/try.zig");
|
||||
_ = @import("behavior/tuple.zig");
|
||||
_ = @import("behavior/type.zig");
|
||||
_ = @import("behavior/type_info.zig");
|
||||
_ = @import("behavior/type_stage1.zig");
|
||||
_ = @import("behavior/type_info_stage1.zig");
|
||||
_ = @import("behavior/typename.zig");
|
||||
_ = @import("behavior/union_stage1.zig");
|
||||
_ = @import("behavior/union_with_members.zig");
|
||||
|
||||
@ -120,3 +120,18 @@ test "size of extern struct with 128-bit field" {
|
||||
}) == 32);
|
||||
}
|
||||
}
|
||||
|
||||
test "@ptrCast preserves alignment of bigger source" {
|
||||
var x: u32 align(16) = 1234;
|
||||
const ptr = @ptrCast(*u8, &x);
|
||||
try expect(@TypeOf(ptr) == *align(16) u8);
|
||||
}
|
||||
|
||||
test "alignstack" {
|
||||
try expect(fnWithAlignedStack() == 1234);
|
||||
}
|
||||
|
||||
fn fnWithAlignedStack() i32 {
|
||||
@setAlignStack(256);
|
||||
return 1234;
|
||||
}
|
||||
|
||||
@ -20,25 +20,6 @@ test "function alignment" {
|
||||
noop4();
|
||||
}
|
||||
|
||||
var baz: packed struct {
|
||||
a: u32,
|
||||
b: u32,
|
||||
} = undefined;
|
||||
|
||||
test "packed struct alignment" {
|
||||
try expect(@TypeOf(&baz.b) == *align(1) u32);
|
||||
}
|
||||
|
||||
const blah: packed struct {
|
||||
a: u3,
|
||||
b: u3,
|
||||
c: u2,
|
||||
} = undefined;
|
||||
|
||||
test "bit field alignment" {
|
||||
try expect(@TypeOf(&blah.b) == *align(1:3:1) const u3);
|
||||
}
|
||||
|
||||
test "implicitly decreasing fn alignment" {
|
||||
// function alignment is a compile error on wasm32/wasm64
|
||||
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
|
||||
@ -90,12 +71,6 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
|
||||
return 0x1;
|
||||
}
|
||||
|
||||
test "@ptrCast preserves alignment of bigger source" {
|
||||
var x: u32 align(16) = 1234;
|
||||
const ptr = @ptrCast(*u8, &x);
|
||||
try expect(@TypeOf(ptr) == *align(16) u8);
|
||||
}
|
||||
|
||||
test "runtime known array index has best alignment possible" {
|
||||
// take full advantage of over-alignment
|
||||
var array align(4) = [_]u8{ 1, 2, 3, 4 };
|
||||
@ -134,15 +109,6 @@ fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) !void {
|
||||
comptime try expect(@TypeOf(&ptr[index]) == T);
|
||||
}
|
||||
|
||||
test "alignstack" {
|
||||
try expect(fnWithAlignedStack() == 1234);
|
||||
}
|
||||
|
||||
fn fnWithAlignedStack() i32 {
|
||||
@setAlignStack(256);
|
||||
return 1234;
|
||||
}
|
||||
|
||||
test "alignment of function with c calling convention" {
|
||||
var runtime_nothing = nothing;
|
||||
const casted1 = @ptrCast(*const u8, runtime_nothing);
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
const std = @import("std");
|
||||
|
||||
const B = union(enum) {
|
||||
c: C,
|
||||
None,
|
||||
};
|
||||
|
||||
const A = struct {
|
||||
b: B,
|
||||
};
|
||||
|
||||
const C = struct {};
|
||||
|
||||
test "tagged union with all void fields but a meaningful tag" {
|
||||
var a: A = A{ .b = B{ .c = C{} } };
|
||||
try std.testing.expect(@as(std.meta.Tag(B), a.b) == std.meta.Tag(B).c);
|
||||
a = A{ .b = B.None };
|
||||
try std.testing.expect(@as(std.meta.Tag(B), a.b) == std.meta.Tag(B).None);
|
||||
}
|
||||
@ -197,3 +197,71 @@ test "cast between *[N]void and []void" {
|
||||
var b: []void = &a;
|
||||
try expect(b.len == 4);
|
||||
}
|
||||
|
||||
test "peer resolve arrays of different size to const slice" {
|
||||
try expect(mem.eql(u8, boolToStr(true), "true"));
|
||||
try expect(mem.eql(u8, boolToStr(false), "false"));
|
||||
comptime try expect(mem.eql(u8, boolToStr(true), "true"));
|
||||
comptime try expect(mem.eql(u8, boolToStr(false), "false"));
|
||||
}
|
||||
fn boolToStr(b: bool) []const u8 {
|
||||
return if (b) "true" else "false";
|
||||
}
|
||||
|
||||
test "cast f16 to wider types" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
var x: f16 = 1234.0;
|
||||
try expect(@as(f32, 1234.0) == x);
|
||||
try expect(@as(f64, 1234.0) == x);
|
||||
try expect(@as(f128, 1234.0) == x);
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "cast f128 to narrower types" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
var x: f128 = 1234.0;
|
||||
try expect(@as(f16, 1234.0) == @floatCast(f16, x));
|
||||
try expect(@as(f32, 1234.0) == @floatCast(f32, x));
|
||||
try expect(@as(f64, 1234.0) == @floatCast(f64, x));
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "peer type resolution: unreachable, null, slice" {
|
||||
const S = struct {
|
||||
fn doTheTest(num: usize, word: []const u8) !void {
|
||||
const result = switch (num) {
|
||||
0 => null,
|
||||
1 => word,
|
||||
else => unreachable,
|
||||
};
|
||||
try expect(mem.eql(u8, result.?, "hi"));
|
||||
}
|
||||
};
|
||||
try S.doTheTest(1, "hi");
|
||||
}
|
||||
|
||||
test "cast i8 fn call peers to i32 result" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
var cond = true;
|
||||
const value: i32 = if (cond) smallBoi() else bigBoi();
|
||||
try expect(value == 123);
|
||||
}
|
||||
fn smallBoi() i8 {
|
||||
return 123;
|
||||
}
|
||||
fn bigBoi() i16 {
|
||||
return 1234;
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
@ -15,16 +15,6 @@ fn testCastIntToErr(err: anyerror) !void {
|
||||
try expect(error.ItBroke == y);
|
||||
}
|
||||
|
||||
test "peer resolve arrays of different size to const slice" {
|
||||
try expect(mem.eql(u8, boolToStr(true), "true"));
|
||||
try expect(mem.eql(u8, boolToStr(false), "false"));
|
||||
comptime try expect(mem.eql(u8, boolToStr(true), "true"));
|
||||
comptime try expect(mem.eql(u8, boolToStr(false), "false"));
|
||||
}
|
||||
fn boolToStr(b: bool) []const u8 {
|
||||
return if (b) "true" else "false";
|
||||
}
|
||||
|
||||
test "peer resolve array and const slice" {
|
||||
try testPeerResolveArrayConstSlice(true);
|
||||
comptime try testPeerResolveArrayConstSlice(true);
|
||||
@ -174,32 +164,6 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
|
||||
try expect(mem.eql(u8, std.mem.sliceTo(@ptrCast([*:0]const u8, x[0].?), 0), "window name"));
|
||||
}
|
||||
|
||||
test "cast f16 to wider types" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
var x: f16 = 1234.0;
|
||||
try std.testing.expectEqual(@as(f32, 1234.0), x);
|
||||
try std.testing.expectEqual(@as(f64, 1234.0), x);
|
||||
try std.testing.expectEqual(@as(f128, 1234.0), x);
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "cast f128 to narrower types" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
var x: f128 = 1234.0;
|
||||
try std.testing.expectEqual(@as(f16, 1234.0), @floatCast(f16, x));
|
||||
try std.testing.expectEqual(@as(f32, 1234.0), @floatCast(f32, x));
|
||||
try std.testing.expectEqual(@as(f64, 1234.0), @floatCast(f64, x));
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "vector casts" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
@ -250,20 +214,6 @@ test "@floatCast cast down" {
|
||||
}
|
||||
}
|
||||
|
||||
test "peer type resolution: unreachable, null, slice" {
|
||||
const S = struct {
|
||||
fn doTheTest(num: usize, word: []const u8) !void {
|
||||
const result = switch (num) {
|
||||
0 => null,
|
||||
1 => word,
|
||||
else => unreachable,
|
||||
};
|
||||
try expect(mem.eql(u8, result.?, "hi"));
|
||||
}
|
||||
};
|
||||
try S.doTheTest(1, "hi");
|
||||
}
|
||||
|
||||
test "peer type resolution: unreachable, error set, unreachable" {
|
||||
const Error = error{
|
||||
FileDescriptorAlreadyPresentInSet,
|
||||
@ -374,24 +324,6 @@ test "type coercion related to sentinel-termination" {
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "cast i8 fn call peers to i32 result" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
var cond = true;
|
||||
const value: i32 = if (cond) smallBoi() else bigBoi();
|
||||
try expect(value == 123);
|
||||
}
|
||||
fn smallBoi() i8 {
|
||||
return 123;
|
||||
}
|
||||
fn bigBoi() i16 {
|
||||
return 1234;
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "peer type resolution implicit cast to return type" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
|
||||
@ -2,3 +2,62 @@ const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const expectError = std.testing.expectError;
|
||||
|
||||
test "break and continue inside loop inside defer expression" {
|
||||
testBreakContInDefer(10);
|
||||
comptime testBreakContInDefer(10);
|
||||
}
|
||||
|
||||
fn testBreakContInDefer(x: usize) void {
|
||||
defer {
|
||||
var i: usize = 0;
|
||||
while (i < x) : (i += 1) {
|
||||
if (i < 5) continue;
|
||||
if (i == 5) break;
|
||||
}
|
||||
expect(i == 5) catch @panic("test failure");
|
||||
}
|
||||
}
|
||||
|
||||
test "defer and labeled break" {
|
||||
var i = @as(usize, 0);
|
||||
|
||||
blk: {
|
||||
defer i += 1;
|
||||
break :blk;
|
||||
}
|
||||
|
||||
try expect(i == 1);
|
||||
}
|
||||
|
||||
test "errdefer does not apply to fn inside fn" {
|
||||
if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);
|
||||
}
|
||||
|
||||
fn testNestedFnErrDefer() anyerror!void {
|
||||
var a: i32 = 0;
|
||||
errdefer a += 1;
|
||||
const S = struct {
|
||||
fn baz() anyerror {
|
||||
return error.Bad;
|
||||
}
|
||||
};
|
||||
return S.baz();
|
||||
}
|
||||
|
||||
test "return variable while defer expression in scope to modify it" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
try expect(notNull().? == 1);
|
||||
}
|
||||
|
||||
fn notNull() ?u8 {
|
||||
var res: ?u8 = 1;
|
||||
defer res = null;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
@ -38,65 +38,6 @@ test "mixing normal and error defers" {
|
||||
try expect(result[2] == 'a');
|
||||
}
|
||||
|
||||
test "break and continue inside loop inside defer expression" {
|
||||
testBreakContInDefer(10);
|
||||
comptime testBreakContInDefer(10);
|
||||
}
|
||||
|
||||
fn testBreakContInDefer(x: usize) void {
|
||||
defer {
|
||||
var i: usize = 0;
|
||||
while (i < x) : (i += 1) {
|
||||
if (i < 5) continue;
|
||||
if (i == 5) break;
|
||||
}
|
||||
expect(i == 5) catch @panic("test failure");
|
||||
}
|
||||
}
|
||||
|
||||
test "defer and labeled break" {
|
||||
var i = @as(usize, 0);
|
||||
|
||||
blk: {
|
||||
defer i += 1;
|
||||
break :blk;
|
||||
}
|
||||
|
||||
try expect(i == 1);
|
||||
}
|
||||
|
||||
test "errdefer does not apply to fn inside fn" {
|
||||
if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);
|
||||
}
|
||||
|
||||
fn testNestedFnErrDefer() anyerror!void {
|
||||
var a: i32 = 0;
|
||||
errdefer a += 1;
|
||||
const S = struct {
|
||||
fn baz() anyerror {
|
||||
return error.Bad;
|
||||
}
|
||||
};
|
||||
return S.baz();
|
||||
}
|
||||
|
||||
test "return variable while defer expression in scope to modify it" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
try expect(notNull().? == 1);
|
||||
}
|
||||
|
||||
fn notNull() ?u8 {
|
||||
var res: ?u8 = 1;
|
||||
defer res = null;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "errdefer with payload" {
|
||||
const S = struct {
|
||||
fn foo() !i32 {
|
||||
|
||||
@ -467,3 +467,28 @@ test "comptime shlWithOverflow" {
|
||||
|
||||
try expect(ct_shifted == rt_shifted);
|
||||
}
|
||||
|
||||
test "const ptr to variable data changes at runtime" {
|
||||
try expect(foo_ref.name[0] == 'a');
|
||||
foo_ref.name = "b";
|
||||
try expect(foo_ref.name[0] == 'b');
|
||||
}
|
||||
|
||||
const Foo = struct {
|
||||
name: []const u8,
|
||||
};
|
||||
|
||||
var foo_contents = Foo{ .name = "a" };
|
||||
const foo_ref = &foo_contents;
|
||||
|
||||
test "runtime 128 bit integer division" {
|
||||
var a: u128 = 152313999999999991610955792383;
|
||||
var b: u128 = 10000000000000000000;
|
||||
var c = a / b;
|
||||
try expect(c == 15231399999);
|
||||
}
|
||||
|
||||
test "@tagName of @typeInfo" {
|
||||
const str = @tagName(@typeInfo(u8));
|
||||
try expect(std.mem.eql(u8, str, "Int"));
|
||||
}
|
||||
|
||||
@ -86,19 +86,6 @@ fn testCompTimeUIntComparisons(x: u32) void {
|
||||
}
|
||||
}
|
||||
|
||||
test "const ptr to variable data changes at runtime" {
|
||||
try expect(foo_ref.name[0] == 'a');
|
||||
foo_ref.name = "b";
|
||||
try expect(foo_ref.name[0] == 'b');
|
||||
}
|
||||
|
||||
const Foo = struct {
|
||||
name: []const u8,
|
||||
};
|
||||
|
||||
var foo_contents = Foo{ .name = "a" };
|
||||
const foo_ref = &foo_contents;
|
||||
|
||||
const hi1 = "hi";
|
||||
const hi2 = hi1;
|
||||
test "const global shares pointer with other same one" {
|
||||
@ -162,13 +149,6 @@ test "const ptr to comptime mutable data is not memoized" {
|
||||
}
|
||||
}
|
||||
|
||||
test "runtime 128 bit integer division" {
|
||||
var a: u128 = 152313999999999991610955792383;
|
||||
var b: u128 = 10000000000000000000;
|
||||
var c = a / b;
|
||||
try expect(c == 15231399999);
|
||||
}
|
||||
|
||||
const Wrapper = struct {
|
||||
T: type,
|
||||
};
|
||||
@ -196,11 +176,6 @@ test "call method with comptime pass-by-non-copying-value self parameter" {
|
||||
try expect(b == 2);
|
||||
}
|
||||
|
||||
test "@tagName of @typeInfo" {
|
||||
const str = @tagName(@typeInfo(u8));
|
||||
try expect(std.mem.eql(u8, str, "Int"));
|
||||
}
|
||||
|
||||
test "setting backward branch quota just before a generic fn call" {
|
||||
@setEvalBranchQuota(1001);
|
||||
loopNTimes(1001);
|
||||
|
||||
@ -199,3 +199,30 @@ test "struct field init with catch" {
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "packed struct field alignment" {
|
||||
const Stage1 = struct {
|
||||
var baz: packed struct {
|
||||
a: u32,
|
||||
b: u32,
|
||||
} = undefined;
|
||||
};
|
||||
const Stage2 = struct {
|
||||
var baz: packed struct {
|
||||
a: u32,
|
||||
b: u32 align(1),
|
||||
} = undefined;
|
||||
};
|
||||
const S = if (builtin.zig_is_stage2) Stage2 else Stage1;
|
||||
try expect(@TypeOf(&S.baz.b) == *align(1) u32);
|
||||
}
|
||||
|
||||
const blah: packed struct {
|
||||
a: u3,
|
||||
b: u3,
|
||||
c: u2,
|
||||
} = undefined;
|
||||
|
||||
test "bit field alignment" {
|
||||
try expect(@TypeOf(&blah.b) == *align(1:3:1) const u3);
|
||||
}
|
||||
|
||||
@ -39,84 +39,6 @@ test "Type.Int" {
|
||||
try testTypes(&[_]type{ u8, u32, i64 });
|
||||
}
|
||||
|
||||
test "Type.Float" {
|
||||
try testing.expect(f16 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 16 } }));
|
||||
try testing.expect(f32 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 32 } }));
|
||||
try testing.expect(f64 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 64 } }));
|
||||
try testing.expect(f128 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 128 } }));
|
||||
try testTypes(&[_]type{ f16, f32, f64, f128 });
|
||||
}
|
||||
|
||||
test "Type.Pointer" {
|
||||
try 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" {
|
||||
try testing.expect([123]u8 == @Type(TypeInfo{
|
||||
.Array = TypeInfo.Array{
|
||||
.len = 123,
|
||||
.child = u8,
|
||||
.sentinel = null,
|
||||
},
|
||||
}));
|
||||
try testing.expect([2]u32 == @Type(TypeInfo{
|
||||
.Array = TypeInfo.Array{
|
||||
.len = 2,
|
||||
.child = u32,
|
||||
.sentinel = null,
|
||||
},
|
||||
}));
|
||||
try testing.expect([2:0]u32 == @Type(TypeInfo{
|
||||
.Array = TypeInfo.Array{
|
||||
.len = 2,
|
||||
.child = u32,
|
||||
.sentinel = 0,
|
||||
},
|
||||
}));
|
||||
try testTypes(&[_]type{ [1]u8, [30]usize, [7]bool });
|
||||
}
|
||||
|
||||
test "Type.ComptimeFloat" {
|
||||
try testTypes(&[_]type{comptime_float});
|
||||
}
|
||||
@ -129,331 +51,9 @@ test "Type.Undefined" {
|
||||
test "Type.Null" {
|
||||
try 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,
|
||||
.address_space = .generic,
|
||||
.child = *i32,
|
||||
.sentinel = null,
|
||||
},
|
||||
});
|
||||
try testing.expect(Slice == []align(8) const *i32);
|
||||
}
|
||||
test "@Type picks up the sentinel value from TypeInfo" {
|
||||
try 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" {
|
||||
try testTypes(&[_]type{
|
||||
?u8,
|
||||
?*u8,
|
||||
?[]u8,
|
||||
?[*]u8,
|
||||
?[*c]u8,
|
||||
});
|
||||
}
|
||||
|
||||
test "Type.ErrorUnion" {
|
||||
try testTypes(&[_]type{
|
||||
error{}!void,
|
||||
error{Error}!void,
|
||||
});
|
||||
}
|
||||
|
||||
test "Type.Opaque" {
|
||||
const Opaque = @Type(.{
|
||||
.Opaque = .{
|
||||
.decls = &[_]TypeInfo.Declaration{},
|
||||
},
|
||||
});
|
||||
try testing.expect(Opaque != opaque {});
|
||||
try testing.expectEqualSlices(
|
||||
TypeInfo.Declaration,
|
||||
&[_]TypeInfo.Declaration{},
|
||||
@typeInfo(Opaque).Opaque.decls,
|
||||
);
|
||||
}
|
||||
|
||||
test "Type.Vector" {
|
||||
try 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" {
|
||||
try testTypes(&[_]type{
|
||||
anyframe,
|
||||
anyframe->u8,
|
||||
anyframe->anyframe->u8,
|
||||
});
|
||||
}
|
||||
|
||||
test "Type.EnumLiteral" {
|
||||
try testTypes(&[_]type{
|
||||
@TypeOf(.Dummy),
|
||||
});
|
||||
}
|
||||
|
||||
fn add(a: i32, b: i32) i32 {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
test "Type.Frame" {
|
||||
try 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;
|
||||
try testing.expectEqual(TypeInfo.ContainerLayout.Auto, infoA.layout);
|
||||
try testing.expectEqualSlices(u8, "x", infoA.fields[0].name);
|
||||
try testing.expectEqual(u8, infoA.fields[0].field_type);
|
||||
try testing.expectEqual(@as(?u8, null), infoA.fields[0].default_value);
|
||||
try testing.expectEqualSlices(u8, "y", infoA.fields[1].name);
|
||||
try testing.expectEqual(u32, infoA.fields[1].field_type);
|
||||
try testing.expectEqual(@as(?u32, null), infoA.fields[1].default_value);
|
||||
try testing.expectEqualSlices(TypeInfo.Declaration, &[_]TypeInfo.Declaration{}, infoA.decls);
|
||||
try testing.expectEqual(@as(bool, false), infoA.is_tuple);
|
||||
|
||||
var a = A{ .x = 0, .y = 1 };
|
||||
try testing.expectEqual(@as(u8, 0), a.x);
|
||||
try testing.expectEqual(@as(u32, 1), a.y);
|
||||
a.y += 1;
|
||||
try testing.expectEqual(@as(u32, 2), a.y);
|
||||
|
||||
const B = @Type(@typeInfo(extern struct { x: u8, y: u32 = 5 }));
|
||||
const infoB = @typeInfo(B).Struct;
|
||||
try testing.expectEqual(TypeInfo.ContainerLayout.Extern, infoB.layout);
|
||||
try testing.expectEqualSlices(u8, "x", infoB.fields[0].name);
|
||||
try testing.expectEqual(u8, infoB.fields[0].field_type);
|
||||
try testing.expectEqual(@as(?u8, null), infoB.fields[0].default_value);
|
||||
try testing.expectEqualSlices(u8, "y", infoB.fields[1].name);
|
||||
try testing.expectEqual(u32, infoB.fields[1].field_type);
|
||||
try testing.expectEqual(@as(?u32, 5), infoB.fields[1].default_value);
|
||||
try testing.expectEqual(@as(usize, 0), infoB.decls.len);
|
||||
try 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;
|
||||
try testing.expectEqual(TypeInfo.ContainerLayout.Packed, infoC.layout);
|
||||
try testing.expectEqualSlices(u8, "x", infoC.fields[0].name);
|
||||
try testing.expectEqual(u8, infoC.fields[0].field_type);
|
||||
try testing.expectEqual(@as(?u8, 3), infoC.fields[0].default_value);
|
||||
try testing.expectEqualSlices(u8, "y", infoC.fields[1].name);
|
||||
try testing.expectEqual(u32, infoC.fields[1].field_type);
|
||||
try testing.expectEqual(@as(?u32, 5), infoC.fields[1].default_value);
|
||||
try testing.expectEqual(@as(usize, 0), infoC.decls.len);
|
||||
try 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,
|
||||
},
|
||||
});
|
||||
try testing.expectEqual(true, @typeInfo(Foo).Enum.is_exhaustive);
|
||||
try testing.expectEqual(@as(u8, 1), @enumToInt(Foo.a));
|
||||
try 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,
|
||||
},
|
||||
});
|
||||
try testing.expectEqual(false, @typeInfo(Bar).Enum.is_exhaustive);
|
||||
try testing.expectEqual(@as(u32, 1), @enumToInt(Bar.a));
|
||||
try testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b));
|
||||
try 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;
|
||||
try 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 };
|
||||
try testing.expectEqual(@as(i32, -1), packed_untagged.signed);
|
||||
try 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 };
|
||||
try testing.expectEqual(Tag.signed, tagged);
|
||||
tagged = .{ .unsigned = 1 };
|
||||
try 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 };
|
||||
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 {
|
||||
_ = a;
|
||||
_ = b;
|
||||
return 0;
|
||||
}
|
||||
}.func;
|
||||
const Foo = @Type(@typeInfo(@TypeOf(foo)));
|
||||
const foo_2: Foo = foo;
|
||||
_ = foo_2;
|
||||
}
|
||||
|
||||
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 {
|
||||
_ = self;
|
||||
}
|
||||
};
|
||||
const test_instance: TestStruct = undefined;
|
||||
try testing.expect(std.meta.eql(
|
||||
@typeName(@TypeOf(test_instance.foo)),
|
||||
@typeName(@Type(@typeInfo(@TypeOf(test_instance.foo)))),
|
||||
));
|
||||
}
|
||||
|
||||
@ -8,18 +8,6 @@ const TypeId = std.builtin.TypeId;
|
||||
const expect = std.testing.expect;
|
||||
const expectEqualStrings = std.testing.expectEqualStrings;
|
||||
|
||||
test "type info: tag type, void info" {
|
||||
try testBasic();
|
||||
comptime try testBasic();
|
||||
}
|
||||
|
||||
fn testBasic() !void {
|
||||
try expect(@typeInfo(TypeInfo).Union.tag_type == TypeId);
|
||||
const void_info = @typeInfo(void);
|
||||
try expect(void_info == TypeId.Void);
|
||||
try expect(void_info.Void == {});
|
||||
}
|
||||
|
||||
test "type info: integer, floating point type info" {
|
||||
try testIntFloat();
|
||||
comptime try testIntFloat();
|
||||
@ -36,107 +24,6 @@ fn testIntFloat() !void {
|
||||
try expect(f64_info.Float.bits == 64);
|
||||
}
|
||||
|
||||
test "type info: pointer type info" {
|
||||
try testPointer();
|
||||
comptime try testPointer();
|
||||
}
|
||||
|
||||
fn testPointer() !void {
|
||||
const u32_ptr_info = @typeInfo(*u32);
|
||||
try expect(u32_ptr_info == .Pointer);
|
||||
try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
|
||||
try expect(u32_ptr_info.Pointer.is_const == false);
|
||||
try expect(u32_ptr_info.Pointer.is_volatile == false);
|
||||
try expect(u32_ptr_info.Pointer.alignment == @alignOf(u32));
|
||||
try expect(u32_ptr_info.Pointer.child == u32);
|
||||
try expect(u32_ptr_info.Pointer.sentinel == null);
|
||||
}
|
||||
|
||||
test "type info: unknown length pointer type info" {
|
||||
try testUnknownLenPtr();
|
||||
comptime try testUnknownLenPtr();
|
||||
}
|
||||
|
||||
fn testUnknownLenPtr() !void {
|
||||
const u32_ptr_info = @typeInfo([*]const volatile f64);
|
||||
try expect(u32_ptr_info == .Pointer);
|
||||
try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
|
||||
try expect(u32_ptr_info.Pointer.is_const == true);
|
||||
try expect(u32_ptr_info.Pointer.is_volatile == true);
|
||||
try expect(u32_ptr_info.Pointer.sentinel == null);
|
||||
try expect(u32_ptr_info.Pointer.alignment == @alignOf(f64));
|
||||
try expect(u32_ptr_info.Pointer.child == f64);
|
||||
}
|
||||
|
||||
test "type info: null terminated pointer type info" {
|
||||
try testNullTerminatedPtr();
|
||||
comptime try testNullTerminatedPtr();
|
||||
}
|
||||
|
||||
fn testNullTerminatedPtr() !void {
|
||||
const ptr_info = @typeInfo([*:0]u8);
|
||||
try expect(ptr_info == .Pointer);
|
||||
try expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
|
||||
try expect(ptr_info.Pointer.is_const == false);
|
||||
try expect(ptr_info.Pointer.is_volatile == false);
|
||||
try expect(ptr_info.Pointer.sentinel.? == 0);
|
||||
|
||||
try expect(@typeInfo([:0]u8).Pointer.sentinel != null);
|
||||
}
|
||||
|
||||
test "type info: C pointer type info" {
|
||||
try testCPtr();
|
||||
comptime try testCPtr();
|
||||
}
|
||||
|
||||
fn testCPtr() !void {
|
||||
const ptr_info = @typeInfo([*c]align(4) const i8);
|
||||
try expect(ptr_info == .Pointer);
|
||||
try expect(ptr_info.Pointer.size == .C);
|
||||
try expect(ptr_info.Pointer.is_const);
|
||||
try expect(!ptr_info.Pointer.is_volatile);
|
||||
try expect(ptr_info.Pointer.alignment == 4);
|
||||
try expect(ptr_info.Pointer.child == i8);
|
||||
}
|
||||
|
||||
test "type info: slice type info" {
|
||||
try testSlice();
|
||||
comptime try testSlice();
|
||||
}
|
||||
|
||||
fn testSlice() !void {
|
||||
const u32_slice_info = @typeInfo([]u32);
|
||||
try expect(u32_slice_info == .Pointer);
|
||||
try expect(u32_slice_info.Pointer.size == .Slice);
|
||||
try expect(u32_slice_info.Pointer.is_const == false);
|
||||
try expect(u32_slice_info.Pointer.is_volatile == false);
|
||||
try expect(u32_slice_info.Pointer.alignment == 4);
|
||||
try expect(u32_slice_info.Pointer.child == u32);
|
||||
}
|
||||
|
||||
test "type info: array type info" {
|
||||
try testArray();
|
||||
comptime try testArray();
|
||||
}
|
||||
|
||||
fn testArray() !void {
|
||||
{
|
||||
const info = @typeInfo([42]u8);
|
||||
try expect(info == .Array);
|
||||
try expect(info.Array.len == 42);
|
||||
try expect(info.Array.child == u8);
|
||||
try expect(info.Array.sentinel == null);
|
||||
}
|
||||
|
||||
{
|
||||
const info = @typeInfo([10:0]u8);
|
||||
try expect(info.Array.len == 10);
|
||||
try expect(info.Array.child == u8);
|
||||
try expect(info.Array.sentinel.? == @as(u8, 0));
|
||||
try expect(@sizeOf([10:0]u8) == info.Array.len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: optional type info" {
|
||||
try testOptional();
|
||||
comptime try testOptional();
|
||||
@ -147,344 +34,3 @@ fn testOptional() !void {
|
||||
try expect(null_info == .Optional);
|
||||
try expect(null_info.Optional.child == void);
|
||||
}
|
||||
|
||||
test "type info: error set, error union info" {
|
||||
try testErrorSet();
|
||||
comptime try testErrorSet();
|
||||
}
|
||||
|
||||
fn testErrorSet() !void {
|
||||
const TestErrorSet = error{
|
||||
First,
|
||||
Second,
|
||||
Third,
|
||||
};
|
||||
|
||||
const error_set_info = @typeInfo(TestErrorSet);
|
||||
try expect(error_set_info == .ErrorSet);
|
||||
try expect(error_set_info.ErrorSet.?.len == 3);
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "First"));
|
||||
|
||||
const error_union_info = @typeInfo(TestErrorSet!usize);
|
||||
try expect(error_union_info == .ErrorUnion);
|
||||
try expect(error_union_info.ErrorUnion.error_set == TestErrorSet);
|
||||
try expect(error_union_info.ErrorUnion.payload == usize);
|
||||
|
||||
const global_info = @typeInfo(anyerror);
|
||||
try expect(global_info == .ErrorSet);
|
||||
try expect(global_info.ErrorSet == null);
|
||||
}
|
||||
|
||||
test "type info: enum info" {
|
||||
try testEnum();
|
||||
comptime try testEnum();
|
||||
}
|
||||
|
||||
fn testEnum() !void {
|
||||
const Os = enum {
|
||||
Windows,
|
||||
Macos,
|
||||
Linux,
|
||||
FreeBSD,
|
||||
};
|
||||
|
||||
const os_info = @typeInfo(Os);
|
||||
try expect(os_info == .Enum);
|
||||
try expect(os_info.Enum.layout == .Auto);
|
||||
try expect(os_info.Enum.fields.len == 4);
|
||||
try expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
|
||||
try expect(os_info.Enum.fields[3].value == 3);
|
||||
try expect(os_info.Enum.tag_type == u2);
|
||||
try expect(os_info.Enum.decls.len == 0);
|
||||
}
|
||||
|
||||
test "type info: union info" {
|
||||
try testUnion();
|
||||
comptime try testUnion();
|
||||
}
|
||||
|
||||
fn testUnion() !void {
|
||||
const typeinfo_info = @typeInfo(TypeInfo);
|
||||
try expect(typeinfo_info == .Union);
|
||||
try expect(typeinfo_info.Union.layout == .Auto);
|
||||
try expect(typeinfo_info.Union.tag_type.? == TypeId);
|
||||
try expect(typeinfo_info.Union.fields.len == 25);
|
||||
try expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
|
||||
try expect(typeinfo_info.Union.decls.len == 22);
|
||||
|
||||
const TestNoTagUnion = union {
|
||||
Foo: void,
|
||||
Bar: u32,
|
||||
};
|
||||
|
||||
const notag_union_info = @typeInfo(TestNoTagUnion);
|
||||
try expect(notag_union_info == .Union);
|
||||
try expect(notag_union_info.Union.tag_type == null);
|
||||
try expect(notag_union_info.Union.layout == .Auto);
|
||||
try expect(notag_union_info.Union.fields.len == 2);
|
||||
try expect(notag_union_info.Union.fields[0].alignment == @alignOf(void));
|
||||
try expect(notag_union_info.Union.fields[1].field_type == u32);
|
||||
try expect(notag_union_info.Union.fields[1].alignment == @alignOf(u32));
|
||||
|
||||
const TestExternUnion = extern union {
|
||||
foo: *anyopaque,
|
||||
};
|
||||
|
||||
const extern_union_info = @typeInfo(TestExternUnion);
|
||||
try expect(extern_union_info.Union.layout == .Extern);
|
||||
try expect(extern_union_info.Union.tag_type == null);
|
||||
try expect(extern_union_info.Union.fields[0].field_type == *anyopaque);
|
||||
}
|
||||
|
||||
test "type info: struct info" {
|
||||
try testStruct();
|
||||
comptime try testStruct();
|
||||
}
|
||||
|
||||
fn testStruct() !void {
|
||||
const unpacked_struct_info = @typeInfo(TestUnpackedStruct);
|
||||
try expect(unpacked_struct_info.Struct.is_tuple == false);
|
||||
try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
|
||||
try expect(unpacked_struct_info.Struct.fields[0].default_value.? == 4);
|
||||
try expectEqualStrings("foobar", unpacked_struct_info.Struct.fields[1].default_value.?);
|
||||
|
||||
const struct_info = @typeInfo(TestStruct);
|
||||
try expect(struct_info == .Struct);
|
||||
try expect(struct_info.Struct.is_tuple == false);
|
||||
try expect(struct_info.Struct.layout == .Packed);
|
||||
try expect(struct_info.Struct.fields.len == 4);
|
||||
try expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize));
|
||||
try expect(struct_info.Struct.fields[2].field_type == *TestStruct);
|
||||
try expect(struct_info.Struct.fields[2].default_value == null);
|
||||
try expect(struct_info.Struct.fields[3].default_value.? == 4);
|
||||
try expect(struct_info.Struct.fields[3].alignment == 1);
|
||||
try expect(struct_info.Struct.decls.len == 2);
|
||||
try expect(struct_info.Struct.decls[0].is_pub);
|
||||
try expect(!struct_info.Struct.decls[0].data.Fn.is_extern);
|
||||
try expect(struct_info.Struct.decls[0].data.Fn.lib_name == null);
|
||||
try expect(struct_info.Struct.decls[0].data.Fn.return_type == void);
|
||||
try expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void);
|
||||
}
|
||||
|
||||
const TestUnpackedStruct = struct {
|
||||
fieldA: u32 = 4,
|
||||
fieldB: *const [6:0]u8 = "foobar",
|
||||
};
|
||||
|
||||
const TestStruct = packed struct {
|
||||
fieldA: usize align(2 * @alignOf(usize)),
|
||||
fieldB: void,
|
||||
fieldC: *Self,
|
||||
fieldD: u32 = 4,
|
||||
|
||||
pub fn foo(self: *const Self) void {
|
||||
_ = self;
|
||||
}
|
||||
const Self = @This();
|
||||
};
|
||||
|
||||
test "type info: opaque info" {
|
||||
try testOpaque();
|
||||
comptime try testOpaque();
|
||||
}
|
||||
|
||||
fn testOpaque() !void {
|
||||
const Foo = opaque {
|
||||
const A = 1;
|
||||
fn b() void {}
|
||||
};
|
||||
|
||||
const foo_info = @typeInfo(Foo);
|
||||
try expect(foo_info.Opaque.decls.len == 2);
|
||||
}
|
||||
|
||||
test "type info: function type info" {
|
||||
// wasm doesn't support align attributes on functions
|
||||
if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
|
||||
try testFunction();
|
||||
comptime try testFunction();
|
||||
}
|
||||
|
||||
fn testFunction() !void {
|
||||
const fn_info = @typeInfo(@TypeOf(foo));
|
||||
try expect(fn_info == .Fn);
|
||||
try expect(fn_info.Fn.alignment > 0);
|
||||
try expect(fn_info.Fn.calling_convention == .C);
|
||||
try expect(!fn_info.Fn.is_generic);
|
||||
try expect(fn_info.Fn.args.len == 2);
|
||||
try expect(fn_info.Fn.is_var_args);
|
||||
try expect(fn_info.Fn.return_type.? == usize);
|
||||
const fn_aligned_info = @typeInfo(@TypeOf(fooAligned));
|
||||
try expect(fn_aligned_info.Fn.alignment == 4);
|
||||
|
||||
const test_instance: TestStruct = undefined;
|
||||
const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo));
|
||||
try expect(bound_fn_info == .BoundFn);
|
||||
try expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
|
||||
}
|
||||
|
||||
extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
|
||||
extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize;
|
||||
|
||||
test "typeInfo with comptime parameter in struct fn def" {
|
||||
const S = struct {
|
||||
pub fn func(comptime x: f32) void {
|
||||
_ = x;
|
||||
}
|
||||
};
|
||||
comptime var info = @typeInfo(S);
|
||||
_ = info;
|
||||
}
|
||||
|
||||
test "type info: vectors" {
|
||||
try testVector();
|
||||
comptime try testVector();
|
||||
}
|
||||
|
||||
fn testVector() !void {
|
||||
const vec_info = @typeInfo(std.meta.Vector(4, i32));
|
||||
try expect(vec_info == .Vector);
|
||||
try expect(vec_info.Vector.len == 4);
|
||||
try expect(vec_info.Vector.child == i32);
|
||||
}
|
||||
|
||||
test "type info: anyframe and anyframe->T" {
|
||||
try testAnyFrame();
|
||||
comptime try testAnyFrame();
|
||||
}
|
||||
|
||||
fn testAnyFrame() !void {
|
||||
{
|
||||
const anyframe_info = @typeInfo(anyframe->i32);
|
||||
try expect(anyframe_info == .AnyFrame);
|
||||
try expect(anyframe_info.AnyFrame.child.? == i32);
|
||||
}
|
||||
|
||||
{
|
||||
const anyframe_info = @typeInfo(anyframe);
|
||||
try expect(anyframe_info == .AnyFrame);
|
||||
try expect(anyframe_info.AnyFrame.child == null);
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: pass to function" {
|
||||
_ = passTypeInfo(@typeInfo(void));
|
||||
_ = comptime passTypeInfo(@typeInfo(void));
|
||||
}
|
||||
|
||||
fn passTypeInfo(comptime info: TypeInfo) type {
|
||||
_ = info;
|
||||
return void;
|
||||
}
|
||||
|
||||
test "type info: TypeId -> TypeInfo impl cast" {
|
||||
_ = passTypeInfo(TypeId.Void);
|
||||
_ = comptime passTypeInfo(TypeId.Void);
|
||||
}
|
||||
|
||||
test "type info: extern fns with and without lib names" {
|
||||
const S = struct {
|
||||
extern fn bar1() void;
|
||||
extern "cool" fn bar2() void;
|
||||
};
|
||||
const info = @typeInfo(S);
|
||||
comptime {
|
||||
for (info.Struct.decls) |decl| {
|
||||
if (std.mem.eql(u8, decl.name, "bar1")) {
|
||||
try expect(decl.data.Fn.lib_name == null);
|
||||
} else {
|
||||
try expectEqualStrings("cool", decl.data.Fn.lib_name.?);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "data field is a compile-time value" {
|
||||
const S = struct {
|
||||
const Bar = @as(isize, -1);
|
||||
};
|
||||
comptime try expect(@typeInfo(S).Struct.decls[0].data.Var == isize);
|
||||
}
|
||||
|
||||
test "sentinel of opaque pointer type" {
|
||||
const c_void_info = @typeInfo(*anyopaque);
|
||||
try expect(c_void_info.Pointer.sentinel == null);
|
||||
}
|
||||
|
||||
test "@typeInfo does not force declarations into existence" {
|
||||
const S = struct {
|
||||
x: i32,
|
||||
|
||||
fn doNotReferenceMe() void {
|
||||
@compileError("test failed");
|
||||
}
|
||||
};
|
||||
comptime try expect(@typeInfo(S).Struct.fields.len == 1);
|
||||
}
|
||||
|
||||
test "defaut value for a var-typed field" {
|
||||
const S = struct { x: anytype };
|
||||
try expect(@typeInfo(S).Struct.fields[0].default_value == null);
|
||||
}
|
||||
|
||||
fn add(a: i32, b: i32) i32 {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
test "type info for async frames" {
|
||||
switch (@typeInfo(@Frame(add))) {
|
||||
.Frame => |frame| {
|
||||
try expect(frame.function == add);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: value is correctly copied" {
|
||||
comptime {
|
||||
var ptrInfo = @typeInfo([]u32);
|
||||
ptrInfo.Pointer.size = .One;
|
||||
try expect(@typeInfo([]u32).Pointer.size == .Slice);
|
||||
}
|
||||
}
|
||||
|
||||
test "Declarations are returned in declaration order" {
|
||||
const S = struct {
|
||||
const a = 1;
|
||||
const b = 2;
|
||||
const c = 3;
|
||||
const d = 4;
|
||||
const e = 5;
|
||||
};
|
||||
const d = @typeInfo(S).Struct.decls;
|
||||
try expect(std.mem.eql(u8, d[0].name, "a"));
|
||||
try expect(std.mem.eql(u8, d[1].name, "b"));
|
||||
try expect(std.mem.eql(u8, d[2].name, "c"));
|
||||
try expect(std.mem.eql(u8, d[3].name, "d"));
|
||||
try expect(std.mem.eql(u8, d[4].name, "e"));
|
||||
}
|
||||
|
||||
test "Struct.is_tuple" {
|
||||
try expect(@typeInfo(@TypeOf(.{0})).Struct.is_tuple);
|
||||
try expect(!@typeInfo(@TypeOf(.{ .a = 0 })).Struct.is_tuple);
|
||||
}
|
||||
|
||||
test "StructField.is_comptime" {
|
||||
const info = @typeInfo(struct { x: u8 = 3, comptime y: u32 = 5 }).Struct;
|
||||
try expect(!info.fields[0].is_comptime);
|
||||
try expect(info.fields[1].is_comptime);
|
||||
}
|
||||
|
||||
test "typeInfo resolves usingnamespace declarations" {
|
||||
const A = struct {
|
||||
pub const f1 = 42;
|
||||
};
|
||||
|
||||
const B = struct {
|
||||
const f0 = 42;
|
||||
usingnamespace A;
|
||||
};
|
||||
|
||||
try expect(@typeInfo(B).Struct.decls.len == 2);
|
||||
//a
|
||||
}
|
||||
|
||||
463
test/behavior/type_info_stage1.zig
Normal file
463
test/behavior/type_info_stage1.zig
Normal file
@ -0,0 +1,463 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const mem = std.mem;
|
||||
|
||||
const TypeInfo = std.builtin.TypeInfo;
|
||||
const TypeId = std.builtin.TypeId;
|
||||
|
||||
const expect = std.testing.expect;
|
||||
const expectEqualStrings = std.testing.expectEqualStrings;
|
||||
|
||||
test "type info: tag type, void info" {
|
||||
try testBasic();
|
||||
comptime try testBasic();
|
||||
}
|
||||
|
||||
fn testBasic() !void {
|
||||
try expect(@typeInfo(TypeInfo).Union.tag_type == TypeId);
|
||||
const void_info = @typeInfo(void);
|
||||
try expect(void_info == TypeId.Void);
|
||||
try expect(void_info.Void == {});
|
||||
}
|
||||
|
||||
test "type info: pointer type info" {
|
||||
try testPointer();
|
||||
comptime try testPointer();
|
||||
}
|
||||
|
||||
fn testPointer() !void {
|
||||
const u32_ptr_info = @typeInfo(*u32);
|
||||
try expect(u32_ptr_info == .Pointer);
|
||||
try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
|
||||
try expect(u32_ptr_info.Pointer.is_const == false);
|
||||
try expect(u32_ptr_info.Pointer.is_volatile == false);
|
||||
try expect(u32_ptr_info.Pointer.alignment == @alignOf(u32));
|
||||
try expect(u32_ptr_info.Pointer.child == u32);
|
||||
try expect(u32_ptr_info.Pointer.sentinel == null);
|
||||
}
|
||||
|
||||
test "type info: unknown length pointer type info" {
|
||||
try testUnknownLenPtr();
|
||||
comptime try testUnknownLenPtr();
|
||||
}
|
||||
|
||||
fn testUnknownLenPtr() !void {
|
||||
const u32_ptr_info = @typeInfo([*]const volatile f64);
|
||||
try expect(u32_ptr_info == .Pointer);
|
||||
try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
|
||||
try expect(u32_ptr_info.Pointer.is_const == true);
|
||||
try expect(u32_ptr_info.Pointer.is_volatile == true);
|
||||
try expect(u32_ptr_info.Pointer.sentinel == null);
|
||||
try expect(u32_ptr_info.Pointer.alignment == @alignOf(f64));
|
||||
try expect(u32_ptr_info.Pointer.child == f64);
|
||||
}
|
||||
|
||||
test "type info: null terminated pointer type info" {
|
||||
try testNullTerminatedPtr();
|
||||
comptime try testNullTerminatedPtr();
|
||||
}
|
||||
|
||||
fn testNullTerminatedPtr() !void {
|
||||
const ptr_info = @typeInfo([*:0]u8);
|
||||
try expect(ptr_info == .Pointer);
|
||||
try expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
|
||||
try expect(ptr_info.Pointer.is_const == false);
|
||||
try expect(ptr_info.Pointer.is_volatile == false);
|
||||
try expect(ptr_info.Pointer.sentinel.? == 0);
|
||||
|
||||
try expect(@typeInfo([:0]u8).Pointer.sentinel != null);
|
||||
}
|
||||
|
||||
test "type info: C pointer type info" {
|
||||
try testCPtr();
|
||||
comptime try testCPtr();
|
||||
}
|
||||
|
||||
fn testCPtr() !void {
|
||||
const ptr_info = @typeInfo([*c]align(4) const i8);
|
||||
try expect(ptr_info == .Pointer);
|
||||
try expect(ptr_info.Pointer.size == .C);
|
||||
try expect(ptr_info.Pointer.is_const);
|
||||
try expect(!ptr_info.Pointer.is_volatile);
|
||||
try expect(ptr_info.Pointer.alignment == 4);
|
||||
try expect(ptr_info.Pointer.child == i8);
|
||||
}
|
||||
|
||||
test "type info: slice type info" {
|
||||
try testSlice();
|
||||
comptime try testSlice();
|
||||
}
|
||||
|
||||
fn testSlice() !void {
|
||||
const u32_slice_info = @typeInfo([]u32);
|
||||
try expect(u32_slice_info == .Pointer);
|
||||
try expect(u32_slice_info.Pointer.size == .Slice);
|
||||
try expect(u32_slice_info.Pointer.is_const == false);
|
||||
try expect(u32_slice_info.Pointer.is_volatile == false);
|
||||
try expect(u32_slice_info.Pointer.alignment == 4);
|
||||
try expect(u32_slice_info.Pointer.child == u32);
|
||||
}
|
||||
|
||||
test "type info: array type info" {
|
||||
try testArray();
|
||||
comptime try testArray();
|
||||
}
|
||||
|
||||
fn testArray() !void {
|
||||
{
|
||||
const info = @typeInfo([42]u8);
|
||||
try expect(info == .Array);
|
||||
try expect(info.Array.len == 42);
|
||||
try expect(info.Array.child == u8);
|
||||
try expect(info.Array.sentinel == null);
|
||||
}
|
||||
|
||||
{
|
||||
const info = @typeInfo([10:0]u8);
|
||||
try expect(info.Array.len == 10);
|
||||
try expect(info.Array.child == u8);
|
||||
try expect(info.Array.sentinel.? == @as(u8, 0));
|
||||
try expect(@sizeOf([10:0]u8) == info.Array.len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: error set, error union info" {
|
||||
try testErrorSet();
|
||||
comptime try testErrorSet();
|
||||
}
|
||||
|
||||
fn testErrorSet() !void {
|
||||
const TestErrorSet = error{
|
||||
First,
|
||||
Second,
|
||||
Third,
|
||||
};
|
||||
|
||||
const error_set_info = @typeInfo(TestErrorSet);
|
||||
try expect(error_set_info == .ErrorSet);
|
||||
try expect(error_set_info.ErrorSet.?.len == 3);
|
||||
try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "First"));
|
||||
|
||||
const error_union_info = @typeInfo(TestErrorSet!usize);
|
||||
try expect(error_union_info == .ErrorUnion);
|
||||
try expect(error_union_info.ErrorUnion.error_set == TestErrorSet);
|
||||
try expect(error_union_info.ErrorUnion.payload == usize);
|
||||
|
||||
const global_info = @typeInfo(anyerror);
|
||||
try expect(global_info == .ErrorSet);
|
||||
try expect(global_info.ErrorSet == null);
|
||||
}
|
||||
|
||||
test "type info: enum info" {
|
||||
try testEnum();
|
||||
comptime try testEnum();
|
||||
}
|
||||
|
||||
fn testEnum() !void {
|
||||
const Os = enum {
|
||||
Windows,
|
||||
Macos,
|
||||
Linux,
|
||||
FreeBSD,
|
||||
};
|
||||
|
||||
const os_info = @typeInfo(Os);
|
||||
try expect(os_info == .Enum);
|
||||
try expect(os_info.Enum.layout == .Auto);
|
||||
try expect(os_info.Enum.fields.len == 4);
|
||||
try expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
|
||||
try expect(os_info.Enum.fields[3].value == 3);
|
||||
try expect(os_info.Enum.tag_type == u2);
|
||||
try expect(os_info.Enum.decls.len == 0);
|
||||
}
|
||||
|
||||
test "type info: union info" {
|
||||
try testUnion();
|
||||
comptime try testUnion();
|
||||
}
|
||||
|
||||
fn testUnion() !void {
|
||||
const typeinfo_info = @typeInfo(TypeInfo);
|
||||
try expect(typeinfo_info == .Union);
|
||||
try expect(typeinfo_info.Union.layout == .Auto);
|
||||
try expect(typeinfo_info.Union.tag_type.? == TypeId);
|
||||
try expect(typeinfo_info.Union.fields.len == 25);
|
||||
try expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
|
||||
try expect(typeinfo_info.Union.decls.len == 22);
|
||||
|
||||
const TestNoTagUnion = union {
|
||||
Foo: void,
|
||||
Bar: u32,
|
||||
};
|
||||
|
||||
const notag_union_info = @typeInfo(TestNoTagUnion);
|
||||
try expect(notag_union_info == .Union);
|
||||
try expect(notag_union_info.Union.tag_type == null);
|
||||
try expect(notag_union_info.Union.layout == .Auto);
|
||||
try expect(notag_union_info.Union.fields.len == 2);
|
||||
try expect(notag_union_info.Union.fields[0].alignment == @alignOf(void));
|
||||
try expect(notag_union_info.Union.fields[1].field_type == u32);
|
||||
try expect(notag_union_info.Union.fields[1].alignment == @alignOf(u32));
|
||||
|
||||
const TestExternUnion = extern union {
|
||||
foo: *anyopaque,
|
||||
};
|
||||
|
||||
const extern_union_info = @typeInfo(TestExternUnion);
|
||||
try expect(extern_union_info.Union.layout == .Extern);
|
||||
try expect(extern_union_info.Union.tag_type == null);
|
||||
try expect(extern_union_info.Union.fields[0].field_type == *anyopaque);
|
||||
}
|
||||
|
||||
test "type info: struct info" {
|
||||
try testStruct();
|
||||
comptime try testStruct();
|
||||
}
|
||||
|
||||
fn testStruct() !void {
|
||||
const unpacked_struct_info = @typeInfo(TestUnpackedStruct);
|
||||
try expect(unpacked_struct_info.Struct.is_tuple == false);
|
||||
try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
|
||||
try expect(unpacked_struct_info.Struct.fields[0].default_value.? == 4);
|
||||
try expectEqualStrings("foobar", unpacked_struct_info.Struct.fields[1].default_value.?);
|
||||
|
||||
const struct_info = @typeInfo(TestStruct);
|
||||
try expect(struct_info == .Struct);
|
||||
try expect(struct_info.Struct.is_tuple == false);
|
||||
try expect(struct_info.Struct.layout == .Packed);
|
||||
try expect(struct_info.Struct.fields.len == 4);
|
||||
try expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize));
|
||||
try expect(struct_info.Struct.fields[2].field_type == *TestStruct);
|
||||
try expect(struct_info.Struct.fields[2].default_value == null);
|
||||
try expect(struct_info.Struct.fields[3].default_value.? == 4);
|
||||
try expect(struct_info.Struct.fields[3].alignment == 1);
|
||||
try expect(struct_info.Struct.decls.len == 2);
|
||||
try expect(struct_info.Struct.decls[0].is_pub);
|
||||
try expect(!struct_info.Struct.decls[0].data.Fn.is_extern);
|
||||
try expect(struct_info.Struct.decls[0].data.Fn.lib_name == null);
|
||||
try expect(struct_info.Struct.decls[0].data.Fn.return_type == void);
|
||||
try expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void);
|
||||
}
|
||||
|
||||
const TestUnpackedStruct = struct {
|
||||
fieldA: u32 = 4,
|
||||
fieldB: *const [6:0]u8 = "foobar",
|
||||
};
|
||||
|
||||
const TestStruct = packed struct {
|
||||
fieldA: usize align(2 * @alignOf(usize)),
|
||||
fieldB: void,
|
||||
fieldC: *Self,
|
||||
fieldD: u32 = 4,
|
||||
|
||||
pub fn foo(self: *const Self) void {
|
||||
_ = self;
|
||||
}
|
||||
const Self = @This();
|
||||
};
|
||||
|
||||
test "type info: opaque info" {
|
||||
try testOpaque();
|
||||
comptime try testOpaque();
|
||||
}
|
||||
|
||||
fn testOpaque() !void {
|
||||
const Foo = opaque {
|
||||
const A = 1;
|
||||
fn b() void {}
|
||||
};
|
||||
|
||||
const foo_info = @typeInfo(Foo);
|
||||
try expect(foo_info.Opaque.decls.len == 2);
|
||||
}
|
||||
|
||||
test "type info: function type info" {
|
||||
// wasm doesn't support align attributes on functions
|
||||
if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
|
||||
try testFunction();
|
||||
comptime try testFunction();
|
||||
}
|
||||
|
||||
fn testFunction() !void {
|
||||
const fn_info = @typeInfo(@TypeOf(foo));
|
||||
try expect(fn_info == .Fn);
|
||||
try expect(fn_info.Fn.alignment > 0);
|
||||
try expect(fn_info.Fn.calling_convention == .C);
|
||||
try expect(!fn_info.Fn.is_generic);
|
||||
try expect(fn_info.Fn.args.len == 2);
|
||||
try expect(fn_info.Fn.is_var_args);
|
||||
try expect(fn_info.Fn.return_type.? == usize);
|
||||
const fn_aligned_info = @typeInfo(@TypeOf(fooAligned));
|
||||
try expect(fn_aligned_info.Fn.alignment == 4);
|
||||
|
||||
const test_instance: TestStruct = undefined;
|
||||
const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo));
|
||||
try expect(bound_fn_info == .BoundFn);
|
||||
try expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
|
||||
}
|
||||
|
||||
extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
|
||||
extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize;
|
||||
|
||||
test "typeInfo with comptime parameter in struct fn def" {
|
||||
const S = struct {
|
||||
pub fn func(comptime x: f32) void {
|
||||
_ = x;
|
||||
}
|
||||
};
|
||||
comptime var info = @typeInfo(S);
|
||||
_ = info;
|
||||
}
|
||||
|
||||
test "type info: vectors" {
|
||||
try testVector();
|
||||
comptime try testVector();
|
||||
}
|
||||
|
||||
fn testVector() !void {
|
||||
const vec_info = @typeInfo(std.meta.Vector(4, i32));
|
||||
try expect(vec_info == .Vector);
|
||||
try expect(vec_info.Vector.len == 4);
|
||||
try expect(vec_info.Vector.child == i32);
|
||||
}
|
||||
|
||||
test "type info: anyframe and anyframe->T" {
|
||||
try testAnyFrame();
|
||||
comptime try testAnyFrame();
|
||||
}
|
||||
|
||||
fn testAnyFrame() !void {
|
||||
{
|
||||
const anyframe_info = @typeInfo(anyframe->i32);
|
||||
try expect(anyframe_info == .AnyFrame);
|
||||
try expect(anyframe_info.AnyFrame.child.? == i32);
|
||||
}
|
||||
|
||||
{
|
||||
const anyframe_info = @typeInfo(anyframe);
|
||||
try expect(anyframe_info == .AnyFrame);
|
||||
try expect(anyframe_info.AnyFrame.child == null);
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: pass to function" {
|
||||
_ = passTypeInfo(@typeInfo(void));
|
||||
_ = comptime passTypeInfo(@typeInfo(void));
|
||||
}
|
||||
|
||||
fn passTypeInfo(comptime info: TypeInfo) type {
|
||||
_ = info;
|
||||
return void;
|
||||
}
|
||||
|
||||
test "type info: TypeId -> TypeInfo impl cast" {
|
||||
_ = passTypeInfo(TypeId.Void);
|
||||
_ = comptime passTypeInfo(TypeId.Void);
|
||||
}
|
||||
|
||||
test "type info: extern fns with and without lib names" {
|
||||
const S = struct {
|
||||
extern fn bar1() void;
|
||||
extern "cool" fn bar2() void;
|
||||
};
|
||||
const info = @typeInfo(S);
|
||||
comptime {
|
||||
for (info.Struct.decls) |decl| {
|
||||
if (std.mem.eql(u8, decl.name, "bar1")) {
|
||||
try expect(decl.data.Fn.lib_name == null);
|
||||
} else {
|
||||
try expectEqualStrings("cool", decl.data.Fn.lib_name.?);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "data field is a compile-time value" {
|
||||
const S = struct {
|
||||
const Bar = @as(isize, -1);
|
||||
};
|
||||
comptime try expect(@typeInfo(S).Struct.decls[0].data.Var == isize);
|
||||
}
|
||||
|
||||
test "sentinel of opaque pointer type" {
|
||||
const c_void_info = @typeInfo(*anyopaque);
|
||||
try expect(c_void_info.Pointer.sentinel == null);
|
||||
}
|
||||
|
||||
test "@typeInfo does not force declarations into existence" {
|
||||
const S = struct {
|
||||
x: i32,
|
||||
|
||||
fn doNotReferenceMe() void {
|
||||
@compileError("test failed");
|
||||
}
|
||||
};
|
||||
comptime try expect(@typeInfo(S).Struct.fields.len == 1);
|
||||
}
|
||||
|
||||
test "defaut value for a var-typed field" {
|
||||
const S = struct { x: anytype };
|
||||
try expect(@typeInfo(S).Struct.fields[0].default_value == null);
|
||||
}
|
||||
|
||||
fn add(a: i32, b: i32) i32 {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
test "type info for async frames" {
|
||||
switch (@typeInfo(@Frame(add))) {
|
||||
.Frame => |frame| {
|
||||
try expect(frame.function == add);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: value is correctly copied" {
|
||||
comptime {
|
||||
var ptrInfo = @typeInfo([]u32);
|
||||
ptrInfo.Pointer.size = .One;
|
||||
try expect(@typeInfo([]u32).Pointer.size == .Slice);
|
||||
}
|
||||
}
|
||||
|
||||
test "Declarations are returned in declaration order" {
|
||||
const S = struct {
|
||||
const a = 1;
|
||||
const b = 2;
|
||||
const c = 3;
|
||||
const d = 4;
|
||||
const e = 5;
|
||||
};
|
||||
const d = @typeInfo(S).Struct.decls;
|
||||
try expect(std.mem.eql(u8, d[0].name, "a"));
|
||||
try expect(std.mem.eql(u8, d[1].name, "b"));
|
||||
try expect(std.mem.eql(u8, d[2].name, "c"));
|
||||
try expect(std.mem.eql(u8, d[3].name, "d"));
|
||||
try expect(std.mem.eql(u8, d[4].name, "e"));
|
||||
}
|
||||
|
||||
test "Struct.is_tuple" {
|
||||
try expect(@typeInfo(@TypeOf(.{0})).Struct.is_tuple);
|
||||
try expect(!@typeInfo(@TypeOf(.{ .a = 0 })).Struct.is_tuple);
|
||||
}
|
||||
|
||||
test "StructField.is_comptime" {
|
||||
const info = @typeInfo(struct { x: u8 = 3, comptime y: u32 = 5 }).Struct;
|
||||
try expect(!info.fields[0].is_comptime);
|
||||
try expect(info.fields[1].is_comptime);
|
||||
}
|
||||
|
||||
test "typeInfo resolves usingnamespace declarations" {
|
||||
const A = struct {
|
||||
pub const f1 = 42;
|
||||
};
|
||||
|
||||
const B = struct {
|
||||
const f0 = 42;
|
||||
usingnamespace A;
|
||||
};
|
||||
|
||||
try expect(@typeInfo(B).Struct.decls.len == 2);
|
||||
//a
|
||||
}
|
||||
411
test/behavior/type_stage1.zig
Normal file
411
test/behavior/type_stage1.zig
Normal file
@ -0,0 +1,411 @@
|
||||
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| {
|
||||
try testing.expect(testType == @Type(@typeInfo(testType)));
|
||||
}
|
||||
}
|
||||
|
||||
test "Type.Float" {
|
||||
try testing.expect(f16 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 16 } }));
|
||||
try testing.expect(f32 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 32 } }));
|
||||
try testing.expect(f64 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 64 } }));
|
||||
try testing.expect(f128 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 128 } }));
|
||||
try testTypes(&[_]type{ f16, f32, f64, f128 });
|
||||
}
|
||||
|
||||
test "Type.Pointer" {
|
||||
try 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" {
|
||||
try testing.expect([123]u8 == @Type(TypeInfo{
|
||||
.Array = TypeInfo.Array{
|
||||
.len = 123,
|
||||
.child = u8,
|
||||
.sentinel = null,
|
||||
},
|
||||
}));
|
||||
try testing.expect([2]u32 == @Type(TypeInfo{
|
||||
.Array = TypeInfo.Array{
|
||||
.len = 2,
|
||||
.child = u32,
|
||||
.sentinel = null,
|
||||
},
|
||||
}));
|
||||
try testing.expect([2:0]u32 == @Type(TypeInfo{
|
||||
.Array = TypeInfo.Array{
|
||||
.len = 2,
|
||||
.child = u32,
|
||||
.sentinel = 0,
|
||||
},
|
||||
}));
|
||||
try testTypes(&[_]type{ [1]u8, [30]usize, [7]bool });
|
||||
}
|
||||
|
||||
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,
|
||||
.address_space = .generic,
|
||||
.child = *i32,
|
||||
.sentinel = null,
|
||||
},
|
||||
});
|
||||
try testing.expect(Slice == []align(8) const *i32);
|
||||
}
|
||||
test "@Type picks up the sentinel value from TypeInfo" {
|
||||
try 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" {
|
||||
try testTypes(&[_]type{
|
||||
?u8,
|
||||
?*u8,
|
||||
?[]u8,
|
||||
?[*]u8,
|
||||
?[*c]u8,
|
||||
});
|
||||
}
|
||||
|
||||
test "Type.ErrorUnion" {
|
||||
try testTypes(&[_]type{
|
||||
error{}!void,
|
||||
error{Error}!void,
|
||||
});
|
||||
}
|
||||
|
||||
test "Type.Opaque" {
|
||||
const Opaque = @Type(.{
|
||||
.Opaque = .{
|
||||
.decls = &[_]TypeInfo.Declaration{},
|
||||
},
|
||||
});
|
||||
try testing.expect(Opaque != opaque {});
|
||||
try testing.expectEqualSlices(
|
||||
TypeInfo.Declaration,
|
||||
&[_]TypeInfo.Declaration{},
|
||||
@typeInfo(Opaque).Opaque.decls,
|
||||
);
|
||||
}
|
||||
|
||||
test "Type.Vector" {
|
||||
try 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" {
|
||||
try testTypes(&[_]type{
|
||||
anyframe,
|
||||
anyframe->u8,
|
||||
anyframe->anyframe->u8,
|
||||
});
|
||||
}
|
||||
|
||||
fn add(a: i32, b: i32) i32 {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
test "Type.Frame" {
|
||||
try 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;
|
||||
try testing.expectEqual(TypeInfo.ContainerLayout.Auto, infoA.layout);
|
||||
try testing.expectEqualSlices(u8, "x", infoA.fields[0].name);
|
||||
try testing.expectEqual(u8, infoA.fields[0].field_type);
|
||||
try testing.expectEqual(@as(?u8, null), infoA.fields[0].default_value);
|
||||
try testing.expectEqualSlices(u8, "y", infoA.fields[1].name);
|
||||
try testing.expectEqual(u32, infoA.fields[1].field_type);
|
||||
try testing.expectEqual(@as(?u32, null), infoA.fields[1].default_value);
|
||||
try testing.expectEqualSlices(TypeInfo.Declaration, &[_]TypeInfo.Declaration{}, infoA.decls);
|
||||
try testing.expectEqual(@as(bool, false), infoA.is_tuple);
|
||||
|
||||
var a = A{ .x = 0, .y = 1 };
|
||||
try testing.expectEqual(@as(u8, 0), a.x);
|
||||
try testing.expectEqual(@as(u32, 1), a.y);
|
||||
a.y += 1;
|
||||
try testing.expectEqual(@as(u32, 2), a.y);
|
||||
|
||||
const B = @Type(@typeInfo(extern struct { x: u8, y: u32 = 5 }));
|
||||
const infoB = @typeInfo(B).Struct;
|
||||
try testing.expectEqual(TypeInfo.ContainerLayout.Extern, infoB.layout);
|
||||
try testing.expectEqualSlices(u8, "x", infoB.fields[0].name);
|
||||
try testing.expectEqual(u8, infoB.fields[0].field_type);
|
||||
try testing.expectEqual(@as(?u8, null), infoB.fields[0].default_value);
|
||||
try testing.expectEqualSlices(u8, "y", infoB.fields[1].name);
|
||||
try testing.expectEqual(u32, infoB.fields[1].field_type);
|
||||
try testing.expectEqual(@as(?u32, 5), infoB.fields[1].default_value);
|
||||
try testing.expectEqual(@as(usize, 0), infoB.decls.len);
|
||||
try 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;
|
||||
try testing.expectEqual(TypeInfo.ContainerLayout.Packed, infoC.layout);
|
||||
try testing.expectEqualSlices(u8, "x", infoC.fields[0].name);
|
||||
try testing.expectEqual(u8, infoC.fields[0].field_type);
|
||||
try testing.expectEqual(@as(?u8, 3), infoC.fields[0].default_value);
|
||||
try testing.expectEqualSlices(u8, "y", infoC.fields[1].name);
|
||||
try testing.expectEqual(u32, infoC.fields[1].field_type);
|
||||
try testing.expectEqual(@as(?u32, 5), infoC.fields[1].default_value);
|
||||
try testing.expectEqual(@as(usize, 0), infoC.decls.len);
|
||||
try 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,
|
||||
},
|
||||
});
|
||||
try testing.expectEqual(true, @typeInfo(Foo).Enum.is_exhaustive);
|
||||
try testing.expectEqual(@as(u8, 1), @enumToInt(Foo.a));
|
||||
try 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,
|
||||
},
|
||||
});
|
||||
try testing.expectEqual(false, @typeInfo(Bar).Enum.is_exhaustive);
|
||||
try testing.expectEqual(@as(u32, 1), @enumToInt(Bar.a));
|
||||
try testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b));
|
||||
try 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;
|
||||
try 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 };
|
||||
try testing.expectEqual(@as(i32, -1), packed_untagged.signed);
|
||||
try 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 };
|
||||
try testing.expectEqual(Tag.signed, tagged);
|
||||
tagged = .{ .unsigned = 1 };
|
||||
try 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 };
|
||||
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 {
|
||||
_ = a;
|
||||
_ = b;
|
||||
return 0;
|
||||
}
|
||||
}.func;
|
||||
const Foo = @Type(@typeInfo(@TypeOf(foo)));
|
||||
const foo_2: Foo = foo;
|
||||
_ = foo_2;
|
||||
}
|
||||
|
||||
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 {
|
||||
_ = self;
|
||||
}
|
||||
};
|
||||
const test_instance: TestStruct = undefined;
|
||||
try testing.expect(std.meta.eql(
|
||||
@typeName(@TypeOf(test_instance.foo)),
|
||||
@typeName(@Type(@typeInfo(@TypeOf(test_instance.foo)))),
|
||||
));
|
||||
}
|
||||
@ -460,3 +460,28 @@ test "tagged union as return value" {
|
||||
fn returnAnInt(x: i32) TaggedFoo {
|
||||
return TaggedFoo{ .One = x };
|
||||
}
|
||||
|
||||
test "tagged union with all void fields but a meaningful tag" {
|
||||
const S = struct {
|
||||
const B = union(enum) {
|
||||
c: C,
|
||||
None,
|
||||
};
|
||||
|
||||
const A = struct {
|
||||
b: B,
|
||||
};
|
||||
|
||||
const C = struct {};
|
||||
|
||||
fn doTheTest() !void {
|
||||
var a: A = A{ .b = B{ .c = C{} } };
|
||||
try expect(@as(Tag(B), a.b) == Tag(B).c);
|
||||
a = A{ .b = B.None };
|
||||
try expect(@as(Tag(B), a.b) == Tag(B).None);
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
// TODO enable the test at comptime too
|
||||
//comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user