diff --git a/test/behavior.zig b/test/behavior.zig index 5fa65fe475..244217111f 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -1,7 +1,6 @@ const builtin = @import("builtin"); test { - // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend. _ = @import("behavior/align.zig"); _ = @import("behavior/alignof.zig"); _ = @import("behavior/array.zig"); @@ -26,7 +25,6 @@ test { _ = @import("behavior/cast.zig"); _ = @import("behavior/comptime_memory.zig"); _ = @import("behavior/fn_in_struct_in_comptime.zig"); - _ = @import("behavior/generics_llvm.zig"); _ = @import("behavior/hasdecl.zig"); _ = @import("behavior/hasfield.zig"); _ = @import("behavior/namespace_depends_on_compile_var.zig"); @@ -43,6 +41,7 @@ test { _ = @import("behavior/bitcast.zig"); _ = @import("behavior/bugs/624.zig"); _ = @import("behavior/bugs/704.zig"); + _ = @import("behavior/bugs/1076.zig"); _ = @import("behavior/bugs/1486.zig"); _ = @import("behavior/bugs/2692.zig"); _ = @import("behavior/bugs/2889.zig"); @@ -128,7 +127,6 @@ test { _ = @import("behavior/bugs/726.zig"); _ = @import("behavior/bugs/828.zig"); _ = @import("behavior/bugs/920.zig"); - _ = @import("behavior/bugs/1076.zig"); _ = @import("behavior/bugs/1120.zig"); _ = @import("behavior/bugs/1421.zig"); _ = @import("behavior/bugs/1442.zig"); @@ -150,9 +148,7 @@ test { _ = @import("behavior/bugs/7047.zig"); _ = @import("behavior/bugs/10147.zig"); _ = @import("behavior/byteswap.zig"); - _ = @import("behavior/call_stage1.zig"); _ = @import("behavior/const_slice_child.zig"); - _ = @import("behavior/error_stage1.zig"); _ = @import("behavior/field_parent_ptr.zig"); _ = @import("behavior/floatop_stage1.zig"); _ = @import("behavior/fn_delegation.zig"); @@ -164,14 +160,12 @@ test { _ = @import("behavior/optional_stage1.zig"); _ = @import("behavior/popcount_stage1.zig"); _ = @import("behavior/reflection.zig"); - _ = @import("behavior/saturating_arithmetic_stage1.zig"); _ = @import("behavior/select.zig"); _ = @import("behavior/shuffle.zig"); _ = @import("behavior/sizeof_and_typeof_stage1.zig"); _ = @import("behavior/slice_stage1.zig"); _ = @import("behavior/struct_contains_null_ptr_itself.zig"); _ = @import("behavior/struct_contains_slice_of_itself.zig"); - _ = @import("behavior/struct_stage1.zig"); _ = @import("behavior/switch_prong_err_enum.zig"); _ = @import("behavior/switch_prong_implicit_cast.zig"); _ = @import("behavior/truncate_stage1.zig"); @@ -185,7 +179,6 @@ test { if (builtin.target.cpu.arch == .wasm32) { _ = @import("behavior/wasm.zig"); } - _ = @import("behavior/translate_c_macros_stage1.zig"); } } } diff --git a/test/behavior/call.zig b/test/behavior/call.zig index 03c8038ffa..69e8fc6570 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -1,3 +1,81 @@ +const builtin = @import("builtin"); const std = @import("std"); const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; + +test "basic invocations" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const foo = struct { + fn foo() i32 { + return 1234; + } + }.foo; + try expect(@call(.{}, foo, .{}) == 1234); + comptime { + // modifiers that allow comptime calls + try expect(@call(.{}, foo, .{}) == 1234); + try expect(@call(.{ .modifier = .no_async }, foo, .{}) == 1234); + try expect(@call(.{ .modifier = .always_tail }, foo, .{}) == 1234); + try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234); + } + { + // comptime call without comptime keyword + const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234; + comptime try expect(result); + } + { + // call of non comptime-known function + var alias_foo = foo; + try expect(@call(.{ .modifier = .no_async }, alias_foo, .{}) == 1234); + try expect(@call(.{ .modifier = .never_tail }, alias_foo, .{}) == 1234); + try expect(@call(.{ .modifier = .never_inline }, alias_foo, .{}) == 1234); + } +} + +test "tuple parameters" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const add = struct { + fn add(a: i32, b: i32) i32 { + return a + b; + } + }.add; + var a: i32 = 12; + var b: i32 = 34; + try expect(@call(.{}, add, .{ a, 34 }) == 46); + try expect(@call(.{}, add, .{ 12, b }) == 46); + try expect(@call(.{}, add, .{ a, b }) == 46); + try expect(@call(.{}, add, .{ 12, 34 }) == 46); + comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46); + { + const separate_args0 = .{ a, b }; + const separate_args1 = .{ a, 34 }; + const separate_args2 = .{ 12, 34 }; + const separate_args3 = .{ 12, b }; + try expect(@call(.{ .modifier = .always_inline }, add, separate_args0) == 46); + try expect(@call(.{ .modifier = .always_inline }, add, separate_args1) == 46); + try expect(@call(.{ .modifier = .always_inline }, add, separate_args2) == 46); + try expect(@call(.{ .modifier = .always_inline }, add, separate_args3) == 46); + } +} + +test "comptime call with bound function as parameter" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn ReturnType(func: anytype) type { + return switch (@typeInfo(@TypeOf(func))) { + .BoundFn => |info| info, + else => unreachable, + }.return_type orelse void; + } + + fn call_me_maybe() ?i32 { + return 123; + } + }; + + var inst: S = undefined; + try expectEqual(?i32, S.ReturnType(inst.call_me_maybe)); +} diff --git a/test/behavior/call_stage1.zig b/test/behavior/call_stage1.zig deleted file mode 100644 index f036c3c7c3..0000000000 --- a/test/behavior/call_stage1.zig +++ /dev/null @@ -1,74 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const expectEqual = std.testing.expectEqual; - -test "basic invocations" { - const foo = struct { - fn foo() i32 { - return 1234; - } - }.foo; - try expect(@call(.{}, foo, .{}) == 1234); - comptime { - // modifiers that allow comptime calls - try expect(@call(.{}, foo, .{}) == 1234); - try expect(@call(.{ .modifier = .no_async }, foo, .{}) == 1234); - try expect(@call(.{ .modifier = .always_tail }, foo, .{}) == 1234); - try expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234); - } - { - // comptime call without comptime keyword - const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234; - comptime try expect(result); - } - { - // call of non comptime-known function - var alias_foo = foo; - try expect(@call(.{ .modifier = .no_async }, alias_foo, .{}) == 1234); - try expect(@call(.{ .modifier = .never_tail }, alias_foo, .{}) == 1234); - try expect(@call(.{ .modifier = .never_inline }, alias_foo, .{}) == 1234); - } -} - -test "tuple parameters" { - const add = struct { - fn add(a: i32, b: i32) i32 { - return a + b; - } - }.add; - var a: i32 = 12; - var b: i32 = 34; - try expect(@call(.{}, add, .{ a, 34 }) == 46); - try expect(@call(.{}, add, .{ 12, b }) == 46); - try expect(@call(.{}, add, .{ a, b }) == 46); - try expect(@call(.{}, add, .{ 12, 34 }) == 46); - comptime try expect(@call(.{}, add, .{ 12, 34 }) == 46); - { - const separate_args0 = .{ a, b }; - const separate_args1 = .{ a, 34 }; - const separate_args2 = .{ 12, 34 }; - const separate_args3 = .{ 12, b }; - try expect(@call(.{ .modifier = .always_inline }, add, separate_args0) == 46); - try expect(@call(.{ .modifier = .always_inline }, add, separate_args1) == 46); - try expect(@call(.{ .modifier = .always_inline }, add, separate_args2) == 46); - try expect(@call(.{ .modifier = .always_inline }, add, separate_args3) == 46); - } -} - -test "comptime call with bound function as parameter" { - const S = struct { - fn ReturnType(func: anytype) type { - return switch (@typeInfo(@TypeOf(func))) { - .BoundFn => |info| info, - else => unreachable, - }.return_type orelse void; - } - - fn call_me_maybe() ?i32 { - return 123; - } - }; - - var inst: S = undefined; - try expectEqual(?i32, S.ReturnType(inst.call_me_maybe)); -} diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 3cb1bcf43b..d58ad6ccb5 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -132,3 +132,349 @@ fn foo2(f: fn () anyerror!void) void { } fn bar2() (error{}!void) {} + +test "error union type " { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try testErrorUnionType(); + comptime try testErrorUnionType(); +} + +fn testErrorUnionType() !void { + const x: anyerror!i32 = 1234; + if (x) |value| try expect(value == 1234) else |_| unreachable; + try expect(@typeInfo(@TypeOf(x)) == .ErrorUnion); + try expect(@typeInfo(@typeInfo(@TypeOf(x)).ErrorUnion.error_set) == .ErrorSet); + try expect(@typeInfo(@TypeOf(x)).ErrorUnion.error_set == anyerror); +} + +test "error set type" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try testErrorSetType(); + comptime try testErrorSetType(); +} + +const MyErrSet = error{ + OutOfMemory, + FileNotFound, +}; + +fn testErrorSetType() !void { + try expect(@typeInfo(MyErrSet).ErrorSet.?.len == 2); + + const a: MyErrSet!i32 = 5678; + const b: MyErrSet!i32 = MyErrSet.OutOfMemory; + try expect(b catch error.OutOfMemory == error.OutOfMemory); + + if (a) |value| try expect(value == 5678) else |err| switch (err) { + error.OutOfMemory => unreachable, + error.FileNotFound => unreachable, + } +} + +test "explicit error set cast" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try testExplicitErrorSetCast(Set1.A); + comptime try testExplicitErrorSetCast(Set1.A); +} + +const Set1 = error{ A, B }; +const Set2 = error{ A, C }; + +fn testExplicitErrorSetCast(set1: Set1) !void { + var x = @errSetCast(Set2, set1); + var y = @errSetCast(Set1, x); + try expect(y == error.A); +} + +test "comptime test error for empty error set" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try testComptimeTestErrorEmptySet(1234); + comptime try testComptimeTestErrorEmptySet(1234); +} + +const EmptyErrorSet = error{}; + +fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) !void { + if (x) |v| try expect(v == 1234) else |err| { + _ = err; + @compileError("bad"); + } +} + +test "comptime err to int of error set with only 1 possible value" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); + comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); +} +fn testErrToIntWithOnePossibleValue( + x: error{A}, + comptime value: u32, +) void { + if (@errorToInt(x) != value) { + @compileError("bad"); + } +} + +test "error union peer type resolution" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try testErrorUnionPeerTypeResolution(1); +} + +fn testErrorUnionPeerTypeResolution(x: i32) !void { + const y = switch (x) { + 1 => bar_1(), + 2 => baz_1(), + else => quux_1(), + }; + if (y) |_| { + @panic("expected error"); + } else |e| { + try expect(e == error.A); + } +} + +fn bar_1() anyerror { + return error.A; +} + +fn baz_1() !i32 { + return error.B; +} + +fn quux_1() !i32 { + return error.C; +} + +test "error: Zero sized error set returned with value payload crash" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + _ = foo3(0) catch {}; + _ = comptime foo3(0) catch {}; +} + +const Error = error{}; +fn foo3(b: usize) Error!usize { + return b; +} + +test "error: Infer error set from literals" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + _ = nullLiteral("n") catch |err| handleErrors(err); + _ = floatLiteral("n") catch |err| handleErrors(err); + _ = intLiteral("n") catch |err| handleErrors(err); + _ = comptime nullLiteral("n") catch |err| handleErrors(err); + _ = comptime floatLiteral("n") catch |err| handleErrors(err); + _ = comptime intLiteral("n") catch |err| handleErrors(err); +} + +fn handleErrors(err: anytype) noreturn { + switch (err) { + error.T => {}, + } + + unreachable; +} + +fn nullLiteral(str: []const u8) !?i64 { + if (str[0] == 'n') return null; + + return error.T; +} + +fn floatLiteral(str: []const u8) !?f64 { + if (str[0] == 'n') return 1.0; + + return error.T; +} + +fn intLiteral(str: []const u8) !?i64 { + if (str[0] == 'n') return 1; + + return error.T; +} + +test "nested error union function call in optional unwrap" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + const Foo = struct { + a: i32, + }; + + fn errorable() !i32 { + var x: Foo = (try getFoo()) orelse return error.Other; + return x.a; + } + + fn errorable2() !i32 { + var x: Foo = (try getFoo2()) orelse return error.Other; + return x.a; + } + + fn errorable3() !i32 { + var x: Foo = (try getFoo3()) orelse return error.Other; + return x.a; + } + + fn getFoo() anyerror!?Foo { + return Foo{ .a = 1234 }; + } + + fn getFoo2() anyerror!?Foo { + return error.Failure; + } + + fn getFoo3() anyerror!?Foo { + return null; + } + }; + try expect((try S.errorable()) == 1234); + try expectError(error.Failure, S.errorable2()); + try expectError(error.Other, S.errorable3()); + comptime { + try expect((try S.errorable()) == 1234); + try expectError(error.Failure, S.errorable2()); + try expectError(error.Other, S.errorable3()); + } +} + +test "return function call to error set from error union function" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn errorable() anyerror!i32 { + return fail(); + } + + fn fail() anyerror { + return error.Failure; + } + }; + try expectError(error.Failure, S.errorable()); + comptime try expectError(error.Failure, S.errorable()); +} + +test "optional error set is the same size as error set" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror)); + const S = struct { + fn returnsOptErrSet() ?anyerror { + return null; + } + }; + try expect(S.returnsOptErrSet() == null); + comptime try expect(S.returnsOptErrSet() == null); +} + +test "nested catch" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn entry() !void { + try expectError(error.Bad, func()); + } + fn fail() anyerror!Foo { + return error.Wrong; + } + fn func() anyerror!Foo { + _ = fail() catch + fail() catch + return error.Bad; + unreachable; + } + const Foo = struct { + field: i32, + }; + }; + try S.entry(); + comptime try S.entry(); +} + +test "function pointer with return type that is error union with payload which is pointer of parent struct" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + const Foo = struct { + fun: fn (a: i32) (anyerror!*Foo), + }; + + const Err = error{UnspecifiedErr}; + + fn bar(a: i32) anyerror!*Foo { + _ = a; + return Err.UnspecifiedErr; + } + + fn doTheTest() !void { + var x = Foo{ .fun = @This().bar }; + try expectError(error.UnspecifiedErr, x.fun(1)); + } + }; + try S.doTheTest(); +} + +test "return result loc as peer result loc in inferred error set function" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + if (quux(2)) |x| { + try expect(x.Two); + } else |e| switch (e) { + error.Whatever => @panic("fail"), + } + try expectError(error.Whatever, quux(99)); + } + const FormValue = union(enum) { + One: void, + Two: bool, + }; + + fn quux(id: u64) !FormValue { + return switch (id) { + 2 => FormValue{ .Two = true }, + 1 => FormValue{ .One = {} }, + else => return error.Whatever, + }; + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "error payload type is correctly resolved" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const MyIntWrapper = struct { + const Self = @This(); + + x: i32, + + pub fn create() anyerror!Self { + return Self{ .x = 42 }; + } + }; + + try expectEqual(MyIntWrapper{ .x = 42 }, try MyIntWrapper.create()); +} + +test "error union comptime caching" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn quux(comptime arg: anytype) void { + arg catch {}; + } + }; + + S.quux(@as(anyerror!void, {})); + S.quux(@as(anyerror!void, {})); +} diff --git a/test/behavior/error_stage1.zig b/test/behavior/error_stage1.zig deleted file mode 100644 index 2e4a6facf0..0000000000 --- a/test/behavior/error_stage1.zig +++ /dev/null @@ -1,319 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const expectError = std.testing.expectError; -const expectEqual = std.testing.expectEqual; -const mem = std.mem; - -test "error union type " { - try testErrorUnionType(); - comptime try testErrorUnionType(); -} - -fn testErrorUnionType() !void { - const x: anyerror!i32 = 1234; - if (x) |value| try expect(value == 1234) else |_| unreachable; - try expect(@typeInfo(@TypeOf(x)) == .ErrorUnion); - try expect(@typeInfo(@typeInfo(@TypeOf(x)).ErrorUnion.error_set) == .ErrorSet); - try expect(@typeInfo(@TypeOf(x)).ErrorUnion.error_set == anyerror); -} - -test "error set type" { - try testErrorSetType(); - comptime try testErrorSetType(); -} - -const MyErrSet = error{ - OutOfMemory, - FileNotFound, -}; - -fn testErrorSetType() !void { - try expect(@typeInfo(MyErrSet).ErrorSet.?.len == 2); - - const a: MyErrSet!i32 = 5678; - const b: MyErrSet!i32 = MyErrSet.OutOfMemory; - try expect(b catch error.OutOfMemory == error.OutOfMemory); - - if (a) |value| try expect(value == 5678) else |err| switch (err) { - error.OutOfMemory => unreachable, - error.FileNotFound => unreachable, - } -} - -test "explicit error set cast" { - try testExplicitErrorSetCast(Set1.A); - comptime try testExplicitErrorSetCast(Set1.A); -} - -const Set1 = error{ A, B }; -const Set2 = error{ A, C }; - -fn testExplicitErrorSetCast(set1: Set1) !void { - var x = @errSetCast(Set2, set1); - var y = @errSetCast(Set1, x); - try expect(y == error.A); -} - -test "comptime test error for empty error set" { - try testComptimeTestErrorEmptySet(1234); - comptime try testComptimeTestErrorEmptySet(1234); -} - -const EmptyErrorSet = error{}; - -fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) !void { - if (x) |v| try expect(v == 1234) else |err| { - _ = err; - @compileError("bad"); - } -} - -test "comptime err to int of error set with only 1 possible value" { - testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); - comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); -} -fn testErrToIntWithOnePossibleValue( - x: error{A}, - comptime value: u32, -) void { - if (@errorToInt(x) != value) { - @compileError("bad"); - } -} - -test "error union peer type resolution" { - try testErrorUnionPeerTypeResolution(1); -} - -fn testErrorUnionPeerTypeResolution(x: i32) !void { - const y = switch (x) { - 1 => bar_1(), - 2 => baz_1(), - else => quux_1(), - }; - if (y) |_| { - @panic("expected error"); - } else |e| { - try expect(e == error.A); - } -} - -fn bar_1() anyerror { - return error.A; -} - -fn baz_1() !i32 { - return error.B; -} - -fn quux_1() !i32 { - return error.C; -} - -test "error: Zero sized error set returned with value payload crash" { - _ = foo3(0) catch {}; - _ = comptime foo3(0) catch {}; -} - -const Error = error{}; -fn foo3(b: usize) Error!usize { - return b; -} - -test "error: Infer error set from literals" { - _ = nullLiteral("n") catch |err| handleErrors(err); - _ = floatLiteral("n") catch |err| handleErrors(err); - _ = intLiteral("n") catch |err| handleErrors(err); - _ = comptime nullLiteral("n") catch |err| handleErrors(err); - _ = comptime floatLiteral("n") catch |err| handleErrors(err); - _ = comptime intLiteral("n") catch |err| handleErrors(err); -} - -fn handleErrors(err: anytype) noreturn { - switch (err) { - error.T => {}, - } - - unreachable; -} - -fn nullLiteral(str: []const u8) !?i64 { - if (str[0] == 'n') return null; - - return error.T; -} - -fn floatLiteral(str: []const u8) !?f64 { - if (str[0] == 'n') return 1.0; - - return error.T; -} - -fn intLiteral(str: []const u8) !?i64 { - if (str[0] == 'n') return 1; - - return error.T; -} - -test "nested error union function call in optional unwrap" { - const S = struct { - const Foo = struct { - a: i32, - }; - - fn errorable() !i32 { - var x: Foo = (try getFoo()) orelse return error.Other; - return x.a; - } - - fn errorable2() !i32 { - var x: Foo = (try getFoo2()) orelse return error.Other; - return x.a; - } - - fn errorable3() !i32 { - var x: Foo = (try getFoo3()) orelse return error.Other; - return x.a; - } - - fn getFoo() anyerror!?Foo { - return Foo{ .a = 1234 }; - } - - fn getFoo2() anyerror!?Foo { - return error.Failure; - } - - fn getFoo3() anyerror!?Foo { - return null; - } - }; - try expect((try S.errorable()) == 1234); - try expectError(error.Failure, S.errorable2()); - try expectError(error.Other, S.errorable3()); - comptime { - try expect((try S.errorable()) == 1234); - try expectError(error.Failure, S.errorable2()); - try expectError(error.Other, S.errorable3()); - } -} - -test "return function call to error set from error union function" { - const S = struct { - fn errorable() anyerror!i32 { - return fail(); - } - - fn fail() anyerror { - return error.Failure; - } - }; - try expectError(error.Failure, S.errorable()); - comptime try expectError(error.Failure, S.errorable()); -} - -test "optional error set is the same size as error set" { - comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror)); - const S = struct { - fn returnsOptErrSet() ?anyerror { - return null; - } - }; - try expect(S.returnsOptErrSet() == null); - comptime try expect(S.returnsOptErrSet() == null); -} - -test "nested catch" { - const S = struct { - fn entry() !void { - try expectError(error.Bad, func()); - } - fn fail() anyerror!Foo { - return error.Wrong; - } - fn func() anyerror!Foo { - _ = fail() catch - fail() catch - return error.Bad; - unreachable; - } - const Foo = struct { - field: i32, - }; - }; - try S.entry(); - comptime try S.entry(); -} - -test "function pointer with return type that is error union with payload which is pointer of parent struct" { - const S = struct { - const Foo = struct { - fun: fn (a: i32) (anyerror!*Foo), - }; - - const Err = error{UnspecifiedErr}; - - fn bar(a: i32) anyerror!*Foo { - _ = a; - return Err.UnspecifiedErr; - } - - fn doTheTest() !void { - var x = Foo{ .fun = @This().bar }; - try expectError(error.UnspecifiedErr, x.fun(1)); - } - }; - try S.doTheTest(); -} - -test "return result loc as peer result loc in inferred error set function" { - const S = struct { - fn doTheTest() !void { - if (quux(2)) |x| { - try expect(x.Two); - } else |e| switch (e) { - error.Whatever => @panic("fail"), - } - try expectError(error.Whatever, quux(99)); - } - const FormValue = union(enum) { - One: void, - Two: bool, - }; - - fn quux(id: u64) !FormValue { - return switch (id) { - 2 => FormValue{ .Two = true }, - 1 => FormValue{ .One = {} }, - else => return error.Whatever, - }; - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "error payload type is correctly resolved" { - const MyIntWrapper = struct { - const Self = @This(); - - x: i32, - - pub fn create() anyerror!Self { - return Self{ .x = 42 }; - } - }; - - try expectEqual(MyIntWrapper{ .x = 42 }, try MyIntWrapper.create()); -} - -test "error union comptime caching" { - const S = struct { - fn quux(comptime arg: anytype) void { - arg catch {}; - } - }; - - S.quux(@as(anyerror!void, {})); - S.quux(@as(anyerror!void, {})); -} diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index f1107cef07..72f5fd9594 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -163,3 +163,49 @@ test "generic fn keeps non-generic parameter types" { var x: [16]u8 align(A) = undefined; try S.f(u8, &x); } + +test "array of generic fns" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + try expect(foos[0](true)); + try expect(!foos[1](true)); +} + +const foos = [_]fn (anytype) bool{ + foo1, + foo2, +}; + +fn foo1(arg: anytype) bool { + return arg; +} +fn foo2(arg: anytype) bool { + return !arg; +} + +test "generic struct" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + var a1 = GenNode(i32){ + .value = 13, + .next = null, + }; + var b1 = GenNode(bool){ + .value = true, + .next = null, + }; + try expect(a1.value == 13); + try expect(a1.value == a1.getVal()); + try expect(b1.getVal()); +} +fn GenNode(comptime T: type) type { + return struct { + value: T, + next: ?*GenNode(T), + fn getVal(n: *const GenNode(T)) T { + return n.value; + } + }; +} diff --git a/test/behavior/generics_llvm.zig b/test/behavior/generics_llvm.zig deleted file mode 100644 index b8a63d7dd0..0000000000 --- a/test/behavior/generics_llvm.zig +++ /dev/null @@ -1,49 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const builtin = @import("builtin"); - -const foos = [_]fn (anytype) bool{ - foo1, - foo2, -}; - -fn foo1(arg: anytype) bool { - return arg; -} -fn foo2(arg: anytype) bool { - return !arg; -} - -test "array of generic fns" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - try expect(foos[0](true)); - try expect(!foos[1](true)); -} - -test "generic struct" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - var a1 = GenNode(i32){ - .value = 13, - .next = null, - }; - var b1 = GenNode(bool){ - .value = true, - .next = null, - }; - try expect(a1.value == 13); - try expect(a1.value == a1.getVal()); - try expect(b1.getVal()); -} -fn GenNode(comptime T: type) type { - return struct { - value: T, - next: ?*GenNode(T), - fn getVal(n: *const GenNode(T)) T { - return n.value; - } - }; -} diff --git a/test/behavior/saturating_arithmetic.zig b/test/behavior/saturating_arithmetic.zig index c0f29892a1..ef6c24a389 100644 --- a/test/behavior/saturating_arithmetic.zig +++ b/test/behavior/saturating_arithmetic.zig @@ -118,3 +118,25 @@ test "saturating shift-left" { try S.doTheTest(); comptime try S.doTheTest(); } + +test "saturating shl uses the LHS type" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const lhs_const: u8 = 1; + var lhs_var: u8 = 1; + + const rhs_const: usize = 8; + var rhs_var: usize = 8; + + try expect((lhs_const <<| 8) == 255); + try expect((lhs_const <<| rhs_const) == 255); + try expect((lhs_const <<| rhs_var) == 255); + + try expect((lhs_var <<| 8) == 255); + try expect((lhs_var <<| rhs_const) == 255); + try expect((lhs_var <<| rhs_var) == 255); + + try expect((@as(u8, 1) <<| 8) == 255); + try expect((@as(u8, 1) <<| rhs_const) == 255); + try expect((@as(u8, 1) <<| rhs_var) == 255); +} diff --git a/test/behavior/saturating_arithmetic_stage1.zig b/test/behavior/saturating_arithmetic_stage1.zig deleted file mode 100644 index 242e74a3fc..0000000000 --- a/test/behavior/saturating_arithmetic_stage1.zig +++ /dev/null @@ -1,22 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; - -test "saturating shl uses the LHS type" { - const lhs_const: u8 = 1; - var lhs_var: u8 = 1; - - const rhs_const: usize = 8; - var rhs_var: usize = 8; - - try expect((lhs_const <<| 8) == 255); - try expect((lhs_const <<| rhs_const) == 255); - try expect((lhs_const <<| rhs_var) == 255); - - try expect((lhs_var <<| 8) == 255); - try expect((lhs_var <<| rhs_const) == 255); - try expect((lhs_var <<| rhs_var) == 255); - - try expect((@as(u8, 1) <<| 8) == 255); - try expect((@as(u8, 1) <<| rhs_const) == 255); - try expect((@as(u8, 1) <<| rhs_var) == 255); -} diff --git a/test/behavior/struct_llvm.zig b/test/behavior/struct_llvm.zig index a6bd9170f3..5aaefc8b38 100644 --- a/test/behavior/struct_llvm.zig +++ b/test/behavior/struct_llvm.zig @@ -305,3 +305,513 @@ test "default struct initialization fields" { try expect(y.b == x.b); try expect(1239 == x.a + x.b); } + +// TODO revisit this test when doing https://github.com/ziglang/zig/issues/1512 +test "packed array 24bits" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + comptime { + try expect(@sizeOf([9]Foo32Bits) == 9 * 4); + try expect(@sizeOf(FooArray24Bits) == 2 + 2 * 4 + 2); + } + + var bytes = [_]u8{0} ** (@sizeOf(FooArray24Bits) + 1); + bytes[bytes.len - 1] = 0xaa; + const ptr = &std.mem.bytesAsSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; + try expect(ptr.a == 0); + try expect(ptr.b[0].field == 0); + try expect(ptr.b[1].field == 0); + try expect(ptr.c == 0); + + ptr.a = maxInt(u16); + try expect(ptr.a == maxInt(u16)); + try expect(ptr.b[0].field == 0); + try expect(ptr.b[1].field == 0); + try expect(ptr.c == 0); + + ptr.b[0].field = maxInt(u24); + try expect(ptr.a == maxInt(u16)); + try expect(ptr.b[0].field == maxInt(u24)); + try expect(ptr.b[1].field == 0); + try expect(ptr.c == 0); + + ptr.b[1].field = maxInt(u24); + try expect(ptr.a == maxInt(u16)); + try expect(ptr.b[0].field == maxInt(u24)); + try expect(ptr.b[1].field == maxInt(u24)); + try expect(ptr.c == 0); + + ptr.c = maxInt(u16); + try expect(ptr.a == maxInt(u16)); + try expect(ptr.b[0].field == maxInt(u24)); + try expect(ptr.b[1].field == maxInt(u24)); + try expect(ptr.c == maxInt(u16)); + + try expect(bytes[bytes.len - 1] == 0xaa); +} + +const Foo32Bits = packed struct { + field: u24, + pad: u8, +}; + +const FooArray24Bits = packed struct { + a: u16, + b: [2]Foo32Bits, + c: u16, +}; + +test "aligned array of packed struct" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + comptime { + try expect(@sizeOf(FooStructAligned) == 2); + try expect(@sizeOf(FooArrayOfAligned) == 2 * 2); + } + + var bytes = [_]u8{0xbb} ** @sizeOf(FooArrayOfAligned); + const ptr = &std.mem.bytesAsSlice(FooArrayOfAligned, bytes[0..])[0]; + + try expect(ptr.a[0].a == 0xbb); + try expect(ptr.a[0].b == 0xbb); + try expect(ptr.a[1].a == 0xbb); + try expect(ptr.a[1].b == 0xbb); +} + +const FooStructAligned = packed struct { + a: u8, + b: u8, +}; + +const FooArrayOfAligned = packed struct { + a: [2]FooStructAligned, +}; + +test "pointer to packed struct member in a stack variable" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = packed struct { + a: u2, + b: u2, + }; + + var s = S{ .a = 2, .b = 0 }; + var b_ptr = &s.b; + try expect(s.b == 0); + b_ptr.* = 2; + try expect(s.b == 2); +} + +test "non-byte-aligned array inside packed struct" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const Foo = packed struct { + a: bool, + b: [0x16]u8, + }; + const S = struct { + fn bar(slice: []const u8) !void { + try expectEqualSlices(u8, slice, "abcdefghijklmnopqurstu"); + } + fn doTheTest() !void { + var foo = Foo{ + .a = true, + .b = "abcdefghijklmnopqurstu".*, + }; + const value = foo.b; + try bar(&value); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "packed struct with u0 field access" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = packed struct { + f0: u0, + }; + var s = S{ .f0 = 0 }; + comptime try expect(s.f0 == 0); +} + +test "access to global struct fields" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + g_foo.bar.value = 42; + try expect(g_foo.bar.value == 42); +} + +const S0 = struct { + bar: S1, + + pub const S1 = struct { + value: u8, + }; + + fn init() @This() { + return S0{ .bar = S1{ .value = 123 } }; + } +}; + +var g_foo: S0 = S0.init(); + +test "packed struct with fp fields" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = packed struct { + data: [3]f32, + + pub fn frob(self: *@This()) void { + self.data[0] += self.data[1] + self.data[2]; + self.data[1] += self.data[0] + self.data[2]; + self.data[2] += self.data[0] + self.data[1]; + } + }; + + var s: S = undefined; + s.data[0] = 1.0; + s.data[1] = 2.0; + s.data[2] = 3.0; + s.frob(); + try expectEqual(@as(f32, 6.0), s.data[0]); + try expectEqual(@as(f32, 11.0), s.data[1]); + try expectEqual(@as(f32, 20.0), s.data[2]); +} + +test "fn with C calling convention returns struct by value" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn entry() !void { + var x = makeBar(10); + try expectEqual(@as(i32, 10), x.handle); + } + + const ExternBar = extern struct { + handle: i32, + }; + + fn makeBar(t: i32) callconv(.C) ExternBar { + return ExternBar{ + .handle = t, + }; + } + }; + try S.entry(); + comptime try S.entry(); +} + +test "non-packed struct with u128 entry in union" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const U = union(enum) { + Num: u128, + Void, + }; + + const S = struct { + f1: U, + f2: U, + }; + + var sx: S = undefined; + var s = &sx; + try std.testing.expect(@ptrToInt(&s.f2) - @ptrToInt(&s.f1) == @offsetOf(S, "f2")); + var v2 = U{ .Num = 123 }; + s.f2 = v2; + try std.testing.expect(s.f2.Num == 123); +} + +test "packed struct field passed to generic function" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + const P = packed struct { + b: u5, + g: u5, + r: u5, + a: u1, + }; + + fn genericReadPackedField(ptr: anytype) u5 { + return ptr.*; + } + }; + + var p: S.P = undefined; + p.b = 29; + var loaded = S.genericReadPackedField(&p.b); + try expect(loaded == 29); +} + +test "anonymous struct literal syntax" { + const S = struct { + const Point = struct { + x: i32, + y: i32, + }; + + fn doTheTest() !void { + var p: Point = .{ + .x = 1, + .y = 2, + }; + try expect(p.x == 1); + try expect(p.y == 2); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "fully anonymous struct" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + try dump(.{ + .int = @as(u32, 1234), + .float = @as(f64, 12.34), + .b = true, + .s = "hi", + }); + } + fn dump(args: anytype) !void { + try expect(args.int == 1234); + try expect(args.float == 12.34); + try expect(args.b); + try expect(args.s[0] == 'h'); + try expect(args.s[1] == 'i'); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "fully anonymous list literal" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + try dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi" }); + } + fn dump(args: anytype) !void { + try expect(args.@"0" == 1234); + try expect(args.@"1" == 12.34); + try expect(args.@"2"); + try expect(args.@"3"[0] == 'h'); + try expect(args.@"3"[1] == 'i'); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "anonymous struct literal assigned to variable" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + var vec = .{ @as(i32, 22), @as(i32, 55), @as(i32, 99) }; + try expect(vec.@"0" == 22); + try expect(vec.@"1" == 55); + try expect(vec.@"2" == 99); +} + +test "struct with var field" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const Point = struct { + x: anytype, + y: anytype, + }; + const pt = Point{ + .x = 1, + .y = 2, + }; + try expect(pt.x == 1); + try expect(pt.y == 2); +} + +test "comptime struct field" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const T = struct { + a: i32, + comptime b: i32 = 1234, + }; + + var foo: T = undefined; + comptime try expect(foo.b == 1234); +} + +test "anon struct literal field value initialized with fn call" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + var x = .{foo()}; + try expectEqualSlices(u8, x[0], "hi"); + } + fn foo() []const u8 { + return "hi"; + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "struct with union field" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const Value = struct { + ref: u32 = 2, + kind: union(enum) { + None: usize, + Bool: bool, + }, + }; + + var True = Value{ + .kind = .{ .Bool = true }, + }; + try expectEqual(@as(u32, 2), True.ref); + try expectEqual(true, True.kind.Bool); +} + +test "type coercion of anon struct literal to struct" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + const S2 = struct { + A: u32, + B: []const u8, + C: void, + D: Foo = .{}, + }; + + const Foo = struct { + field: i32 = 1234, + }; + + fn doTheTest() !void { + var y: u32 = 42; + const t0 = .{ .A = 123, .B = "foo", .C = {} }; + const t1 = .{ .A = y, .B = "foo", .C = {} }; + const y0: S2 = t0; + var y1: S2 = t1; + try expect(y0.A == 123); + try expect(std.mem.eql(u8, y0.B, "foo")); + try expect(y0.C == {}); + try expect(y0.D.field == 1234); + try expect(y1.A == y); + try expect(std.mem.eql(u8, y1.B, "foo")); + try expect(y1.C == {}); + try expect(y1.D.field == 1234); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "type coercion of pointer to anon struct literal to pointer to struct" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + const S2 = struct { + A: u32, + B: []const u8, + C: void, + D: Foo = .{}, + }; + + const Foo = struct { + field: i32 = 1234, + }; + + fn doTheTest() !void { + var y: u32 = 42; + const t0 = &.{ .A = 123, .B = "foo", .C = {} }; + const t1 = &.{ .A = y, .B = "foo", .C = {} }; + const y0: *const S2 = t0; + var y1: *const S2 = t1; + try expect(y0.A == 123); + try expect(std.mem.eql(u8, y0.B, "foo")); + try expect(y0.C == {}); + try expect(y0.D.field == 1234); + try expect(y1.A == y); + try expect(std.mem.eql(u8, y1.B, "foo")); + try expect(y1.C == {}); + try expect(y1.D.field == 1234); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "packed struct with undefined initializers" { + const S = struct { + const P = packed struct { + a: u3, + _a: u3 = undefined, + b: u3, + _b: u3 = undefined, + c: u3, + _c: u3 = undefined, + }; + + fn doTheTest() !void { + var p: P = undefined; + p = P{ .a = 2, .b = 4, .c = 6 }; + // Make sure the compiler doesn't touch the unprefixed fields. + // Use expect since i386-linux doesn't like expectEqual + try expect(p.a == 2); + try expect(p.b == 4); + try expect(p.c == 6); + } + }; + + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "for loop over pointers to struct, getting field from struct pointer" { + // When enabling this test, be careful. I have observed it to pass when compiling + // stage2 alone, but when using stage1 with -fno-stage1 -fLLVM it fails. + // Maybe eyeball the LLVM that it generates and run in valgrind, both the compiler + // and the generated test at runtime. + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + const Foo = struct { + name: []const u8, + }; + + var ok = true; + + fn eql(a: []const u8) bool { + _ = a; + return true; + } + + const ArrayList = struct { + fn toSlice(self: *ArrayList) []*Foo { + _ = self; + return @as([*]*Foo, undefined)[0..0]; + } + }; + + fn doTheTest() !void { + var objects: ArrayList = undefined; + + for (objects.toSlice()) |obj| { + if (eql(obj.name)) { + ok = false; + } + } + + try expect(ok); + } + }; + try S.doTheTest(); +} diff --git a/test/behavior/struct_stage1.zig b/test/behavior/struct_stage1.zig deleted file mode 100644 index f079302f43..0000000000 --- a/test/behavior/struct_stage1.zig +++ /dev/null @@ -1,473 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const native_endian = builtin.target.cpu.arch.endian(); -const expect = std.testing.expect; -const expectEqual = std.testing.expectEqual; -const expectEqualSlices = std.testing.expectEqualSlices; -const maxInt = std.math.maxInt; - -const Foo32Bits = packed struct { - field: u24, - pad: u8, -}; - -const FooArray24Bits = packed struct { - a: u16, - b: [2]Foo32Bits, - c: u16, -}; - -// TODO revisit this test when doing https://github.com/ziglang/zig/issues/1512 -test "packed array 24bits" { - comptime { - try expect(@sizeOf([9]Foo32Bits) == 9 * 4); - try expect(@sizeOf(FooArray24Bits) == 2 + 2 * 4 + 2); - } - - var bytes = [_]u8{0} ** (@sizeOf(FooArray24Bits) + 1); - bytes[bytes.len - 1] = 0xaa; - const ptr = &std.mem.bytesAsSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; - try expect(ptr.a == 0); - try expect(ptr.b[0].field == 0); - try expect(ptr.b[1].field == 0); - try expect(ptr.c == 0); - - ptr.a = maxInt(u16); - try expect(ptr.a == maxInt(u16)); - try expect(ptr.b[0].field == 0); - try expect(ptr.b[1].field == 0); - try expect(ptr.c == 0); - - ptr.b[0].field = maxInt(u24); - try expect(ptr.a == maxInt(u16)); - try expect(ptr.b[0].field == maxInt(u24)); - try expect(ptr.b[1].field == 0); - try expect(ptr.c == 0); - - ptr.b[1].field = maxInt(u24); - try expect(ptr.a == maxInt(u16)); - try expect(ptr.b[0].field == maxInt(u24)); - try expect(ptr.b[1].field == maxInt(u24)); - try expect(ptr.c == 0); - - ptr.c = maxInt(u16); - try expect(ptr.a == maxInt(u16)); - try expect(ptr.b[0].field == maxInt(u24)); - try expect(ptr.b[1].field == maxInt(u24)); - try expect(ptr.c == maxInt(u16)); - - try expect(bytes[bytes.len - 1] == 0xaa); -} - -const FooStructAligned = packed struct { - a: u8, - b: u8, -}; - -const FooArrayOfAligned = packed struct { - a: [2]FooStructAligned, -}; - -test "aligned array of packed struct" { - comptime { - try expect(@sizeOf(FooStructAligned) == 2); - try expect(@sizeOf(FooArrayOfAligned) == 2 * 2); - } - - var bytes = [_]u8{0xbb} ** @sizeOf(FooArrayOfAligned); - const ptr = &std.mem.bytesAsSlice(FooArrayOfAligned, bytes[0..])[0]; - - try expect(ptr.a[0].a == 0xbb); - try expect(ptr.a[0].b == 0xbb); - try expect(ptr.a[1].a == 0xbb); - try expect(ptr.a[1].b == 0xbb); -} - -test "pointer to packed struct member in a stack variable" { - const S = packed struct { - a: u2, - b: u2, - }; - - var s = S{ .a = 2, .b = 0 }; - var b_ptr = &s.b; - try expect(s.b == 0); - b_ptr.* = 2; - try expect(s.b == 2); -} - -test "non-byte-aligned array inside packed struct" { - const Foo = packed struct { - a: bool, - b: [0x16]u8, - }; - const S = struct { - fn bar(slice: []const u8) !void { - try expectEqualSlices(u8, slice, "abcdefghijklmnopqurstu"); - } - fn doTheTest() !void { - var foo = Foo{ - .a = true, - .b = "abcdefghijklmnopqurstu".*, - }; - const value = foo.b; - try bar(&value); - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "packed struct with u0 field access" { - const S = packed struct { - f0: u0, - }; - var s = S{ .f0 = 0 }; - comptime try expect(s.f0 == 0); -} - -const S0 = struct { - bar: S1, - - pub const S1 = struct { - value: u8, - }; - - fn init() @This() { - return S0{ .bar = S1{ .value = 123 } }; - } -}; - -var g_foo: S0 = S0.init(); - -test "access to global struct fields" { - g_foo.bar.value = 42; - try expect(g_foo.bar.value == 42); -} - -test "packed struct with fp fields" { - const S = packed struct { - data: [3]f32, - - pub fn frob(self: *@This()) void { - self.data[0] += self.data[1] + self.data[2]; - self.data[1] += self.data[0] + self.data[2]; - self.data[2] += self.data[0] + self.data[1]; - } - }; - - var s: S = undefined; - s.data[0] = 1.0; - s.data[1] = 2.0; - s.data[2] = 3.0; - s.frob(); - try expectEqual(@as(f32, 6.0), s.data[0]); - try expectEqual(@as(f32, 11.0), s.data[1]); - try expectEqual(@as(f32, 20.0), s.data[2]); -} - -test "fn with C calling convention returns struct by value" { - const S = struct { - fn entry() !void { - var x = makeBar(10); - try expectEqual(@as(i32, 10), x.handle); - } - - const ExternBar = extern struct { - handle: i32, - }; - - fn makeBar(t: i32) callconv(.C) ExternBar { - return ExternBar{ - .handle = t, - }; - } - }; - try S.entry(); - comptime try S.entry(); -} - -test "non-packed struct with u128 entry in union" { - const U = union(enum) { - Num: u128, - Void, - }; - - const S = struct { - f1: U, - f2: U, - }; - - var sx: S = undefined; - var s = &sx; - try std.testing.expect(@ptrToInt(&s.f2) - @ptrToInt(&s.f1) == @offsetOf(S, "f2")); - var v2 = U{ .Num = 123 }; - s.f2 = v2; - try std.testing.expect(s.f2.Num == 123); -} - -test "packed struct field passed to generic function" { - const S = struct { - const P = packed struct { - b: u5, - g: u5, - r: u5, - a: u1, - }; - - fn genericReadPackedField(ptr: anytype) u5 { - return ptr.*; - } - }; - - var p: S.P = undefined; - p.b = 29; - var loaded = S.genericReadPackedField(&p.b); - try expect(loaded == 29); -} - -test "anonymous struct literal syntax" { - const S = struct { - const Point = struct { - x: i32, - y: i32, - }; - - fn doTheTest() !void { - var p: Point = .{ - .x = 1, - .y = 2, - }; - try expect(p.x == 1); - try expect(p.y == 2); - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "fully anonymous struct" { - const S = struct { - fn doTheTest() !void { - try dump(.{ - .int = @as(u32, 1234), - .float = @as(f64, 12.34), - .b = true, - .s = "hi", - }); - } - fn dump(args: anytype) !void { - try expect(args.int == 1234); - try expect(args.float == 12.34); - try expect(args.b); - try expect(args.s[0] == 'h'); - try expect(args.s[1] == 'i'); - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "fully anonymous list literal" { - const S = struct { - fn doTheTest() !void { - try dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi" }); - } - fn dump(args: anytype) !void { - try expect(args.@"0" == 1234); - try expect(args.@"1" == 12.34); - try expect(args.@"2"); - try expect(args.@"3"[0] == 'h'); - try expect(args.@"3"[1] == 'i'); - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "anonymous struct literal assigned to variable" { - var vec = .{ @as(i32, 22), @as(i32, 55), @as(i32, 99) }; - try expect(vec.@"0" == 22); - try expect(vec.@"1" == 55); - try expect(vec.@"2" == 99); -} - -test "struct with var field" { - const Point = struct { - x: anytype, - y: anytype, - }; - const pt = Point{ - .x = 1, - .y = 2, - }; - try expect(pt.x == 1); - try expect(pt.y == 2); -} - -test "comptime struct field" { - const T = struct { - a: i32, - comptime b: i32 = 1234, - }; - - var foo: T = undefined; - comptime try expect(foo.b == 1234); -} - -test "anon struct literal field value initialized with fn call" { - const S = struct { - fn doTheTest() !void { - var x = .{foo()}; - try expectEqualSlices(u8, x[0], "hi"); - } - fn foo() []const u8 { - return "hi"; - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "struct with union field" { - const Value = struct { - ref: u32 = 2, - kind: union(enum) { - None: usize, - Bool: bool, - }, - }; - - var True = Value{ - .kind = .{ .Bool = true }, - }; - try expectEqual(@as(u32, 2), True.ref); - try expectEqual(true, True.kind.Bool); -} - -test "type coercion of anon struct literal to struct" { - const S = struct { - const S2 = struct { - A: u32, - B: []const u8, - C: void, - D: Foo = .{}, - }; - - const Foo = struct { - field: i32 = 1234, - }; - - fn doTheTest() !void { - var y: u32 = 42; - const t0 = .{ .A = 123, .B = "foo", .C = {} }; - const t1 = .{ .A = y, .B = "foo", .C = {} }; - const y0: S2 = t0; - var y1: S2 = t1; - try expect(y0.A == 123); - try expect(std.mem.eql(u8, y0.B, "foo")); - try expect(y0.C == {}); - try expect(y0.D.field == 1234); - try expect(y1.A == y); - try expect(std.mem.eql(u8, y1.B, "foo")); - try expect(y1.C == {}); - try expect(y1.D.field == 1234); - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "type coercion of pointer to anon struct literal to pointer to struct" { - const S = struct { - const S2 = struct { - A: u32, - B: []const u8, - C: void, - D: Foo = .{}, - }; - - const Foo = struct { - field: i32 = 1234, - }; - - fn doTheTest() !void { - var y: u32 = 42; - const t0 = &.{ .A = 123, .B = "foo", .C = {} }; - const t1 = &.{ .A = y, .B = "foo", .C = {} }; - const y0: *const S2 = t0; - var y1: *const S2 = t1; - try expect(y0.A == 123); - try expect(std.mem.eql(u8, y0.B, "foo")); - try expect(y0.C == {}); - try expect(y0.D.field == 1234); - try expect(y1.A == y); - try expect(std.mem.eql(u8, y1.B, "foo")); - try expect(y1.C == {}); - try expect(y1.D.field == 1234); - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "packed struct with undefined initializers" { - const S = struct { - const P = packed struct { - a: u3, - _a: u3 = undefined, - b: u3, - _b: u3 = undefined, - c: u3, - _c: u3 = undefined, - }; - - fn doTheTest() !void { - var p: P = undefined; - p = P{ .a = 2, .b = 4, .c = 6 }; - // Make sure the compiler doesn't touch the unprefixed fields. - // Use expect since i386-linux doesn't like expectEqual - try expect(p.a == 2); - try expect(p.b == 4); - try expect(p.c == 6); - } - }; - - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "for loop over pointers to struct, getting field from struct pointer" { - const S = struct { - const Foo = struct { - name: []const u8, - }; - - var ok = true; - - fn eql(a: []const u8) bool { - _ = a; - return true; - } - - const ArrayList = struct { - fn toSlice(self: *ArrayList) []*Foo { - _ = self; - return @as([*]*Foo, undefined)[0..0]; - } - }; - - fn doTheTest() !void { - var objects: ArrayList = undefined; - - for (objects.toSlice()) |obj| { - if (eql(obj.name)) { - ok = false; - } - } - - try expect(ok); - } - }; - try S.doTheTest(); -} diff --git a/test/behavior/translate_c_macros.zig b/test/behavior/translate_c_macros.zig index 0e4841020e..880e1b41df 100644 --- a/test/behavior/translate_c_macros.zig +++ b/test/behavior/translate_c_macros.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("std"); const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; @@ -16,3 +17,33 @@ test "casting to void with a macro" { h.IGNORE_ME_9(42); h.IGNORE_ME_10(42); } + +test "initializer list expression" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try expectEqual(h.Color{ + .r = 200, + .g = 200, + .b = 200, + .a = 255, + }, h.LIGHTGRAY); +} + +test "sizeof in macros" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF(u32)); + try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF2(u32)); +} + +test "reference to a struct type" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO); +} + +test "cast negative integer to pointer" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try expectEqual(@intToPtr(?*anyopaque, @bitCast(usize, @as(isize, -1))), h.MAP_FAILED); +} diff --git a/test/behavior/translate_c_macros_stage1.zig b/test/behavior/translate_c_macros_stage1.zig deleted file mode 100644 index c380508a37..0000000000 --- a/test/behavior/translate_c_macros_stage1.zig +++ /dev/null @@ -1,27 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const expectEqual = std.testing.expectEqual; - -const h = @cImport(@cInclude("behavior/translate_c_macros.h")); - -test "initializer list expression" { - try expectEqual(h.Color{ - .r = 200, - .g = 200, - .b = 200, - .a = 255, - }, h.LIGHTGRAY); -} - -test "sizeof in macros" { - try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF(u32)); - try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF2(u32)); -} - -test "reference to a struct type" { - try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO); -} - -test "cast negative integer to pointer" { - try expectEqual(@intToPtr(?*anyopaque, @bitCast(usize, @as(isize, -1))), h.MAP_FAILED); -}