From 2c9a5e791ba17987061b057083c99158e85f17d1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 25 Jan 2022 23:29:02 -0700 Subject: [PATCH] organize behavior tests Every test that is moved in this commit has been checked to see if it is now passing. --- test/behavior.zig | 14 +- test/behavior/align.zig | 226 +++++++++++++++ test/behavior/align_stage1.zig | 174 ------------ test/behavior/basic.zig | 399 ++++++++++++++++++++++++++ test/behavior/basic_llvm.zig | 250 ---------------- test/behavior/bitcast.zig | 163 +++++++++++ test/behavior/bitcast_stage1.zig | 131 --------- test/behavior/cast.zig | 471 +++++++++++++++++++++++++++++++ test/behavior/cast_stage1.zig | 426 ---------------------------- test/behavior/defer.zig | 56 ++++ test/behavior/defer_stage1.zig | 55 ---- test/behavior/enum.zig | 102 +++++++ test/behavior/enum_stage1.zig | 97 ------- test/behavior/eval.zig | 306 ++++++++++++++++++++ test/behavior/eval_stage1.zig | 266 ----------------- test/behavior/fn.zig | 98 +++++++ test/behavior/fn_stage1.zig | 99 ------- test/behavior/for.zig | 57 ++++ test/behavior/for_stage1.zig | 54 ---- test/behavior/if.zig | 19 ++ test/behavior/if_stage1.zig | 19 -- test/behavior/misc.zig | 130 --------- 22 files changed, 1899 insertions(+), 1713 deletions(-) delete mode 100644 test/behavior/align_stage1.zig delete mode 100644 test/behavior/basic_llvm.zig delete mode 100644 test/behavior/bitcast_stage1.zig delete mode 100644 test/behavior/cast_stage1.zig delete mode 100644 test/behavior/defer_stage1.zig delete mode 100644 test/behavior/enum_stage1.zig delete mode 100644 test/behavior/eval_stage1.zig delete mode 100644 test/behavior/fn_stage1.zig delete mode 100644 test/behavior/for_stage1.zig delete mode 100644 test/behavior/if_stage1.zig diff --git a/test/behavior.zig b/test/behavior.zig index 15fbe8038b..162631ba4e 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -91,8 +91,9 @@ test { // Tests that pass for stage1 and the llvm backend. _ = @import("behavior/array_llvm.zig"); _ = @import("behavior/atomics.zig"); - _ = @import("behavior/basic_llvm.zig"); + _ = @import("behavior/bugs/1025.zig"); _ = @import("behavior/bugs/1741.zig"); + _ = @import("behavior/bugs/1914.zig"); _ = @import("behavior/bugs/2578.zig"); _ = @import("behavior/bugs/3007.zig"); _ = @import("behavior/bugs/9584.zig"); @@ -116,13 +117,11 @@ test { if (builtin.zig_backend == .stage1) { // Tests that only pass for the stage1 backend. - _ = @import("behavior/align_stage1.zig"); if (builtin.os.tag != .wasi) { _ = @import("behavior/asm.zig"); _ = @import("behavior/async_fn.zig"); } _ = @import("behavior/await_struct.zig"); - _ = @import("behavior/bitcast_stage1.zig"); _ = @import("behavior/bitreverse.zig"); _ = @import("behavior/bugs/421.zig"); _ = @import("behavior/bugs/529.zig"); @@ -130,14 +129,12 @@ test { _ = @import("behavior/bugs/726.zig"); _ = @import("behavior/bugs/828.zig"); _ = @import("behavior/bugs/920.zig"); - _ = @import("behavior/bugs/1025.zig"); _ = @import("behavior/bugs/1076.zig"); _ = @import("behavior/bugs/1120.zig"); _ = @import("behavior/bugs/1421.zig"); _ = @import("behavior/bugs/1442.zig"); _ = @import("behavior/bugs/1607.zig"); _ = @import("behavior/bugs/1851.zig"); - _ = @import("behavior/bugs/1914.zig"); _ = @import("behavior/bugs/2114.zig"); _ = @import("behavior/bugs/3384.zig"); _ = @import("behavior/bugs/3742.zig"); @@ -155,18 +152,11 @@ test { _ = @import("behavior/bugs/10147.zig"); _ = @import("behavior/byteswap.zig"); _ = @import("behavior/call_stage1.zig"); - _ = @import("behavior/cast_stage1.zig"); _ = @import("behavior/const_slice_child.zig"); - _ = @import("behavior/defer_stage1.zig"); - _ = @import("behavior/enum_stage1.zig"); _ = @import("behavior/error_stage1.zig"); - _ = @import("behavior/eval_stage1.zig"); _ = @import("behavior/field_parent_ptr.zig"); _ = @import("behavior/floatop_stage1.zig"); - _ = @import("behavior/fn_stage1.zig"); _ = @import("behavior/fn_delegation.zig"); - _ = @import("behavior/for_stage1.zig"); - _ = @import("behavior/if_stage1.zig"); _ = @import("behavior/ir_block_deps.zig"); _ = @import("behavior/math_stage1.zig"); _ = @import("behavior/misc.zig"); diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 1f9ebed497..40b0304371 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -204,3 +204,229 @@ test "function alignment" { noop1(); noop4(); } + +test "implicitly decreasing fn alignment" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + // function alignment is a compile error on wasm32/wasm64 + if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; + + try testImplicitlyDecreaseFnAlign(alignedSmall, 1234); + try testImplicitlyDecreaseFnAlign(alignedBig, 5678); +} + +// TODO make it a compile error to put align on the fn proto instead of on the ptr +fn testImplicitlyDecreaseFnAlign(ptr: *align(1) const fn () i32, answer: i32) !void { + try expect(ptr() == answer); +} + +fn alignedSmall() align(8) i32 { + return 1234; +} +fn alignedBig() align(16) i32 { + return 5678; +} + +test "@alignCast functions" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + // function alignment is a compile error on wasm32/wasm64 + if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; + if (native_arch == .thumb) return error.SkipZigTest; + + try expect(fnExpectsOnly1(simple4) == 0x19); +} +fn fnExpectsOnly1(ptr: *const fn () align(1) i32) i32 { + return fnExpects4(@alignCast(4, ptr)); +} +fn fnExpects4(ptr: *align(4) const fn () i32) i32 { + return ptr(); +} +fn simple4() align(4) i32 { + return 0x19; +} + +test "generic function with align param" { + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + // function alignment is a compile error on wasm32/wasm64 + if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; + if (native_arch == .thumb) return error.SkipZigTest; + + try expect(whyWouldYouEverDoThis(1) == 0x1); + try expect(whyWouldYouEverDoThis(4) == 0x1); + try expect(whyWouldYouEverDoThis(8) == 0x1); +} + +fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { + _ = align_bytes; + return 0x1; +} + +test "runtime known array index has best alignment possible" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + // take full advantage of over-alignment + var array align(4) = [_]u8{ 1, 2, 3, 4 }; + try expect(@TypeOf(&array[0]) == *align(4) u8); + try expect(@TypeOf(&array[1]) == *u8); + try expect(@TypeOf(&array[2]) == *align(2) u8); + try expect(@TypeOf(&array[3]) == *u8); + + // because align is too small but we still figure out to use 2 + var bigger align(2) = [_]u64{ 1, 2, 3, 4 }; + try expect(@TypeOf(&bigger[0]) == *align(2) u64); + try expect(@TypeOf(&bigger[1]) == *align(2) u64); + try expect(@TypeOf(&bigger[2]) == *align(2) u64); + try expect(@TypeOf(&bigger[3]) == *align(2) u64); + + // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 + var smaller align(2) = [_]u32{ 1, 2, 3, 4 }; + var runtime_zero: usize = 0; + comptime try expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32); + comptime try expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32); + try testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32); + try testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32); + try testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32); + try testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32); + + // has to use ABI alignment because index known at runtime only + try testIndex2(array[runtime_zero..].ptr, 0, *u8); + try testIndex2(array[runtime_zero..].ptr, 1, *u8); + try testIndex2(array[runtime_zero..].ptr, 2, *u8); + try testIndex2(array[runtime_zero..].ptr, 3, *u8); +} +fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) !void { + comptime try expect(@TypeOf(&smaller[index]) == T); +} +fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) !void { + comptime try expect(@TypeOf(&ptr[index]) == T); +} + +test "alignment of function with c calling convention" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + + var runtime_nothing = ¬hing; + const casted1 = @ptrCast(*const u8, runtime_nothing); + const casted2 = @ptrCast(*const fn () callconv(.C) void, casted1); + casted2(); +} + +fn nothing() callconv(.C) void {} + +const DefaultAligned = struct { + nevermind: u32, + badguy: i128, +}; + +test "read 128-bit field from default aligned struct in stack memory" { + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + var default_aligned = DefaultAligned{ + .nevermind = 1, + .badguy = 12, + }; + try expect((@ptrToInt(&default_aligned.badguy) % 16) == 0); + try expect(12 == default_aligned.badguy); +} + +var default_aligned_global = DefaultAligned{ + .nevermind = 1, + .badguy = 12, +}; + +test "read 128-bit field from default aligned struct in global memory" { + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + try expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0); + try expect(12 == default_aligned_global.badguy); +} + +test "struct field explicit alignment" { + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + const S = struct { + const Node = struct { + next: *Node, + massive_byte: u8 align(64), + }; + }; + + var node: S.Node = undefined; + node.massive_byte = 100; + try expect(node.massive_byte == 100); + comptime try expect(@TypeOf(&node.massive_byte) == *align(64) u8); + try expect(@ptrToInt(&node.massive_byte) % 64 == 0); +} + +test "align(@alignOf(T)) T does not force resolution of T" { + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + const S = struct { + const A = struct { + a: *align(@alignOf(A)) A, + }; + fn doTheTest() void { + suspend { + resume @frame(); + } + _ = bar(@Frame(doTheTest)); + } + fn bar(comptime T: type) *align(@alignOf(T)) T { + ok = true; + return undefined; + } + + var ok = false; + }; + _ = async S.doTheTest(); + try expect(S.ok); +} + +test "align(N) on functions" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + // function alignment is a compile error on wasm32/wasm64 + if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; + if (native_arch == .thumb) return error.SkipZigTest; + + try expect((@ptrToInt(&overaligned_fn) & (0x1000 - 1)) == 0); +} +fn overaligned_fn() align(0x1000) i32 { + return 42; +} diff --git a/test/behavior/align_stage1.zig b/test/behavior/align_stage1.zig deleted file mode 100644 index 71a8c87e82..0000000000 --- a/test/behavior/align_stage1.zig +++ /dev/null @@ -1,174 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const builtin = @import("builtin"); -const native_arch = builtin.target.cpu.arch; - -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; - - try testImplicitlyDecreaseFnAlign(alignedSmall, 1234); - try testImplicitlyDecreaseFnAlign(alignedBig, 5678); -} - -fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) !void { - try expect(ptr() == answer); -} - -fn alignedSmall() align(8) i32 { - return 1234; -} -fn alignedBig() align(16) i32 { - return 5678; -} - -test "@alignCast functions" { - // function alignment is a compile error on wasm32/wasm64 - if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; - if (native_arch == .thumb) return error.SkipZigTest; - - try expect(fnExpectsOnly1(simple4) == 0x19); -} -fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 { - return fnExpects4(@alignCast(4, ptr)); -} -fn fnExpects4(ptr: fn () align(4) i32) i32 { - return ptr(); -} -fn simple4() align(4) i32 { - return 0x19; -} - -test "generic function with align param" { - // function alignment is a compile error on wasm32/wasm64 - if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; - if (native_arch == .thumb) return error.SkipZigTest; - - try expect(whyWouldYouEverDoThis(1) == 0x1); - try expect(whyWouldYouEverDoThis(4) == 0x1); - try expect(whyWouldYouEverDoThis(8) == 0x1); -} - -fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { - _ = align_bytes; - return 0x1; -} - -test "runtime known array index has best alignment possible" { - // take full advantage of over-alignment - var array align(4) = [_]u8{ 1, 2, 3, 4 }; - try expect(@TypeOf(&array[0]) == *align(4) u8); - try expect(@TypeOf(&array[1]) == *u8); - try expect(@TypeOf(&array[2]) == *align(2) u8); - try expect(@TypeOf(&array[3]) == *u8); - - // because align is too small but we still figure out to use 2 - var bigger align(2) = [_]u64{ 1, 2, 3, 4 }; - try expect(@TypeOf(&bigger[0]) == *align(2) u64); - try expect(@TypeOf(&bigger[1]) == *align(2) u64); - try expect(@TypeOf(&bigger[2]) == *align(2) u64); - try expect(@TypeOf(&bigger[3]) == *align(2) u64); - - // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 - var smaller align(2) = [_]u32{ 1, 2, 3, 4 }; - var runtime_zero: usize = 0; - comptime try expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32); - comptime try expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32); - try testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32); - try testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32); - try testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32); - try testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32); - - // has to use ABI alignment because index known at runtime only - try testIndex2(array[runtime_zero..].ptr, 0, *u8); - try testIndex2(array[runtime_zero..].ptr, 1, *u8); - try testIndex2(array[runtime_zero..].ptr, 2, *u8); - try testIndex2(array[runtime_zero..].ptr, 3, *u8); -} -fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) !void { - comptime try expect(@TypeOf(&smaller[index]) == T); -} -fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) !void { - comptime try expect(@TypeOf(&ptr[index]) == T); -} - -test "alignment of function with c calling convention" { - var runtime_nothing = nothing; - const casted1 = @ptrCast(*const u8, runtime_nothing); - const casted2 = @ptrCast(fn () callconv(.C) void, casted1); - casted2(); -} - -fn nothing() callconv(.C) void {} - -const DefaultAligned = struct { - nevermind: u32, - badguy: i128, -}; - -test "read 128-bit field from default aligned struct in stack memory" { - var default_aligned = DefaultAligned{ - .nevermind = 1, - .badguy = 12, - }; - try expect((@ptrToInt(&default_aligned.badguy) % 16) == 0); - try expect(12 == default_aligned.badguy); -} - -var default_aligned_global = DefaultAligned{ - .nevermind = 1, - .badguy = 12, -}; - -test "read 128-bit field from default aligned struct in global memory" { - try expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0); - try expect(12 == default_aligned_global.badguy); -} - -test "struct field explicit alignment" { - const S = struct { - const Node = struct { - next: *Node, - massive_byte: u8 align(64), - }; - }; - - var node: S.Node = undefined; - node.massive_byte = 100; - try expect(node.massive_byte == 100); - comptime try expect(@TypeOf(&node.massive_byte) == *align(64) u8); - try expect(@ptrToInt(&node.massive_byte) % 64 == 0); -} - -test "align(@alignOf(T)) T does not force resolution of T" { - const S = struct { - const A = struct { - a: *align(@alignOf(A)) A, - }; - fn doTheTest() void { - suspend { - resume @frame(); - } - _ = bar(@Frame(doTheTest)); - } - fn bar(comptime T: type) *align(@alignOf(T)) T { - ok = true; - return undefined; - } - - var ok = false; - }; - _ = async S.doTheTest(); - try expect(S.ok); -} - -test "align(N) on functions" { - // function alignment is a compile error on wasm32/wasm64 - if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; - if (native_arch == .thumb) return error.SkipZigTest; - - try expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0); -} -fn overaligned_fn() align(0x1000) i32 { - return 42; -} diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 3a7d95457e..186418b69c 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -294,3 +294,402 @@ test "const ptr from var variable" { fn copy(src: *const u64, dst: *u64) void { dst.* = src.*; } + +test "call result of if else expression" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + try expect(mem.eql(u8, f2(true), "a")); + try expect(mem.eql(u8, f2(false), "b")); +} +fn f2(x: bool) []const u8 { + return (if (x) fA else fB)(); +} + +test "memcpy and memset intrinsics" { + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + try testMemcpyMemset(); + // TODO add comptime test coverage + //comptime try testMemcpyMemset(); +} + +fn testMemcpyMemset() !void { + var foo: [20]u8 = undefined; + var bar: [20]u8 = undefined; + + @memset(&foo, 'A', foo.len); + @memcpy(&bar, &foo, bar.len); + + try expect(bar[0] == 'A'); + try expect(bar[11] == 'A'); + try expect(bar[19] == 'A'); +} + +test "variable is allowed to be a pointer to an opaque type" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + + var x: i32 = 1234; + _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); +} +fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { + var a = ptr; + return a; +} + +test "take address of parameter" { + try testTakeAddressOfParameter(12.34); +} +fn testTakeAddressOfParameter(f: f32) !void { + const f_ptr = &f; + try expect(f_ptr.* == 12.34); +} + +test "pointer to void return type" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + + try testPointerToVoidReturnType(); +} +fn testPointerToVoidReturnType() anyerror!void { + const a = testPointerToVoidReturnType2(); + return a.*; +} +const test_pointer_to_void_return_type_x = void{}; +fn testPointerToVoidReturnType2() *const void { + return &test_pointer_to_void_return_type_x; +} + +test "array 2D const double ptr" { + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + const rect_2d_vertexes = [_][1]f32{ + [_]f32{1.0}, + [_]f32{2.0}, + }; + try testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]); +} + +fn testArray2DConstDoublePtr(ptr: *const f32) !void { + const ptr2 = @ptrCast([*]const f32, ptr); + try expect(ptr2[0] == 1.0); + try expect(ptr2[1] == 2.0); +} + +test "double implicit cast in same expression" { + var x = @as(i32, @as(u16, nine())); + try expect(x == 9); +} +fn nine() u8 { + return 9; +} + +test "struct inside function" { + try testStructInFn(); + comptime try testStructInFn(); +} + +fn testStructInFn() !void { + const BlockKind = u32; + + const Block = struct { + kind: BlockKind, + }; + + var block = Block{ .kind = 1234 }; + + block.kind += 1; + + try expect(block.kind == 1235); +} + +test "fn call returning scalar optional in equality expression" { + try expect(getNull() == null); +} + +fn getNull() ?*i32 { + return null; +} + +test "global variable assignment with optional unwrapping with var initialized to undefined" { + const S = struct { + var data: i32 = 1234; + fn foo() ?*i32 { + return &data; + } + }; + global_foo = S.foo() orelse { + @panic("bad"); + }; + try expect(global_foo.* == 1234); +} + +var global_foo: *i32 = undefined; + +test "peer result location with typed parent, runtime condition, comptime prongs" { + const S = struct { + fn doTheTest(arg: i32) i32 { + const st = Structy{ + .bleh = if (arg == 1) 1 else 1, + }; + + if (st.bleh == 1) + return 1234; + return 0; + } + + const Structy = struct { + bleh: i32, + }; + }; + try expect(S.doTheTest(0) == 1234); + try expect(S.doTheTest(1) == 1234); +} + +test "non-ambiguous reference of shadowed decls" { + try expect(ZA().B().Self != ZA().Self); +} + +fn ZA() type { + return struct { + b: B(), + + const Self = @This(); + + fn B() type { + return struct { + const Self = @This(); + }; + } + }; +} + +test "use of declaration with same name as primitive" { + const S = struct { + const @"u8" = u16; + const alias = @"u8"; + }; + const a: S.u8 = 300; + try expect(a == 300); + + const b: S.alias = 300; + try expect(b == 300); + + const @"u8" = u16; + const c: @"u8" = 300; + try expect(c == 300); +} + +test "constant equal function pointers" { + const alias = emptyFn; + try expect(comptime x: { + break :x emptyFn == alias; + }); +} + +fn emptyFn() void {} + +const addr1 = @ptrCast(*const u8, &emptyFn); +test "comptime cast fn to ptr" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + + const addr2 = @ptrCast(*const u8, &emptyFn); + comptime try expect(addr1 == addr2); +} + +test "equality compare fn ptrs" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + + var a = &emptyFn; + try expect(a == a); +} + +test "self reference through fn ptr field" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + + const S = struct { + const A = struct { + f: *const fn (A) u8, + }; + + fn foo(a: A) u8 { + _ = a; + return 12; + } + }; + var a: S.A = undefined; + a.f = S.foo; + try expect(a.f(a) == 12); +} + +test "global variable initialized to global variable array element" { + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + + try expect(global_ptr == &gdt[0]); +} +const GDTEntry = struct { + field: i32, +}; +var gdt = [_]GDTEntry{ + GDTEntry{ .field = 1 }, + GDTEntry{ .field = 2 }, +}; +var global_ptr = &gdt[0]; + +test "global constant is loaded with a runtime-known index" { + const S = struct { + fn doTheTest() !void { + var index: usize = 1; + const ptr = &pieces[index].field; + try expect(ptr.* == 2); + } + const Piece = struct { + field: i32, + }; + const pieces = [_]Piece{ Piece{ .field = 1 }, Piece{ .field = 2 }, Piece{ .field = 3 } }; + }; + try S.doTheTest(); +} + +test "multiline string literal is null terminated" { + const s1 = + \\one + \\two) + \\three + ; + const s2 = "one\ntwo)\nthree"; + try expect(std.cstr.cmp(s1, s2) == 0); +} + +test "string escapes" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try expectEqualStrings("\"", "\x22"); + try expectEqualStrings("\'", "\x27"); + try expectEqualStrings("\n", "\x0a"); + try expectEqualStrings("\r", "\x0d"); + try expectEqualStrings("\t", "\x09"); + try expectEqualStrings("\\", "\x5c"); + try expectEqualStrings("\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01"); +} + +test "explicit cast optional pointers" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const a: ?*i32 = undefined; + const b: ?*f32 = @ptrCast(?*f32, a); + _ = b; +} + +test "pointer comparison" { + const a = @as([]const u8, "a"); + const b = &a; + try expect(ptrEql(b, b)); +} +fn ptrEql(a: *const []const u8, b: *const []const u8) bool { + return a == b; +} + +test "string concatenation" { + const a = "OK" ++ " IT " ++ "WORKED"; + const b = "OK IT WORKED"; + + comptime try expect(@TypeOf(a) == *const [12:0]u8); + comptime try expect(@TypeOf(b) == *const [12:0]u8); + + const len = mem.len(b); + const len_with_null = len + 1; + { + var i: u32 = 0; + while (i < len_with_null) : (i += 1) { + try expect(a[i] == b[i]); + } + } + try expect(a[len] == 0); + try expect(b[len] == 0); +} + +test "thread local variable" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + threadlocal var t: i32 = 1234; + }; + S.t += 1; + try expect(S.t == 1235); +} + +test "result location is optional inside error union" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const x = maybe(true) catch unreachable; + try expect(x.? == 42); +} + +fn maybe(x: bool) anyerror!?u32 { + return switch (x) { + true => @as(u32, 42), + else => null, + }; +} + +test "pointer to thread local array" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const s = "Hello world"; + std.mem.copy(u8, buffer[0..], s); + try std.testing.expectEqualSlices(u8, buffer[0..], s); +} + +threadlocal var buffer: [11]u8 = undefined; + +test "auto created variables have correct alignment" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn foo(str: [*]const u8) u32 { + for (@ptrCast([*]align(1) const u32, str)[0..1]) |v| { + return v; + } + return 0; + } + }; + try expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a); + comptime try expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a); +} + +test "extern variable with non-pointer opaque type" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + @export(var_to_export, .{ .name = "opaque_extern_var" }); + try expect(@ptrCast(*align(1) u32, &opaque_extern_var).* == 42); +} +extern var opaque_extern_var: opaque {}; +var var_to_export: u32 = 42; + +test "lazy typeInfo value as generic parameter" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn foo(args: anytype) void { + _ = args; + } + }; + S.foo(@typeInfo(@TypeOf(.{}))); +} + +test "variable name containing underscores does not shadow int primitive" { + const _u0 = 0; + const i_8 = 0; + const u16_ = 0; + const i3_2 = 0; + const u6__4 = 0; + const i2_04_8 = 0; + + _ = _u0; + _ = i_8; + _ = u16_; + _ = i3_2; + _ = u6__4; + _ = i2_04_8; +} diff --git a/test/behavior/basic_llvm.zig b/test/behavior/basic_llvm.zig deleted file mode 100644 index 29cad01567..0000000000 --- a/test/behavior/basic_llvm.zig +++ /dev/null @@ -1,250 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const mem = std.mem; -const expect = std.testing.expect; -const expectEqualStrings = std.testing.expectEqualStrings; - -test "call result of if else expression" { - try expect(mem.eql(u8, f2(true), "a")); - try expect(mem.eql(u8, f2(false), "b")); -} -fn f2(x: bool) []const u8 { - return (if (x) fA else fB)(); -} -fn fA() []const u8 { - return "a"; -} -fn fB() []const u8 { - return "b"; -} - -test "memcpy and memset intrinsics" { - try testMemcpyMemset(); - // TODO add comptime test coverage - //comptime try testMemcpyMemset(); -} - -fn testMemcpyMemset() !void { - var foo: [20]u8 = undefined; - var bar: [20]u8 = undefined; - - @memset(&foo, 'A', foo.len); - @memcpy(&bar, &foo, bar.len); - - try expect(bar[0] == 'A'); - try expect(bar[11] == 'A'); - try expect(bar[19] == 'A'); -} - -const OpaqueA = opaque {}; -const OpaqueB = opaque {}; - -test "variable is allowed to be a pointer to an opaque type" { - var x: i32 = 1234; - _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); -} -fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { - var a = ptr; - return a; -} - -test "take address of parameter" { - try testTakeAddressOfParameter(12.34); -} -fn testTakeAddressOfParameter(f: f32) !void { - const f_ptr = &f; - try expect(f_ptr.* == 12.34); -} - -test "pointer to void return type" { - try testPointerToVoidReturnType(); -} -fn testPointerToVoidReturnType() anyerror!void { - const a = testPointerToVoidReturnType2(); - return a.*; -} -const test_pointer_to_void_return_type_x = void{}; -fn testPointerToVoidReturnType2() *const void { - return &test_pointer_to_void_return_type_x; -} - -test "array 2D const double ptr" { - const rect_2d_vertexes = [_][1]f32{ - [_]f32{1.0}, - [_]f32{2.0}, - }; - try testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]); -} - -fn testArray2DConstDoublePtr(ptr: *const f32) !void { - const ptr2 = @ptrCast([*]const f32, ptr); - try expect(ptr2[0] == 1.0); - try expect(ptr2[1] == 2.0); -} - -test "double implicit cast in same expression" { - var x = @as(i32, @as(u16, nine())); - try expect(x == 9); -} -fn nine() u8 { - return 9; -} - -test "struct inside function" { - try testStructInFn(); - comptime try testStructInFn(); -} - -fn testStructInFn() !void { - const BlockKind = u32; - - const Block = struct { - kind: BlockKind, - }; - - var block = Block{ .kind = 1234 }; - - block.kind += 1; - - try expect(block.kind == 1235); -} - -test "fn call returning scalar optional in equality expression" { - try expect(getNull() == null); -} - -fn getNull() ?*i32 { - return null; -} - -var global_foo: *i32 = undefined; - -test "global variable assignment with optional unwrapping with var initialized to undefined" { - const S = struct { - var data: i32 = 1234; - fn foo() ?*i32 { - return &data; - } - }; - global_foo = S.foo() orelse { - @panic("bad"); - }; - try expect(global_foo.* == 1234); -} - -test "peer result location with typed parent, runtime condition, comptime prongs" { - const S = struct { - fn doTheTest(arg: i32) i32 { - const st = Structy{ - .bleh = if (arg == 1) 1 else 1, - }; - - if (st.bleh == 1) - return 1234; - return 0; - } - - const Structy = struct { - bleh: i32, - }; - }; - try expect(S.doTheTest(0) == 1234); - try expect(S.doTheTest(1) == 1234); -} - -fn ZA() type { - return struct { - b: B(), - - const Self = @This(); - - fn B() type { - return struct { - const Self = @This(); - }; - } - }; -} -test "non-ambiguous reference of shadowed decls" { - try expect(ZA().B().Self != ZA().Self); -} - -test "use of declaration with same name as primitive" { - const S = struct { - const @"u8" = u16; - const alias = @"u8"; - }; - const a: S.u8 = 300; - try expect(a == 300); - - const b: S.alias = 300; - try expect(b == 300); - - const @"u8" = u16; - const c: @"u8" = 300; - try expect(c == 300); -} - -fn emptyFn() void {} - -test "constant equal function pointers" { - const alias = emptyFn; - try expect(comptime x: { - break :x emptyFn == alias; - }); -} - -test "multiline string literal is null terminated" { - const s1 = - \\one - \\two) - \\three - ; - const s2 = "one\ntwo)\nthree"; - try expect(std.cstr.cmp(s1, s2) == 0); -} - -test "self reference through fn ptr field" { - if (builtin.zig_backend == .stage1) return error.SkipZigTest; - - const S = struct { - const A = struct { - f: *const fn (A) u8, - }; - - fn foo(a: A) u8 { - _ = a; - return 12; - } - }; - var a: S.A = undefined; - a.f = S.foo; - try expect(a.f(a) == 12); -} - -test "global variable initialized to global variable array element" { - try expect(global_ptr == &gdt[0]); -} -const GDTEntry = struct { - field: i32, -}; -var gdt = [_]GDTEntry{ - GDTEntry{ .field = 1 }, - GDTEntry{ .field = 2 }, -}; -var global_ptr = &gdt[0]; - -test "global constant is loaded with a runtime-known index" { - const S = struct { - fn doTheTest() !void { - var index: usize = 1; - const ptr = &pieces[index].field; - try expect(ptr.* == 2); - } - const Piece = struct { - field: i32, - }; - const pieces = [_]Piece{ Piece{ .field = 1 }, Piece{ .field = 2 }, Piece{ .field = 3 } }; - }; - try S.doTheTest(); -} diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig index c4827e1795..a4a555057e 100644 --- a/test/behavior/bitcast.zig +++ b/test/behavior/bitcast.zig @@ -70,3 +70,166 @@ test "bitcast generates a temporary value" { const x = @bitCast(u16, @bitCast([2]u8, y)); try expect(y == x); } + +test "@bitCast packed structs at runtime and comptime" { + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + const Full = packed struct { + number: u16, + }; + const Divided = packed struct { + half1: u8, + quarter3: u4, + quarter4: u4, + }; + const S = struct { + fn doTheTest() !void { + var full = Full{ .number = 0x1234 }; + var two_halves = @bitCast(Divided, full); + switch (native_endian) { + .Big => { + try expect(two_halves.half1 == 0x12); + try expect(two_halves.quarter3 == 0x3); + try expect(two_halves.quarter4 == 0x4); + }, + .Little => { + try expect(two_halves.half1 == 0x34); + try expect(two_halves.quarter3 == 0x2); + try expect(two_halves.quarter4 == 0x1); + }, + } + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "@bitCast extern structs at runtime and comptime" { + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + const Full = extern struct { + number: u16, + }; + const TwoHalves = extern struct { + half1: u8, + half2: u8, + }; + const S = struct { + fn doTheTest() !void { + var full = Full{ .number = 0x1234 }; + var two_halves = @bitCast(TwoHalves, full); + switch (native_endian) { + .Big => { + try expect(two_halves.half1 == 0x12); + try expect(two_halves.half2 == 0x34); + }, + .Little => { + try expect(two_halves.half1 == 0x34); + try expect(two_halves.half2 == 0x12); + }, + } + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "bitcast packed struct to integer and back" { + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + const LevelUpMove = packed struct { + move_id: u9, + level: u7, + }; + const S = struct { + fn doTheTest() !void { + var move = LevelUpMove{ .move_id = 1, .level = 2 }; + var v = @bitCast(u16, move); + var back_to_a_move = @bitCast(LevelUpMove, v); + try expect(back_to_a_move.move_id == 1); + try expect(back_to_a_move.level == 2); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "implicit cast to error union by returning" { + const S = struct { + fn entry() !void { + try expect((func(-1) catch unreachable) == maxInt(u64)); + } + pub fn func(sz: i64) anyerror!u64 { + return @bitCast(u64, sz); + } + }; + try S.entry(); + comptime try S.entry(); +} + +test "bitcast packed struct literal to byte" { + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + const Foo = packed struct { + value: u8, + }; + const casted = @bitCast(u8, Foo{ .value = 0xF }); + try expect(casted == 0xf); +} + +test "comptime bitcast used in expression has the correct type" { + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + const Foo = packed struct { + value: u8, + }; + try expect(@bitCast(u8, Foo{ .value = 0xF }) == 0xf); +} + +test "bitcast passed as tuple element" { + if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + const S = struct { + fn foo(args: anytype) !void { + comptime try expect(@TypeOf(args[0]) == f32); + try expect(args[0] == 12.34); + } + }; + try S.foo(.{@bitCast(f32, @as(u32, 0x414570A4))}); +} + +test "triple level result location with bitcast sandwich passed as tuple element" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + + const S = struct { + fn foo(args: anytype) !void { + comptime try expect(@TypeOf(args[0]) == f64); + try expect(args[0] > 12.33 and args[0] < 12.35); + } + }; + try S.foo(.{@as(f64, @bitCast(f32, @as(u32, 0x414570A4)))}); +} diff --git a/test/behavior/bitcast_stage1.zig b/test/behavior/bitcast_stage1.zig deleted file mode 100644 index c491571e9c..0000000000 --- a/test/behavior/bitcast_stage1.zig +++ /dev/null @@ -1,131 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const expect = std.testing.expect; -const expectEqual = std.testing.expectEqual; -const maxInt = std.math.maxInt; -const native_endian = builtin.target.cpu.arch.endian(); - -test "@bitCast packed structs at runtime and comptime" { - const Full = packed struct { - number: u16, - }; - const Divided = packed struct { - half1: u8, - quarter3: u4, - quarter4: u4, - }; - const S = struct { - fn doTheTest() !void { - var full = Full{ .number = 0x1234 }; - var two_halves = @bitCast(Divided, full); - switch (native_endian) { - .Big => { - try expect(two_halves.half1 == 0x12); - try expect(two_halves.quarter3 == 0x3); - try expect(two_halves.quarter4 == 0x4); - }, - .Little => { - try expect(two_halves.half1 == 0x34); - try expect(two_halves.quarter3 == 0x2); - try expect(two_halves.quarter4 == 0x1); - }, - } - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "@bitCast extern structs at runtime and comptime" { - const Full = extern struct { - number: u16, - }; - const TwoHalves = extern struct { - half1: u8, - half2: u8, - }; - const S = struct { - fn doTheTest() !void { - var full = Full{ .number = 0x1234 }; - var two_halves = @bitCast(TwoHalves, full); - switch (native_endian) { - .Big => { - try expect(two_halves.half1 == 0x12); - try expect(two_halves.half2 == 0x34); - }, - .Little => { - try expect(two_halves.half1 == 0x34); - try expect(two_halves.half2 == 0x12); - }, - } - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "bitcast packed struct to integer and back" { - const LevelUpMove = packed struct { - move_id: u9, - level: u7, - }; - const S = struct { - fn doTheTest() !void { - var move = LevelUpMove{ .move_id = 1, .level = 2 }; - var v = @bitCast(u16, move); - var back_to_a_move = @bitCast(LevelUpMove, v); - try expect(back_to_a_move.move_id == 1); - try expect(back_to_a_move.level == 2); - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "implicit cast to error union by returning" { - const S = struct { - fn entry() !void { - try expect((func(-1) catch unreachable) == maxInt(u64)); - } - pub fn func(sz: i64) anyerror!u64 { - return @bitCast(u64, sz); - } - }; - try S.entry(); - comptime try S.entry(); -} - -test "bitcast packed struct literal to byte" { - const Foo = packed struct { - value: u8, - }; - const casted = @bitCast(u8, Foo{ .value = 0xF }); - try expect(casted == 0xf); -} - -test "comptime bitcast used in expression has the correct type" { - const Foo = packed struct { - value: u8, - }; - try expect(@bitCast(u8, Foo{ .value = 0xF }) == 0xf); -} - -test "bitcast passed as tuple element" { - const S = struct { - fn foo(args: anytype) !void { - comptime try expect(@TypeOf(args[0]) == f32); - try expect(args[0] == 12.34); - } - }; - try S.foo(.{@bitCast(f32, @as(u32, 0x414570A4))}); -} - -test "triple level result location with bitcast sandwich passed as tuple element" { - const S = struct { - fn foo(args: anytype) !void { - comptime try expect(@TypeOf(args[0]) == f64); - try expect(args[0] > 12.33 and args[0] < 12.35); - } - }; - try S.foo(.{@as(f64, @bitCast(f32, @as(u32, 0x414570A4)))}); -} diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 54b7df4fc3..42602366d5 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -336,3 +336,474 @@ test "expected [*c]const u8, found [*:0]const u8" { var c: [*:0]const u8 = b; try expect(std.mem.eql(u8, c[0..5], "hello")); } + +test "explicit cast from integer to error type" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try testCastIntToErr(error.ItBroke); + comptime try testCastIntToErr(error.ItBroke); +} +fn testCastIntToErr(err: anyerror) !void { + const x = @errorToInt(err); + const y = @intToError(x); + try expect(error.ItBroke == y); +} + +test "peer resolve array and const slice" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try testPeerResolveArrayConstSlice(true); + comptime try testPeerResolveArrayConstSlice(true); +} +fn testPeerResolveArrayConstSlice(b: bool) !void { + const value1 = if (b) "aoeu" else @as([]const u8, "zz"); + const value2 = if (b) @as([]const u8, "zz") else "aoeu"; + try expect(mem.eql(u8, value1, "aoeu")); + try expect(mem.eql(u8, value2, "zz")); +} + +test "implicitly cast from T to anyerror!?T" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try castToOptionalTypeError(1); + comptime try castToOptionalTypeError(1); +} + +const A = struct { + a: i32, +}; +fn castToOptionalTypeError(z: i32) !void { + const x = @as(i32, 1); + const y: anyerror!?i32 = x; + try expect((try y).? == 1); + + const f = z; + const g: anyerror!?i32 = f; + _ = g catch {}; + + const a = A{ .a = z }; + const b: anyerror!?A = a; + try expect((b catch unreachable).?.a == 1); +} + +test "implicitly cast from [0]T to anyerror![]T" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + try testCastZeroArrayToErrSliceMut(); + comptime try testCastZeroArrayToErrSliceMut(); +} + +fn testCastZeroArrayToErrSliceMut() !void { + try expect((gimmeErrOrSlice() catch unreachable).len == 0); +} + +fn gimmeErrOrSlice() anyerror![]u8 { + return &[_]u8{}; +} + +test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() anyerror!void { + { + var data = "hi".*; + const slice = data[0..]; + try expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + try expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + } + { + var data: [2]u8 = "hi".*; + const slice = data[0..]; + try expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + try expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + } + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} +fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { + if (a) { + return &[_]u8{}; + } + + return slice[0..1]; +} + +test "implicit cast from *const [N]T to []const T" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try testCastConstArrayRefToConstSlice(); + comptime try testCastConstArrayRefToConstSlice(); +} + +fn testCastConstArrayRefToConstSlice() !void { + { + const blah = "aoeu".*; + const const_array_ref = &blah; + try expect(@TypeOf(const_array_ref) == *const [4:0]u8); + const slice: []const u8 = const_array_ref; + try expect(mem.eql(u8, slice, "aoeu")); + } + { + const blah: [4]u8 = "aoeu".*; + const const_array_ref = &blah; + try expect(@TypeOf(const_array_ref) == *const [4]u8); + const slice: []const u8 = const_array_ref; + try expect(mem.eql(u8, slice, "aoeu")); + } +} + +test "peer type resolution: error and [N]T" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); + comptime try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); + try expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); + comptime try expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); +} + +fn testPeerErrorAndArray(x: u8) anyerror![]const u8 { + return switch (x) { + 0x00 => "OK", + else => error.BadValue, + }; +} +fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { + return switch (x) { + 0x00 => "OK", + 0x01 => "OKK", + else => error.BadValue, + }; +} + +test "single-item pointer of array to slice to unknown length pointer" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try testCastPtrOfArrayToSliceAndPtr(); + comptime try testCastPtrOfArrayToSliceAndPtr(); +} + +fn testCastPtrOfArrayToSliceAndPtr() !void { + { + var array = "aoeu".*; + const x: [*]u8 = &array; + x[0] += 1; + try expect(mem.eql(u8, array[0..], "boeu")); + const y: []u8 = &array; + y[0] += 1; + try expect(mem.eql(u8, array[0..], "coeu")); + } + { + var array: [4]u8 = "aoeu".*; + const x: [*]u8 = &array; + x[0] += 1; + try expect(mem.eql(u8, array[0..], "boeu")); + const y: []u8 = &array; + y[0] += 1; + try expect(mem.eql(u8, array[0..], "coeu")); + } +} + +test "cast *[1][*]const u8 to [*]const ?[*]const u8" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const window_name = [1][*]const u8{"window name"}; + const x: [*]const ?[*]const u8 = &window_name; + try expect(mem.eql(u8, std.mem.sliceTo(@ptrCast([*:0]const u8, x[0].?), 0), "window name")); +} + +test "vector casts" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + // Upcast (implicit, equivalent to @intCast) + var up0: @Vector(2, u8) = [_]u8{ 0x55, 0xaa }; + var up1 = @as(@Vector(2, u16), up0); + var up2 = @as(@Vector(2, u32), up0); + var up3 = @as(@Vector(2, u64), up0); + // Downcast (safety-checked) + var down0 = up3; + var down1 = @intCast(@Vector(2, u32), down0); + var down2 = @intCast(@Vector(2, u16), down0); + var down3 = @intCast(@Vector(2, u8), down0); + + try expect(mem.eql(u16, &@as([2]u16, up1), &[2]u16{ 0x55, 0xaa })); + try expect(mem.eql(u32, &@as([2]u32, up2), &[2]u32{ 0x55, 0xaa })); + try expect(mem.eql(u64, &@as([2]u64, up3), &[2]u64{ 0x55, 0xaa })); + + try expect(mem.eql(u32, &@as([2]u32, down1), &[2]u32{ 0x55, 0xaa })); + try expect(mem.eql(u16, &@as([2]u16, down2), &[2]u16{ 0x55, 0xaa })); + try expect(mem.eql(u8, &@as([2]u8, down3), &[2]u8{ 0x55, 0xaa })); + } + + fn doTheTestFloat() !void { + var vec = @splat(2, @as(f32, 1234.0)); + var wider: @Vector(2, f64) = vec; + try expect(wider[0] == 1234.0); + try expect(wider[1] == 1234.0); + } + }; + + try S.doTheTest(); + comptime try S.doTheTest(); + try S.doTheTestFloat(); + comptime try S.doTheTestFloat(); +} + +test "@floatCast cast down" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + { + var double: f64 = 0.001534; + var single = @floatCast(f32, double); + try expect(single == 0.001534); + } + { + const double: f64 = 0.001534; + const single = @floatCast(f32, double); + try expect(single == 0.001534); + } +} + +test "peer type resolution: unreachable, error set, unreachable" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const Error = error{ + FileDescriptorAlreadyPresentInSet, + OperationCausesCircularLoop, + FileDescriptorNotRegistered, + SystemResources, + UserResourceLimitReached, + FileDescriptorIncompatibleWithEpoll, + Unexpected, + }; + var err = Error.SystemResources; + const transformed_err = switch (err) { + error.FileDescriptorAlreadyPresentInSet => unreachable, + error.OperationCausesCircularLoop => unreachable, + error.FileDescriptorNotRegistered => unreachable, + error.SystemResources => error.SystemResources, + error.UserResourceLimitReached => error.UserResourceLimitReached, + error.FileDescriptorIncompatibleWithEpoll => unreachable, + error.Unexpected => unreachable, + }; + try expect(transformed_err == error.SystemResources); +} + +test "peer cast *[0]T to E![]const T" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + var buffer: [5]u8 = "abcde".*; + var buf: anyerror![]const u8 = buffer[0..]; + var b = false; + var y = if (b) &[0]u8{} else buf; + try expect(mem.eql(u8, "abcde", y catch unreachable)); +} + +test "peer cast *[0]T to []const T" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + var buffer: [5]u8 = "abcde".*; + var buf: []const u8 = buffer[0..]; + var b = false; + var y = if (b) &[0]u8{} else buf; + try expect(mem.eql(u8, "abcde", y)); +} + +test "peer resolution of string literals" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + const E = enum { a, b, c, d }; + + fn doTheTest(e: E) !void { + const cmd = switch (e) { + .a => "one", + .b => "two", + .c => "three", + .d => "four", + }; + try expect(mem.eql(u8, cmd, "two")); + } + }; + try S.doTheTest(.b); + comptime try S.doTheTest(.b); +} + +test "type coercion related to sentinel-termination" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + // [:x]T to []T + { + var array = [4:0]i32{ 1, 2, 3, 4 }; + var slice: [:0]i32 = &array; + var dest: []i32 = slice; + try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); + } + + // [*:x]T to [*]T + { + var array = [4:99]i32{ 1, 2, 3, 4 }; + var dest: [*]i32 = &array; + try expect(dest[0] == 1); + try expect(dest[1] == 2); + try expect(dest[2] == 3); + try expect(dest[3] == 4); + try expect(dest[4] == 99); + } + + // [N:x]T to [N]T + { + var array = [4:0]i32{ 1, 2, 3, 4 }; + var dest: [4]i32 = array; + try expect(mem.eql(i32, &dest, &[_]i32{ 1, 2, 3, 4 })); + } + + // *[N:x]T to *[N]T + { + var array = [4:0]i32{ 1, 2, 3, 4 }; + var dest: *[4]i32 = &array; + try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); + } + + // [:x]T to [*:x]T + { + var array = [4:0]i32{ 1, 2, 3, 4 }; + var slice: [:0]i32 = &array; + var dest: [*:0]i32 = slice; + try expect(dest[0] == 1); + try expect(dest[1] == 2); + try expect(dest[2] == 3); + try expect(dest[3] == 4); + try expect(dest[4] == 0); + } + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "peer type resolution implicit cast to return type" { + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + for ("hello") |c| _ = f(c); + } + fn f(c: u8) []const u8 { + return switch (c) { + 'h', 'e' => &[_]u8{c}, // should cast to slice + 'l', ' ' => &[_]u8{ c, '.' }, // should cast to slice + else => ([_]u8{c})[0..], // is a slice + }; + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "peer type resolution implicit cast to variable type" { + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + var x: []const u8 = undefined; + for ("hello") |c| x = switch (c) { + 'h', 'e' => &[_]u8{c}, // should cast to slice + 'l', ' ' => &[_]u8{ c, '.' }, // should cast to slice + else => ([_]u8{c})[0..], // is a slice + }; + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "variable initialization uses result locations properly with regards to the type" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + var b = true; + const x: i32 = if (b) 1 else 2; + try expect(x == 1); +} + +test "cast between C pointer with different but compatible types" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn foo(arg: [*]c_ushort) u16 { + return arg[0]; + } + fn doTheTest() !void { + var x = [_]u16{ 4, 2, 1, 3 }; + try expect(foo(@ptrCast([*]u16, &x)) == 4); + } + }; + try S.doTheTest(); +} + +test "peer type resolve string lit with sentinel-terminated mutable slice" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + var array: [4:0]u8 = undefined; + array[4] = 0; // TODO remove this when #4372 is solved + var slice: [:0]u8 = array[0..4 :0]; + comptime try expect(@TypeOf(slice, "hi") == [:0]const u8); + comptime try expect(@TypeOf("hi", slice) == [:0]const u8); +} + +test "peer type resolve array pointers, one of them const" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + var array1: [4]u8 = undefined; + const array2: [5]u8 = undefined; + comptime try expect(@TypeOf(&array1, &array2) == []const u8); + comptime try expect(@TypeOf(&array2, &array1) == []const u8); +} + +test "peer type resolve array pointer and unknown pointer" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const const_array: [4]u8 = undefined; + var array: [4]u8 = undefined; + var const_ptr: [*]const u8 = undefined; + var ptr: [*]u8 = undefined; + + comptime try expect(@TypeOf(&array, ptr) == [*]u8); + comptime try expect(@TypeOf(ptr, &array) == [*]u8); + + comptime try expect(@TypeOf(&const_array, ptr) == [*]const u8); + comptime try expect(@TypeOf(ptr, &const_array) == [*]const u8); + + comptime try expect(@TypeOf(&array, const_ptr) == [*]const u8); + comptime try expect(@TypeOf(const_ptr, &array) == [*]const u8); + + comptime try expect(@TypeOf(&const_array, const_ptr) == [*]const u8); + comptime try expect(@TypeOf(const_ptr, &const_array) == [*]const u8); +} + +test "comptime float casts" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const a = @intToFloat(comptime_float, 1); + try expect(a == 1); + try expect(@TypeOf(a) == comptime_float); + const b = @floatToInt(comptime_int, 2); + try expect(b == 2); + try expect(@TypeOf(b) == comptime_int); + + try expectFloatToInt(comptime_int, 1234, i16, 1234); + try expectFloatToInt(comptime_float, 12.3, comptime_int, 12); +} diff --git a/test/behavior/cast_stage1.zig b/test/behavior/cast_stage1.zig deleted file mode 100644 index ff4c657ed7..0000000000 --- a/test/behavior/cast_stage1.zig +++ /dev/null @@ -1,426 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const mem = std.mem; -const maxInt = std.math.maxInt; -const Vector = std.meta.Vector; -const native_endian = @import("builtin").target.cpu.arch.endian(); - -test "explicit cast from integer to error type" { - try testCastIntToErr(error.ItBroke); - comptime try testCastIntToErr(error.ItBroke); -} -fn testCastIntToErr(err: anyerror) !void { - const x = @errorToInt(err); - const y = @intToError(x); - try expect(error.ItBroke == y); -} - -test "peer resolve array and const slice" { - try testPeerResolveArrayConstSlice(true); - comptime try testPeerResolveArrayConstSlice(true); -} -fn testPeerResolveArrayConstSlice(b: bool) !void { - const value1 = if (b) "aoeu" else @as([]const u8, "zz"); - const value2 = if (b) @as([]const u8, "zz") else "aoeu"; - try expect(mem.eql(u8, value1, "aoeu")); - try expect(mem.eql(u8, value2, "zz")); -} - -test "implicitly cast from T to anyerror!?T" { - try castToOptionalTypeError(1); - comptime try castToOptionalTypeError(1); -} - -const A = struct { - a: i32, -}; -fn castToOptionalTypeError(z: i32) !void { - const x = @as(i32, 1); - const y: anyerror!?i32 = x; - try expect((try y).? == 1); - - const f = z; - const g: anyerror!?i32 = f; - _ = g catch {}; - - const a = A{ .a = z }; - const b: anyerror!?A = a; - try expect((b catch unreachable).?.a == 1); -} - -test "implicitly cast from [0]T to anyerror![]T" { - try testCastZeroArrayToErrSliceMut(); - comptime try testCastZeroArrayToErrSliceMut(); -} - -fn testCastZeroArrayToErrSliceMut() !void { - try expect((gimmeErrOrSlice() catch unreachable).len == 0); -} - -fn gimmeErrOrSlice() anyerror![]u8 { - return &[_]u8{}; -} - -test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { - const S = struct { - fn doTheTest() anyerror!void { - { - var data = "hi".*; - const slice = data[0..]; - try expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - try expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); - } - { - var data: [2]u8 = "hi".*; - const slice = data[0..]; - try expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - try expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); - } - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} -fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { - if (a) { - return &[_]u8{}; - } - - return slice[0..1]; -} - -test "implicit cast from *const [N]T to []const T" { - try testCastConstArrayRefToConstSlice(); - comptime try testCastConstArrayRefToConstSlice(); -} - -fn testCastConstArrayRefToConstSlice() !void { - { - const blah = "aoeu".*; - const const_array_ref = &blah; - try expect(@TypeOf(const_array_ref) == *const [4:0]u8); - const slice: []const u8 = const_array_ref; - try expect(mem.eql(u8, slice, "aoeu")); - } - { - const blah: [4]u8 = "aoeu".*; - const const_array_ref = &blah; - try expect(@TypeOf(const_array_ref) == *const [4]u8); - const slice: []const u8 = const_array_ref; - try expect(mem.eql(u8, slice, "aoeu")); - } -} - -test "peer type resolution: error and [N]T" { - try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); - comptime try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); - try expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); - comptime try expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); -} - -fn testPeerErrorAndArray(x: u8) anyerror![]const u8 { - return switch (x) { - 0x00 => "OK", - else => error.BadValue, - }; -} -fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { - return switch (x) { - 0x00 => "OK", - 0x01 => "OKK", - else => error.BadValue, - }; -} - -test "single-item pointer of array to slice to unknown length pointer" { - try testCastPtrOfArrayToSliceAndPtr(); - comptime try testCastPtrOfArrayToSliceAndPtr(); -} - -fn testCastPtrOfArrayToSliceAndPtr() !void { - { - var array = "aoeu".*; - const x: [*]u8 = &array; - x[0] += 1; - try expect(mem.eql(u8, array[0..], "boeu")); - const y: []u8 = &array; - y[0] += 1; - try expect(mem.eql(u8, array[0..], "coeu")); - } - { - var array: [4]u8 = "aoeu".*; - const x: [*]u8 = &array; - x[0] += 1; - try expect(mem.eql(u8, array[0..], "boeu")); - const y: []u8 = &array; - y[0] += 1; - try expect(mem.eql(u8, array[0..], "coeu")); - } -} - -test "cast *[1][*]const u8 to [*]const ?[*]const u8" { - const window_name = [1][*]const u8{"window name"}; - const x: [*]const ?[*]const u8 = &window_name; - try expect(mem.eql(u8, std.mem.sliceTo(@ptrCast([*:0]const u8, x[0].?), 0), "window name")); -} - -test "vector casts" { - const S = struct { - fn doTheTest() !void { - // Upcast (implicit, equivalent to @intCast) - var up0: Vector(2, u8) = [_]u8{ 0x55, 0xaa }; - var up1 = @as(Vector(2, u16), up0); - var up2 = @as(Vector(2, u32), up0); - var up3 = @as(Vector(2, u64), up0); - // Downcast (safety-checked) - var down0 = up3; - var down1 = @intCast(Vector(2, u32), down0); - var down2 = @intCast(Vector(2, u16), down0); - var down3 = @intCast(Vector(2, u8), down0); - - try expect(mem.eql(u16, &@as([2]u16, up1), &[2]u16{ 0x55, 0xaa })); - try expect(mem.eql(u32, &@as([2]u32, up2), &[2]u32{ 0x55, 0xaa })); - try expect(mem.eql(u64, &@as([2]u64, up3), &[2]u64{ 0x55, 0xaa })); - - try expect(mem.eql(u32, &@as([2]u32, down1), &[2]u32{ 0x55, 0xaa })); - try expect(mem.eql(u16, &@as([2]u16, down2), &[2]u16{ 0x55, 0xaa })); - try expect(mem.eql(u8, &@as([2]u8, down3), &[2]u8{ 0x55, 0xaa })); - } - - fn doTheTestFloat() !void { - var vec = @splat(2, @as(f32, 1234.0)); - var wider: Vector(2, f64) = vec; - try expect(wider[0] == 1234.0); - try expect(wider[1] == 1234.0); - } - }; - - try S.doTheTest(); - comptime try S.doTheTest(); - try S.doTheTestFloat(); - comptime try S.doTheTestFloat(); -} - -test "@floatCast cast down" { - { - var double: f64 = 0.001534; - var single = @floatCast(f32, double); - try expect(single == 0.001534); - } - { - const double: f64 = 0.001534; - const single = @floatCast(f32, double); - try expect(single == 0.001534); - } -} - -test "peer type resolution: unreachable, error set, unreachable" { - const Error = error{ - FileDescriptorAlreadyPresentInSet, - OperationCausesCircularLoop, - FileDescriptorNotRegistered, - SystemResources, - UserResourceLimitReached, - FileDescriptorIncompatibleWithEpoll, - Unexpected, - }; - var err = Error.SystemResources; - const transformed_err = switch (err) { - error.FileDescriptorAlreadyPresentInSet => unreachable, - error.OperationCausesCircularLoop => unreachable, - error.FileDescriptorNotRegistered => unreachable, - error.SystemResources => error.SystemResources, - error.UserResourceLimitReached => error.UserResourceLimitReached, - error.FileDescriptorIncompatibleWithEpoll => unreachable, - error.Unexpected => unreachable, - }; - try expect(transformed_err == error.SystemResources); -} - -test "peer cast *[0]T to E![]const T" { - var buffer: [5]u8 = "abcde".*; - var buf: anyerror![]const u8 = buffer[0..]; - var b = false; - var y = if (b) &[0]u8{} else buf; - try expect(mem.eql(u8, "abcde", y catch unreachable)); -} - -test "peer cast *[0]T to []const T" { - var buffer: [5]u8 = "abcde".*; - var buf: []const u8 = buffer[0..]; - var b = false; - var y = if (b) &[0]u8{} else buf; - try expect(mem.eql(u8, "abcde", y)); -} - -test "peer resolution of string literals" { - const S = struct { - const E = enum { a, b, c, d }; - - fn doTheTest(e: E) !void { - const cmd = switch (e) { - .a => "one", - .b => "two", - .c => "three", - .d => "four", - }; - try expect(mem.eql(u8, cmd, "two")); - } - }; - try S.doTheTest(.b); - comptime try S.doTheTest(.b); -} - -test "type coercion related to sentinel-termination" { - const S = struct { - fn doTheTest() !void { - // [:x]T to []T - { - var array = [4:0]i32{ 1, 2, 3, 4 }; - var slice: [:0]i32 = &array; - var dest: []i32 = slice; - try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); - } - - // [*:x]T to [*]T - { - var array = [4:99]i32{ 1, 2, 3, 4 }; - var dest: [*]i32 = &array; - try expect(dest[0] == 1); - try expect(dest[1] == 2); - try expect(dest[2] == 3); - try expect(dest[3] == 4); - try expect(dest[4] == 99); - } - - // [N:x]T to [N]T - { - var array = [4:0]i32{ 1, 2, 3, 4 }; - var dest: [4]i32 = array; - try expect(mem.eql(i32, &dest, &[_]i32{ 1, 2, 3, 4 })); - } - - // *[N:x]T to *[N]T - { - var array = [4:0]i32{ 1, 2, 3, 4 }; - var dest: *[4]i32 = &array; - try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); - } - - // [:x]T to [*:x]T - { - var array = [4:0]i32{ 1, 2, 3, 4 }; - var slice: [:0]i32 = &array; - var dest: [*:0]i32 = slice; - try expect(dest[0] == 1); - try expect(dest[1] == 2); - try expect(dest[2] == 3); - try expect(dest[3] == 4); - try expect(dest[4] == 0); - } - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "peer type resolution implicit cast to return type" { - const S = struct { - fn doTheTest() !void { - for ("hello") |c| _ = f(c); - } - fn f(c: u8) []const u8 { - return switch (c) { - 'h', 'e' => &[_]u8{c}, // should cast to slice - 'l', ' ' => &[_]u8{ c, '.' }, // should cast to slice - else => ([_]u8{c})[0..], // is a slice - }; - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "peer type resolution implicit cast to variable type" { - const S = struct { - fn doTheTest() !void { - var x: []const u8 = undefined; - for ("hello") |c| x = switch (c) { - 'h', 'e' => &[_]u8{c}, // should cast to slice - 'l', ' ' => &[_]u8{ c, '.' }, // should cast to slice - else => ([_]u8{c})[0..], // is a slice - }; - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "variable initialization uses result locations properly with regards to the type" { - var b = true; - const x: i32 = if (b) 1 else 2; - try expect(x == 1); -} - -test "cast between C pointer with different but compatible types" { - const S = struct { - fn foo(arg: [*]c_ushort) u16 { - return arg[0]; - } - fn doTheTest() !void { - var x = [_]u16{ 4, 2, 1, 3 }; - try expect(foo(@ptrCast([*]u16, &x)) == 4); - } - }; - try S.doTheTest(); -} - -test "peer type resolve string lit with sentinel-terminated mutable slice" { - var array: [4:0]u8 = undefined; - array[4] = 0; // TODO remove this when #4372 is solved - var slice: [:0]u8 = array[0..4 :0]; - comptime try expect(@TypeOf(slice, "hi") == [:0]const u8); - comptime try expect(@TypeOf("hi", slice) == [:0]const u8); -} - -test "peer type resolve array pointers, one of them const" { - var array1: [4]u8 = undefined; - const array2: [5]u8 = undefined; - comptime try expect(@TypeOf(&array1, &array2) == []const u8); - comptime try expect(@TypeOf(&array2, &array1) == []const u8); -} - -test "peer type resolve array pointer and unknown pointer" { - const const_array: [4]u8 = undefined; - var array: [4]u8 = undefined; - var const_ptr: [*]const u8 = undefined; - var ptr: [*]u8 = undefined; - - comptime try expect(@TypeOf(&array, ptr) == [*]u8); - comptime try expect(@TypeOf(ptr, &array) == [*]u8); - - comptime try expect(@TypeOf(&const_array, ptr) == [*]const u8); - comptime try expect(@TypeOf(ptr, &const_array) == [*]const u8); - - comptime try expect(@TypeOf(&array, const_ptr) == [*]const u8); - comptime try expect(@TypeOf(const_ptr, &array) == [*]const u8); - - comptime try expect(@TypeOf(&const_array, const_ptr) == [*]const u8); - comptime try expect(@TypeOf(const_ptr, &const_array) == [*]const u8); -} - -test "comptime float casts" { - const a = @intToFloat(comptime_float, 1); - try expect(a == 1); - try expect(@TypeOf(a) == comptime_float); - const b = @floatToInt(comptime_int, 2); - try expect(b == 2); - try expect(@TypeOf(b) == comptime_int); - - try expectFloatToInt(comptime_int, 1234, i16, 1234); - try expectFloatToInt(comptime_float, 12.3, comptime_int, 12); -} - -fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void { - try expect(@floatToInt(I, f) == i); -} diff --git a/test/behavior/defer.zig b/test/behavior/defer.zig index f485dadcd7..b574b25ce5 100644 --- a/test/behavior/defer.zig +++ b/test/behavior/defer.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("std"); const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; @@ -61,3 +62,58 @@ test "return variable while defer expression in scope to modify it" { try S.doTheTest(); comptime try S.doTheTest(); } + +var result: [3]u8 = undefined; +var index: usize = undefined; + +fn runSomeErrorDefers(x: bool) !bool { + index = 0; + defer { + result[index] = 'a'; + index += 1; + } + errdefer { + result[index] = 'b'; + index += 1; + } + defer { + result[index] = 'c'; + index += 1; + } + return if (x) x else error.FalseNotAllowed; +} + +test "mixing normal and error defers" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try expect(runSomeErrorDefers(true) catch unreachable); + try expect(result[0] == 'c'); + try expect(result[1] == 'a'); + + const ok = runSomeErrorDefers(false) catch |err| x: { + try expect(err == error.FalseNotAllowed); + break :x true; + }; + try expect(ok); + try expect(result[0] == 'c'); + try expect(result[1] == 'b'); + try expect(result[2] == 'a'); +} + +test "errdefer with payload" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn foo() !i32 { + errdefer |a| { + expectEqual(error.One, a) catch @panic("test failure"); + } + return error.One; + } + fn doTheTest() !void { + try expectError(error.One, foo()); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} diff --git a/test/behavior/defer_stage1.zig b/test/behavior/defer_stage1.zig deleted file mode 100644 index bb8cd51755..0000000000 --- a/test/behavior/defer_stage1.zig +++ /dev/null @@ -1,55 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const expectEqual = std.testing.expectEqual; -const expectError = std.testing.expectError; - -var result: [3]u8 = undefined; -var index: usize = undefined; - -fn runSomeErrorDefers(x: bool) !bool { - index = 0; - defer { - result[index] = 'a'; - index += 1; - } - errdefer { - result[index] = 'b'; - index += 1; - } - defer { - result[index] = 'c'; - index += 1; - } - return if (x) x else error.FalseNotAllowed; -} - -test "mixing normal and error defers" { - try expect(runSomeErrorDefers(true) catch unreachable); - try expect(result[0] == 'c'); - try expect(result[1] == 'a'); - - const ok = runSomeErrorDefers(false) catch |err| x: { - try expect(err == error.FalseNotAllowed); - break :x true; - }; - try expect(ok); - try expect(result[0] == 'c'); - try expect(result[1] == 'b'); - try expect(result[2] == 'a'); -} - -test "errdefer with payload" { - const S = struct { - fn foo() !i32 { - errdefer |a| { - expectEqual(error.One, a) catch @panic("test failure"); - } - return error.One; - } - fn doTheTest() !void { - try expectError(error.One, foo()); - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index d044619edf..0a0d7e5a15 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("std"); const expect = std.testing.expect; const mem = std.mem; @@ -870,3 +871,104 @@ test "method call on an enum" { try S.doTheTest(); comptime try S.doTheTest(); } + +test "enum value allocation" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const LargeEnum = enum(u32) { + A0 = 0x80000000, + A1, + A2, + }; + + try expect(@enumToInt(LargeEnum.A0) == 0x80000000); + try expect(@enumToInt(LargeEnum.A1) == 0x80000001); + try expect(@enumToInt(LargeEnum.A2) == 0x80000002); +} + +test "enum literal casting to tagged union" { + const Arch = union(enum) { + x86_64, + arm: Arm32, + + const Arm32 = enum { + v8_5a, + v8_4a, + }; + }; + + var t = true; + var x: Arch = .x86_64; + var y = if (t) x else .x86_64; + switch (y) { + .x86_64 => {}, + else => @panic("fail"), + } +} + +const Bar = enum { A, B, C, D }; + +test "enum literal casting to error union with payload enum" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + var bar: error{B}!Bar = undefined; + bar = .B; // should never cast to the error set + + try expect((try bar) == Bar.B); +} + +test "exporting enum type and value" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + const E = enum(c_int) { one, two }; + comptime { + @export(E, .{ .name = "E" }); + } + const e: E = .two; + comptime { + @export(e, .{ .name = "e" }); + } + }; + try expect(S.e == .two); +} + +test "constant enum initialization with differing sizes" { + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + try test3_1(test3_foo); + try test3_2(test3_bar); +} +const Test3Foo = union(enum) { + One: void, + Two: f32, + Three: Test3Point, +}; +const Test3Point = struct { + x: i32, + y: i32, +}; +const test3_foo = Test3Foo{ + .Three = Test3Point{ + .x = 3, + .y = 4, + }, +}; +const test3_bar = Test3Foo{ .Two = 13 }; +fn test3_1(f: Test3Foo) !void { + switch (f) { + Test3Foo.Three => |pt| { + try expect(pt.x == 3); + try expect(pt.y == 4); + }, + else => unreachable, + } +} +fn test3_2(f: Test3Foo) !void { + switch (f) { + Test3Foo.Two => |x| { + try expect(x == 13); + }, + else => unreachable, + } +} diff --git a/test/behavior/enum_stage1.zig b/test/behavior/enum_stage1.zig deleted file mode 100644 index f8d9d0a1b2..0000000000 --- a/test/behavior/enum_stage1.zig +++ /dev/null @@ -1,97 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const mem = std.mem; -const Tag = std.meta.Tag; - -test "enum value allocation" { - const LargeEnum = enum(u32) { - A0 = 0x80000000, - A1, - A2, - }; - - try expect(@enumToInt(LargeEnum.A0) == 0x80000000); - try expect(@enumToInt(LargeEnum.A1) == 0x80000001); - try expect(@enumToInt(LargeEnum.A2) == 0x80000002); -} - -test "enum literal casting to tagged union" { - const Arch = union(enum) { - x86_64, - arm: Arm32, - - const Arm32 = enum { - v8_5a, - v8_4a, - }; - }; - - var t = true; - var x: Arch = .x86_64; - var y = if (t) x else .x86_64; - switch (y) { - .x86_64 => {}, - else => @panic("fail"), - } -} - -const Bar = enum { A, B, C, D }; - -test "enum literal casting to error union with payload enum" { - var bar: error{B}!Bar = undefined; - bar = .B; // should never cast to the error set - - try expect((try bar) == Bar.B); -} - -test "exporting enum type and value" { - const S = struct { - const E = enum(c_int) { one, two }; - comptime { - @export(E, .{ .name = "E" }); - } - const e: E = .two; - comptime { - @export(e, .{ .name = "e" }); - } - }; - try expect(S.e == .two); -} - -test "constant enum initialization with differing sizes" { - try test3_1(test3_foo); - try test3_2(test3_bar); -} -const Test3Foo = union(enum) { - One: void, - Two: f32, - Three: Test3Point, -}; -const Test3Point = struct { - x: i32, - y: i32, -}; -const test3_foo = Test3Foo{ - .Three = Test3Point{ - .x = 3, - .y = 4, - }, -}; -const test3_bar = Test3Foo{ .Two = 13 }; -fn test3_1(f: Test3Foo) !void { - switch (f) { - Test3Foo.Three => |pt| { - try expect(pt.x == 3); - try expect(pt.y == 4); - }, - else => unreachable, - } -} -fn test3_2(f: Test3Foo) !void { - switch (f) { - Test3Foo.Two => |x| { - try expect(x == 13); - }, - else => unreachable, - } -} diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 9fb6e9a8ce..7918785968 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("std"); const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; @@ -492,3 +493,308 @@ test "@tagName of @typeInfo" { const str = @tagName(@typeInfo(u8)); try expect(std.mem.eql(u8, str, "Int")); } + +test "static eval list init" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try expect(static_vec3.data[2] == 1.0); + try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); +} +const static_vec3 = vec3(0.0, 0.0, 1.0); +pub const Vec3 = struct { + data: [3]f32, +}; +pub fn vec3(x: f32, y: f32, z: f32) Vec3 { + return Vec3{ + .data = [_]f32{ x, y, z }, + }; +} + +test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + var runtime = [1]i32{3}; + comptime var i: usize = 0; + inline while (i < 2) : (i += 1) { + const result = if (i == 0) [1]i32{2} else runtime; + _ = result; + } + comptime { + try expect(i == 2); + } +} + +test "eval @setFloatMode at compile-time" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const result = comptime fnWithFloatMode(); + try expect(result == 1234.0); +} + +fn fnWithFloatMode() f32 { + @setFloatMode(std.builtin.FloatMode.Strict); + return 1234.0; +} + +test "call method on bound fn referring to var instance" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try expect(bound_fn() == 1237); +} + +const SimpleStruct = struct { + field: i32, + + fn method(self: *const SimpleStruct) i32 { + return self.field + 3; + } +}; + +var simple_struct = SimpleStruct{ .field = 1234 }; + +const bound_fn = simple_struct.method; + +test "ptr to local array argument at comptime" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + comptime { + var bytes: [10]u8 = undefined; + modifySomeBytes(bytes[0..]); + try expect(bytes[0] == 'a'); + try expect(bytes[9] == 'b'); + } +} + +fn modifySomeBytes(bytes: []u8) void { + bytes[0] = 'a'; + bytes[9] = 'b'; +} + +test "comparisons 0 <= uint and 0 > uint should be comptime" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + testCompTimeUIntComparisons(1234); +} +fn testCompTimeUIntComparisons(x: u32) void { + if (!(0 <= x)) { + @compileError("this condition should be comptime known"); + } + if (0 > x) { + @compileError("this condition should be comptime known"); + } + if (!(x >= 0)) { + @compileError("this condition should be comptime known"); + } + if (x < 0) { + @compileError("this condition should be comptime known"); + } +} + +const hi1 = "hi"; +const hi2 = hi1; +test "const global shares pointer with other same one" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try assertEqualPtrs(&hi1[0], &hi2[0]); + comptime try expect(&hi1[0] == &hi2[0]); +} +fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) !void { + try expect(ptr1 == ptr2); +} + +test "float literal at compile time not lossy" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try expect(16777216.0 + 1.0 == 16777217.0); + try expect(9007199254740992.0 + 1.0 == 9007199254740993.0); +} + +test "f128 at compile time is lossy" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); +} + +test "string literal used as comptime slice is memoized" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const a = "link"; + const b = "link"; + comptime try expect(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); + comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); +} + +pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { + _ = field_name; + return struct { + pub const Node = struct {}; + }; +} + +test "comptime function with mutable pointer is not memoized" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + comptime { + var x: i32 = 1; + const ptr = &x; + increment(ptr); + increment(ptr); + try expect(x == 3); + } +} + +fn increment(value: *i32) void { + value.* += 1; +} + +test "const ptr to comptime mutable data is not memoized" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + comptime { + var foo = SingleFieldStruct{ .x = 1 }; + try expect(foo.read_x() == 1); + foo.x = 2; + try expect(foo.read_x() == 2); + } +} + +const SingleFieldStruct = struct { + x: i32, + + fn read_x(self: *const SingleFieldStruct) i32 { + return self.x; + } +}; + +test "function which returns struct with type field causes implicit comptime" { + const ty = wrap(i32).T; + try expect(ty == i32); +} + +const Wrapper = struct { + T: type, +}; + +fn wrap(comptime T: type) Wrapper { + return Wrapper{ .T = T }; +} + +test "call method with comptime pass-by-non-copying-value self parameter" { + const S = struct { + a: u8, + + fn b(comptime s: @This()) u8 { + return s.a; + } + }; + + const s = S{ .a = 2 }; + var b = s.b(); + try expect(b == 2); +} + +test "setting backward branch quota just before a generic fn call" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + @setEvalBranchQuota(1001); + loopNTimes(1001); +} + +fn loopNTimes(comptime n: usize) void { + comptime var i = 0; + inline while (i < n) : (i += 1) {} +} + +test "variable inside inline loop that has different types on different iterations" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + try testVarInsideInlineLoop(.{ true, @as(u32, 42) }); +} + +fn testVarInsideInlineLoop(args: anytype) !void { + comptime var i = 0; + inline while (i < args.len) : (i += 1) { + const x = args[i]; + if (i == 0) try expect(x); + if (i == 1) try expect(x == 42); + } +} + +test "bit shift a u1" { + // note: when debugging this test case for stage2, be sure to run it + // in valgrind. I noticed the rhs value is undefined in the lowering + // of the const value. + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + var x: u1 = 1; + var y = x << 0; + try expect(y == 1); +} + +test "*align(1) u16 is the same as *align(1:0:2) u16" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + comptime { + try expect(*align(1:0:2) u16 == *align(1) u16); + try expect(*align(2:0:2) u16 == *u16); + } +} + +test "array concatenation forces comptime" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + var a = oneItem(3) ++ oneItem(4); + try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 })); +} + +test "array multiplication forces comptime" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + var a = oneItem(3) ** scalar(2); + try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 })); +} + +fn oneItem(x: i32) [1]i32 { + return [_]i32{x}; +} + +fn scalar(x: u32) u32 { + return x; +} + +test "comptime assign int to optional int" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + comptime { + var x: ?i32 = null; + x = 2; + x.? *= 10; + try expectEqual(20, x.?); + } +} + +test "two comptime calls with array default initialized to undefined" { + const S = struct { + const CrossTarget = struct { + dynamic_linker: DynamicLinker = DynamicLinker{}, + + pub fn parse() void { + var result: CrossTarget = .{}; + result.getCpuArch(); + } + + pub fn getCpuArch(self: CrossTarget) void { + _ = self; + } + }; + + const DynamicLinker = struct { + buffer: [255]u8 = undefined, + }; + }; + + comptime { + S.CrossTarget.parse(); + S.CrossTarget.parse(); + } +} diff --git a/test/behavior/eval_stage1.zig b/test/behavior/eval_stage1.zig deleted file mode 100644 index 5475de3aa0..0000000000 --- a/test/behavior/eval_stage1.zig +++ /dev/null @@ -1,266 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const expectEqual = std.testing.expectEqual; - -test "static eval list init" { - try expect(static_vec3.data[2] == 1.0); - try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); -} -const static_vec3 = vec3(0.0, 0.0, 1.0); -pub const Vec3 = struct { - data: [3]f32, -}; -pub fn vec3(x: f32, y: f32, z: f32) Vec3 { - return Vec3{ - .data = [_]f32{ x, y, z }, - }; -} - -test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" { - var runtime = [1]i32{3}; - comptime var i: usize = 0; - inline while (i < 2) : (i += 1) { - const result = if (i == 0) [1]i32{2} else runtime; - _ = result; - } - comptime { - try expect(i == 2); - } -} - -test "eval @setFloatMode at compile-time" { - const result = comptime fnWithFloatMode(); - try expect(result == 1234.0); -} - -fn fnWithFloatMode() f32 { - @setFloatMode(std.builtin.FloatMode.Strict); - return 1234.0; -} - -const SimpleStruct = struct { - field: i32, - - fn method(self: *const SimpleStruct) i32 { - return self.field + 3; - } -}; - -var simple_struct = SimpleStruct{ .field = 1234 }; - -const bound_fn = simple_struct.method; - -test "call method on bound fn referring to var instance" { - try expect(bound_fn() == 1237); -} - -test "ptr to local array argument at comptime" { - comptime { - var bytes: [10]u8 = undefined; - modifySomeBytes(bytes[0..]); - try expect(bytes[0] == 'a'); - try expect(bytes[9] == 'b'); - } -} - -fn modifySomeBytes(bytes: []u8) void { - bytes[0] = 'a'; - bytes[9] = 'b'; -} - -test "comparisons 0 <= uint and 0 > uint should be comptime" { - testCompTimeUIntComparisons(1234); -} -fn testCompTimeUIntComparisons(x: u32) void { - if (!(0 <= x)) { - @compileError("this condition should be comptime known"); - } - if (0 > x) { - @compileError("this condition should be comptime known"); - } - if (!(x >= 0)) { - @compileError("this condition should be comptime known"); - } - if (x < 0) { - @compileError("this condition should be comptime known"); - } -} - -const hi1 = "hi"; -const hi2 = hi1; -test "const global shares pointer with other same one" { - try assertEqualPtrs(&hi1[0], &hi2[0]); - comptime try expect(&hi1[0] == &hi2[0]); -} -fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) !void { - try expect(ptr1 == ptr2); -} - -test "float literal at compile time not lossy" { - try expect(16777216.0 + 1.0 == 16777217.0); - try expect(9007199254740992.0 + 1.0 == 9007199254740993.0); -} - -test "f128 at compile time is lossy" { - try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); -} - -pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { - _ = field_name; - return struct { - pub const Node = struct {}; - }; -} - -test "string literal used as comptime slice is memoized" { - const a = "link"; - const b = "link"; - comptime try expect(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); - comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); -} - -test "comptime function with mutable pointer is not memoized" { - comptime { - var x: i32 = 1; - const ptr = &x; - increment(ptr); - increment(ptr); - try expect(x == 3); - } -} - -fn increment(value: *i32) void { - value.* += 1; -} - -const SingleFieldStruct = struct { - x: i32, - - fn read_x(self: *const SingleFieldStruct) i32 { - return self.x; - } -}; -test "const ptr to comptime mutable data is not memoized" { - comptime { - var foo = SingleFieldStruct{ .x = 1 }; - try expect(foo.read_x() == 1); - foo.x = 2; - try expect(foo.read_x() == 2); - } -} - -const Wrapper = struct { - T: type, -}; - -fn wrap(comptime T: type) Wrapper { - return Wrapper{ .T = T }; -} - -test "function which returns struct with type field causes implicit comptime" { - const ty = wrap(i32).T; - try expect(ty == i32); -} - -test "call method with comptime pass-by-non-copying-value self parameter" { - const S = struct { - a: u8, - - fn b(comptime s: @This()) u8 { - return s.a; - } - }; - - const s = S{ .a = 2 }; - var b = s.b(); - try expect(b == 2); -} - -test "setting backward branch quota just before a generic fn call" { - @setEvalBranchQuota(1001); - loopNTimes(1001); -} - -fn loopNTimes(comptime n: usize) void { - comptime var i = 0; - inline while (i < n) : (i += 1) {} -} - -test "variable inside inline loop that has different types on different iterations" { - try testVarInsideInlineLoop(.{ true, @as(u32, 42) }); -} - -fn testVarInsideInlineLoop(args: anytype) !void { - comptime var i = 0; - inline while (i < args.len) : (i += 1) { - const x = args[i]; - if (i == 0) try expect(x); - if (i == 1) try expect(x == 42); - } -} - -test "bit shift a u1" { - var x: u1 = 1; - var y = x << 0; - try expect(y == 1); -} - -test "*align(1) u16 is the same as *align(1:0:2) u16" { - comptime { - try expect(*align(1:0:2) u16 == *align(1) u16); - try expect(*align(2:0:2) u16 == *u16); - } -} - -test "array concatenation forces comptime" { - var a = oneItem(3) ++ oneItem(4); - try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 })); -} - -test "array multiplication forces comptime" { - var a = oneItem(3) ** scalar(2); - try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 })); -} - -fn oneItem(x: i32) [1]i32 { - return [_]i32{x}; -} - -fn scalar(x: u32) u32 { - return x; -} - -test "comptime assign int to optional int" { - comptime { - var x: ?i32 = null; - x = 2; - x.? *= 10; - try expectEqual(20, x.?); - } -} - -test "two comptime calls with array default initialized to undefined" { - const S = struct { - const CrossTarget = struct { - dynamic_linker: DynamicLinker = DynamicLinker{}, - - pub fn parse() void { - var result: CrossTarget = .{}; - result.getCpuArch(); - } - - pub fn getCpuArch(self: CrossTarget) void { - _ = self; - } - }; - - const DynamicLinker = struct { - buffer: [255]u8 = undefined, - }; - }; - - comptime { - S.CrossTarget.parse(); - S.CrossTarget.parse(); - } -} diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 8cf9fbfe48..ebbbfda67b 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -250,3 +250,101 @@ test "implicit cast fn call result to optional in field result" { try S.entry(); comptime try S.entry(); } + +test "void parameters" { + try voidFun(1, void{}, 2, {}); +} +fn voidFun(a: i32, b: void, c: i32, d: void) !void { + _ = d; + const v = b; + const vv: void = if (a == 1) v else {}; + try expect(a + c == 3); + return vv; +} + +test "call function with empty string" { + acceptsString(""); +} + +fn acceptsString(foo: []u8) void { + _ = foo; +} + +test "function pointers" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const fns = [_]@TypeOf(fn1){ + fn1, + fn2, + fn3, + fn4, + }; + for (fns) |f, i| { + try expect(f() == @intCast(u32, i) + 5); + } +} +fn fn1() u32 { + return 5; +} +fn fn2() u32 { + return 6; +} +fn fn3() u32 { + return 7; +} +fn fn4() u32 { + return 8; +} + +test "number literal as an argument" { + try numberLiteralArg(3); + comptime try numberLiteralArg(3); +} + +fn numberLiteralArg(a: anytype) !void { + try expect(a == 3); +} + +test "function call with anon list literal" { + const S = struct { + fn doTheTest() !void { + try consumeVec(.{ 9, 8, 7 }); + } + + fn consumeVec(vec: [3]f32) !void { + try expect(vec[0] == 9); + try expect(vec[1] == 8); + try expect(vec[2] == 7); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "ability to give comptime types and non comptime types to same parameter" { + const S = struct { + fn doTheTest() !void { + var x: i32 = 1; + try expect(foo(x) == 10); + try expect(foo(i32) == 20); + } + + fn foo(arg: anytype) i32 { + if (@typeInfo(@TypeOf(arg)) == .Type and arg == i32) return 20; + return 9 + arg; + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "function with inferred error set but returning no error" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn foo() !void {} + }; + + const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?; + try expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len); +} diff --git a/test/behavior/fn_stage1.zig b/test/behavior/fn_stage1.zig deleted file mode 100644 index 18663f2e10..0000000000 --- a/test/behavior/fn_stage1.zig +++ /dev/null @@ -1,99 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const testing = std.testing; -const expect = testing.expect; -const expectEqual = testing.expectEqual; - -test "void parameters" { - try voidFun(1, void{}, 2, {}); -} -fn voidFun(a: i32, b: void, c: i32, d: void) !void { - _ = d; - const v = b; - const vv: void = if (a == 1) v else {}; - try expect(a + c == 3); - return vv; -} - -test "call function with empty string" { - acceptsString(""); -} - -fn acceptsString(foo: []u8) void { - _ = foo; -} - -test "function pointers" { - const fns = [_]@TypeOf(fn1){ - fn1, - fn2, - fn3, - fn4, - }; - for (fns) |f, i| { - try expect(f() == @intCast(u32, i) + 5); - } -} -fn fn1() u32 { - return 5; -} -fn fn2() u32 { - return 6; -} -fn fn3() u32 { - return 7; -} -fn fn4() u32 { - return 8; -} - -test "number literal as an argument" { - try numberLiteralArg(3); - comptime try numberLiteralArg(3); -} - -fn numberLiteralArg(a: anytype) !void { - try expect(a == 3); -} - -test "function call with anon list literal" { - const S = struct { - fn doTheTest() !void { - try consumeVec(.{ 9, 8, 7 }); - } - - fn consumeVec(vec: [3]f32) !void { - try expect(vec[0] == 9); - try expect(vec[1] == 8); - try expect(vec[2] == 7); - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "ability to give comptime types and non comptime types to same parameter" { - const S = struct { - fn doTheTest() !void { - var x: i32 = 1; - try expect(foo(x) == 10); - try expect(foo(i32) == 20); - } - - fn foo(arg: anytype) i32 { - if (@typeInfo(@TypeOf(arg)) == .Type and arg == i32) return 20; - return 9 + arg; - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "function with inferred error set but returning no error" { - const S = struct { - fn foo() !void {} - }; - - const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?; - try expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len); -} diff --git a/test/behavior/for.zig b/test/behavior/for.zig index c6d8eeac57..b4416caa28 100644 --- a/test/behavior/for.zig +++ b/test/behavior/for.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("std"); const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; @@ -133,3 +134,59 @@ test "2 break statements and an else" { try S.entry(true, false); comptime try S.entry(true, false); } + +test "for loop with pointer elem var" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const source = "abcdefg"; + var target: [source.len]u8 = undefined; + mem.copy(u8, target[0..], source); + mangleString(target[0..]); + try expect(mem.eql(u8, &target, "bcdefgh")); + + for (source) |*c, i| { + _ = i; + try expect(@TypeOf(c) == *const u8); + } + for (target) |*c, i| { + _ = i; + try expect(@TypeOf(c) == *u8); + } +} + +fn mangleString(s: []u8) void { + for (s) |*c| { + c.* += 1; + } +} + +test "for copies its payload" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + var x = [_]usize{ 1, 2, 3 }; + for (x) |value, i| { + // Modify the original array + x[i] += 99; + try expectEqual(value, i + 1); + } + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "for on slice with allowzero ptr" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest(slice: []const u8) !void { + var ptr = @ptrCast([*]allowzero const u8, slice.ptr)[0..slice.len]; + for (ptr) |x, i| try expect(x == i + 1); + for (ptr) |*x, i| try expect(x.* == i + 1); + } + }; + try S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); + comptime try S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); +} diff --git a/test/behavior/for_stage1.zig b/test/behavior/for_stage1.zig deleted file mode 100644 index 9518c4b5b4..0000000000 --- a/test/behavior/for_stage1.zig +++ /dev/null @@ -1,54 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const expectEqual = std.testing.expectEqual; -const mem = std.mem; - -test "for loop with pointer elem var" { - const source = "abcdefg"; - var target: [source.len]u8 = undefined; - mem.copy(u8, target[0..], source); - mangleString(target[0..]); - try expect(mem.eql(u8, &target, "bcdefgh")); - - for (source) |*c, i| { - _ = i; - try expect(@TypeOf(c) == *const u8); - } - for (target) |*c, i| { - _ = i; - try expect(@TypeOf(c) == *u8); - } -} - -fn mangleString(s: []u8) void { - for (s) |*c| { - c.* += 1; - } -} - -test "for copies its payload" { - const S = struct { - fn doTheTest() !void { - var x = [_]usize{ 1, 2, 3 }; - for (x) |value, i| { - // Modify the original array - x[i] += 99; - try expectEqual(value, i + 1); - } - } - }; - try S.doTheTest(); - comptime try S.doTheTest(); -} - -test "for on slice with allowzero ptr" { - const S = struct { - fn doTheTest(slice: []const u8) !void { - var ptr = @ptrCast([*]allowzero const u8, slice.ptr)[0..slice.len]; - for (ptr) |x, i| try expect(x == i + 1); - for (ptr) |*x, i| try expect(x.* == i + 1); - } - }; - try S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); - comptime try S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); -} diff --git a/test/behavior/if.zig b/test/behavior/if.zig index e907f288de..7f80229332 100644 --- a/test/behavior/if.zig +++ b/test/behavior/if.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("std"); const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; @@ -88,3 +89,21 @@ test "if copies its payload" { try S.doTheTest(); comptime try S.doTheTest(); } + +test "if prongs cast to expected type instead of peer type resolution" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest(f: bool) !void { + var x: i32 = 0; + x = if (f) 1 else 2; + try expect(x == 2); + + var b = true; + const y: i32 = if (b) 1 else 2; + try expect(y == 1); + } + }; + try S.doTheTest(false); + comptime try S.doTheTest(false); +} diff --git a/test/behavior/if_stage1.zig b/test/behavior/if_stage1.zig deleted file mode 100644 index df1f3f3201..0000000000 --- a/test/behavior/if_stage1.zig +++ /dev/null @@ -1,19 +0,0 @@ -const std = @import("std"); -const expect = std.testing.expect; -const expectEqual = std.testing.expectEqual; - -test "if prongs cast to expected type instead of peer type resolution" { - const S = struct { - fn doTheTest(f: bool) !void { - var x: i32 = 0; - x = if (f) 1 else 2; - try expect(x == 2); - - var b = true; - const y: i32 = if (b) 1 else 2; - try expect(y == 1); - } - }; - try S.doTheTest(false); - comptime try S.doTheTest(false); -} diff --git a/test/behavior/misc.zig b/test/behavior/misc.zig index e7d15d047c..e6138d1298 100644 --- a/test/behavior/misc.zig +++ b/test/behavior/misc.zig @@ -5,63 +5,6 @@ const expectEqualStrings = std.testing.expectEqualStrings; const mem = std.mem; const builtin = @import("builtin"); -fn emptyFn() void {} - -const addr1 = @ptrCast(*const u8, emptyFn); -test "comptime cast fn to ptr" { - const addr2 = @ptrCast(*const u8, emptyFn); - comptime try expect(addr1 == addr2); -} - -test "equality compare fn ptrs" { - var a = emptyFn; - try expect(a == a); -} - -test "string escapes" { - try expectEqualStrings("\"", "\x22"); - try expectEqualStrings("\'", "\x27"); - try expectEqualStrings("\n", "\x0a"); - try expectEqualStrings("\r", "\x0d"); - try expectEqualStrings("\t", "\x09"); - try expectEqualStrings("\\", "\x5c"); - try expectEqualStrings("\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01"); -} - -test "explicit cast optional pointers" { - const a: ?*i32 = undefined; - const b: ?*f32 = @ptrCast(?*f32, a); - _ = b; -} - -test "pointer comparison" { - const a = @as([]const u8, "a"); - const b = &a; - try expect(ptrEql(b, b)); -} -fn ptrEql(a: *const []const u8, b: *const []const u8) bool { - return a == b; -} - -test "string concatenation" { - const a = "OK" ++ " IT " ++ "WORKED"; - const b = "OK IT WORKED"; - - comptime try expect(@TypeOf(a) == *const [12:0]u8); - comptime try expect(@TypeOf(b) == *const [12:0]u8); - - const len = mem.len(b); - const len_with_null = len + 1; - { - var i: u32 = 0; - while (i < len_with_null) : (i += 1) { - try expect(a[i] == b[i]); - } - } - try expect(a[len] == 0); - try expect(b[len] == 0); -} - // can't really run this test but we can make sure it has no compile error // and generates code const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000]; @@ -91,76 +34,3 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void { b; } } - -test "thread local variable" { - const S = struct { - threadlocal var t: i32 = 1234; - }; - S.t += 1; - try expect(S.t == 1235); -} - -fn maybe(x: bool) anyerror!?u32 { - return switch (x) { - true => @as(u32, 42), - else => null, - }; -} - -test "result location is optional inside error union" { - const x = maybe(true) catch unreachable; - try expect(x.? == 42); -} - -threadlocal var buffer: [11]u8 = undefined; - -test "pointer to thread local array" { - const s = "Hello world"; - std.mem.copy(u8, buffer[0..], s); - try std.testing.expectEqualSlices(u8, buffer[0..], s); -} - -test "auto created variables have correct alignment" { - const S = struct { - fn foo(str: [*]const u8) u32 { - for (@ptrCast([*]align(1) const u32, str)[0..1]) |v| { - return v; - } - return 0; - } - }; - try expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a); - comptime try expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a); -} - -extern var opaque_extern_var: opaque {}; -var var_to_export: u32 = 42; -test "extern variable with non-pointer opaque type" { - @export(var_to_export, .{ .name = "opaque_extern_var" }); - try expect(@ptrCast(*align(1) u32, &opaque_extern_var).* == 42); -} - -test "lazy typeInfo value as generic parameter" { - const S = struct { - fn foo(args: anytype) void { - _ = args; - } - }; - S.foo(@typeInfo(@TypeOf(.{}))); -} - -test "variable name containing underscores does not shadow int primitive" { - const _u0 = 0; - const i_8 = 0; - const u16_ = 0; - const i3_2 = 0; - const u6__4 = 0; - const i2_04_8 = 0; - - _ = _u0; - _ = i_8; - _ = u16_; - _ = i3_2; - _ = u6__4; - _ = i2_04_8; -}