From 58c1d98c1463210135ab7f405d204b0769525328 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 31 Dec 2022 14:28:21 +0200 Subject: [PATCH] add tests for fixed stage1 bugs Closes #4144 Closes #4255 Closes #4372 Closes #4375 Closes #4380 Closes #4417 Closes #4423 Closes #4476 Closes #4528 Closes #4562 Closes #4572 Closes #4597 Closes #4639 Closes #4672 Closes #4782 Closes #4955 Closes #4984 Closes #4997 Closes #5010 Closes #5114 Closes #5166 Closes #5173 Closes #5276 --- lib/std/fmt.zig | 18 ++++++ lib/std/io/fixed_buffer_stream.zig | 11 ++++ test/behavior/array.zig | 8 +++ test/behavior/call.zig | 17 ++++++ test/behavior/cast.zig | 16 +++++ test/behavior/eval.zig | 35 +++++++++++ test/behavior/fn.zig | 33 ++++++++++ test/behavior/packed-struct.zig | 11 ++++ test/behavior/slice.zig | 10 ++++ test/behavior/struct.zig | 60 +++++++++++++++++++ test/behavior/translate_c_macros.zig | 4 ++ test/behavior/tuple.zig | 43 +++++++++++-- test/behavior/union.zig | 2 + ...entinel_does_not_match_target-sentinel.zig | 21 +++++++ 14 files changed, 283 insertions(+), 6 deletions(-) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 57771d8e51cb4416c68e26c2f23d965a00ddc756..94b25c79a1e6fef3da2b4b5dce2563e7b7899263 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -2773,3 +2773,21 @@ test "runtime precision specifier" { try expectFmt("3.14e+00", "{:1.[1]}", .{ number, precision }); try expectFmt("3.14e+00", "{:1.[precision]}", .{ .number = number, .precision = precision }); } + +test "recursive format function" { + const R = union(enum) { + const R = @This(); + Leaf: i32, + Branch: struct { left: *const R, right: *const R }, + + pub fn format(self: R, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + return switch (self) { + .Leaf => |n| std.fmt.format(writer, "Leaf({})", .{n}), + .Branch => |b| std.fmt.format(writer, "Branch({}, {})", .{ b.left, b.right }), + }; + } + }; + + var r = R{ .Leaf = 1 }; + try expectFmt("Leaf(1)\n", "{}\n", .{&r}); +} diff --git a/lib/std/io/fixed_buffer_stream.zig b/lib/std/io/fixed_buffer_stream.zig index b002bb47b83aa0b4c90bee99a32023a1d1001123..f486356491fa98c4d4c16245d14ecaec114d0e20 100644 --- a/lib/std/io/fixed_buffer_stream.zig +++ b/lib/std/io/fixed_buffer_stream.zig @@ -132,6 +132,17 @@ test "FixedBufferStream output" { try testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten()); } +test "FixedBufferStream output at comptime" { + comptime { + var buf: [255]u8 = undefined; + var fbs = fixedBufferStream(&buf); + const stream = fbs.writer(); + + try stream.print("{s}{s}!", .{ "Hello", "World" }); + try testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten()); + } +} + test "FixedBufferStream output 2" { var buffer: [10]u8 = undefined; var fbs = fixedBufferStream(&buffer); diff --git a/test/behavior/array.zig b/test/behavior/array.zig index 52a4d7512afbd66c19510721cb1310c0b584961b..012e0785319bcec0bbf6c73c0014a00ddfab3a4f 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -654,3 +654,11 @@ test "array init of container level array variable" { S.bar(5, 6); try expectEqual([2]usize{ 5, 6 }, S.pair); } + +test "runtime initialized sentinel-terminated array literal" { + var c: u16 = 300; + const f = &[_:0x9999]u16{c}; + const g = @ptrCast(*[4]u8, f); + try std.testing.expect(g[2] == 0x99); + try std.testing.expect(g[3] == 0x99); +} diff --git a/test/behavior/call.zig b/test/behavior/call.zig index 7cbe8891d8ae75a7a1beea7ecf4eea05525a29d6..4cdd54584f1837dccd7129387fcb0b8cce2fc3a9 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -394,3 +394,20 @@ test "recursive inline call with comptime known argument" { try expect(S.foo(4) == 20); } + +test "inline while with @call" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + + const S = struct { + fn inc(a: *u32) void { + a.* += 1; + } + }; + var a: u32 = 0; + comptime var i = 0; + inline while (i < 10) : (i += 1) { + @call(.auto, S.inc, .{&a}); + } + try expect(a == 10); +} diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index b0e067045913713235c19c08f5c52853f1890cf2..7c0746bfcd64bbfe4bb68b28cbc03fccfa2714ea 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -1528,3 +1528,19 @@ test "optional pointer coerced to optional allowzero pointer" { q = p; try expect(@ptrToInt(q.?) == 4); } + +test "ptrToInt on const inside comptime block" { + var a = comptime blk: { + const b: u8 = 1; + const c = @ptrToInt(&b); + break :blk c; + }; + try expect(@intToPtr(*const u8, a).* == 1); +} + +test "single item pointer to pointer to array to slice" { + var x: i32 = 1234; + try expect(@as([]const i32, @as(*[1]i32, &x))[0] == 1234); + const z1 = @as([]const i32, @as(*[1]i32, &x)); + try expect(z1[0] == 1234); +} diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 86409c023113f66d16b6cc7f78d215187cdf7add..2a1f2b7155113dbd247bac8990cc94026bf2ffed 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -1621,3 +1621,38 @@ test "inline for loop of functions returning error unions" { } try expect(a == 3); } + +test "if inside a switch" { + var condition = true; + var wave_type: u32 = 0; + var sample: i32 = switch (wave_type) { + 0 => if (condition) 2 else 3, + 1 => 100, + 2 => 200, + 3 => 300, + else => unreachable, + }; + try expect(sample == 2); +} + +test "function has correct return type when previous return is casted to smaller type" { + const S = struct { + fn foo(b: bool) u16 { + if (b) return @as(u8, 0xFF); + return 0xFFFF; + } + }; + try expect(S.foo(true) == 0xFF); +} + +test "early exit in container level const" { + const S = struct { + const value = blk: { + if (true) { + break :blk @as(u32, 1); + } + break :blk @as(u32, 0); + }; + }; + try expect(S.value == 1); +} diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index e306fdc2074b450eaa0f06114e3531e63ae6a515..8dca94a656e7fe46ee03b50c66b776ac9ae04c25 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -484,3 +484,36 @@ test "using @ptrCast on function pointers" { // https://github.com/ziglang/zig/issues/2626 // try comptime S.run(); } + +test "function returns function returning type" { + const S = struct { + fn a() fn () type { + return (struct { + fn b() type { + return u32; + } + }).b; + } + }; + try expect(S.a()() == u32); +} + +test "peer type resolution of inferred error set with non-void payload" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const S = struct { + fn openDataFile(mode: enum { read, write }) !u32 { + return switch (mode) { + .read => foo(), + .write => bar(), + }; + } + fn foo() error{ a, b }!u32 { + return 1; + } + fn bar() error{ c, d }!u32 { + return 2; + } + }; + try expect(try S.openDataFile(.read) == 1); +} diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index 2290b1d1cc1b69c0f44d0a06873d539cb9b1fbe6..3baaaee3d8a7a8316be7c02a9e141f989c2b03e5 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -588,3 +588,14 @@ test "overaligned pointer to packed struct" { }, } } + +test "packed struct initialized in bitcast" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + + const T = packed struct { val: u8 }; + var val: u8 = 123; + const t = @bitCast(u8, T{ .val = val }); + try expect(t == val); +} diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index 63c3178325c23a7bfc73642f1cd927250a832a00..76cadc8d843ca0f57b4f3ce310eb36c531b04333 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -737,3 +737,13 @@ test "empty slice ptr is non null" { const t = @ptrCast([*]i8, p); try expect(@ptrToInt(t) == @ptrToInt(empty_slice.ptr)); } + +test "slice decays to many pointer" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + + var buf: [8]u8 = "abcdefg\x00".*; + const p: [*:0]const u8 = buf[0..7 :0]; + try expectEqualStrings(buf[0..7], std.mem.span(p)); +} diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index dfed7d276e36120b56c6436fec5b77c85324b17b..20a09f92cc696ed776610a71e8b63e2ead306592 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -1495,3 +1495,63 @@ test "function pointer in struct returns the struct" { var a = A.f(); try expect(a.f == A.f); } + +test "no dependency loop on optional field wrapped in generic function" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + + const S = struct { + fn Atomic(comptime T: type) type { + return T; + } + const A = struct { b: Atomic(?*B) }; + const B = struct { a: ?*A }; + }; + var a: S.A = .{ .b = null }; + var b: S.B = .{ .a = &a }; + a.b = &b; + + try expect(a.b == &b); + try expect(b.a == &a); +} + +test "optional field init with tuple" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + + const S = struct { + a: ?struct { b: u32 }, + }; + var a: u32 = 0; + var b = S{ + .a = .{ .b = a }, + }; + try expect(b.a.?.b == a); +} + +test "if inside struct init inside if" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const MyStruct = struct { x: u32 }; + const b: u32 = 5; + var i: u32 = 1; + var my_var = if (i < 5) + MyStruct{ + .x = 1 + if (i > 0) b else 0, + } + else + MyStruct{ + .x = 1 + if (i > 0) b else 0, + }; + try expect(my_var.x == 6); +} + +test "optional generic function label struct field" { + const Options = struct { + isFoo: ?fn (type) u8 = defaultIsFoo, + fn defaultIsFoo(comptime _: type) u8 { + return 123; + } + }; + try expect((Options{}).isFoo.?(u8) == 123); +} diff --git a/test/behavior/translate_c_macros.zig b/test/behavior/translate_c_macros.zig index d975002f8a8c9a494536e1fe03b65a71497e73ea..8143b1bddd160f270ac90bbceb55d0a7b9fd6a9c 100644 --- a/test/behavior/translate_c_macros.zig +++ b/test/behavior/translate_c_macros.zig @@ -221,3 +221,7 @@ test "Macro that uses remainder operator. Issue #13346" { ), ); } + +test "@typeInfo on @cImport result" { + try expect(@typeInfo(h).Struct.decls.len > 1); +} diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index c80318c144fbc611d4d29b4e8a2dbb2e44db421b..f1c15fb3e3d680e84221144521cc055176f29655 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -3,6 +3,7 @@ const std = @import("std"); const testing = std.testing; const expect = testing.expect; const expectEqualStrings = std.testing.expectEqualStrings; +const expectEqual = std.testing.expectEqual; test "tuple concatenation" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -233,31 +234,31 @@ test "fieldParentPtr of anon struct" { test "offsetOf tuple" { var x: u32 = 0; const T = @TypeOf(.{ x, x }); - _ = @offsetOf(T, "1"); + try expect(@offsetOf(T, "1") == @sizeOf(u32)); } test "offsetOf anon struct" { var x: u32 = 0; const T = @TypeOf(.{ .foo = x, .bar = x }); - _ = @offsetOf(T, "bar"); + try expect(@offsetOf(T, "bar") == @sizeOf(u32)); } test "initializing tuple with mixed comptime-runtime fields" { - if (true) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO var x: u32 = 15; const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x }); var a: T = .{ -1234, 5678, x + 1 }; - _ = a; + try expect(a[2] == 16); } test "initializing anon struct with mixed comptime-runtime fields" { - if (true) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO var x: u32 = 15; const T = @TypeOf(.{ .foo = @as(i32, -1234), .bar = x }); var a: T = .{ .foo = -1234, .bar = x + 1 }; - _ = a; + try expect(a.bar == 16); } test "tuple in tuple passed to generic function" { @@ -366,3 +367,33 @@ test "tuple initialized with a runtime known value" { const w = .{W{ .w = e }}; try expectEqualStrings(w[0].w.e, "test"); } + +test "tuple of struct concatenation and coercion to array" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + + const StructWithDefault = struct { value: f32 = 42 }; + const SomeStruct = struct { array: [4]StructWithDefault }; + + const value1 = SomeStruct{ .array = .{StructWithDefault{}} ++ [_]StructWithDefault{.{}} ** 3 }; + const value2 = SomeStruct{ .array = .{.{}} ++ [_]StructWithDefault{.{}} ** 3 }; + + try expectEqual(value1, value2); +} + +test "nested runtime conditionals in tuple initializer" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + + var data: u8 = 0; + const x = .{ + if (data != 0) "" else switch (@truncate(u1, data)) { + 0 => "up", + 1 => "down", + }, + }; + try expectEqualStrings("up", x[0]); +} diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 3a0fce30ff938aa8d6506795968c1e4e4d4f0f7a..87691cf3cbfd537438ffa40466a378381f65243b 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1482,6 +1482,8 @@ test "no dependency loop when function pointer in union returns the union" { b: *const fn (x: U) void, c: *const fn (x: U) U, d: *const fn (x: u8) U, + e: *const fn (x: *U) void, + f: *const fn (x: *U) U, fn foo(x: u8) U { return .{ .a = x }; } diff --git a/test/cases/compile_errors/comptime_slice-sentinel_does_not_match_target-sentinel.zig b/test/cases/compile_errors/comptime_slice-sentinel_does_not_match_target-sentinel.zig index b574df88334d07e88e2deb2aad0040fd0b6b83e0..aa52fb97568931fc927e49e91ef6a5834768860b 100644 --- a/test/cases/compile_errors/comptime_slice-sentinel_does_not_match_target-sentinel.zig +++ b/test/cases/compile_errors/comptime_slice-sentinel_does_not_match_target-sentinel.zig @@ -53,6 +53,21 @@ export fn foo_slice() void { _ = slice; } } +export fn undefined_slice() void { + const arr: [100]u16 = undefined; + const slice = arr[0..12 :0]; + _ = slice; +} +export fn string_slice() void { + const str = "abcdefg"; + const slice = str[0..1 :12]; + _ = slice; +} +export fn typeName_slice() void { + const arr = @typeName(usize); + const slice = arr[0..2 :0]; + _ = slice; +} // error // backend=stage2 @@ -72,3 +87,9 @@ export fn foo_slice() void { // :44:29: note: expected '255', found '0' // :52:29: error: value in memory does not match slice sentinel // :52:29: note: expected '255', found '0' +// :58:22: error: value in memory does not match slice sentinel +// :58:22: note: expected '0', found 'undefined' +// :63:22: error: value in memory does not match slice sentinel +// :63:22: note: expected '12', found '98' +// :68:22: error: value in memory does not match slice sentinel +// :68:22: note: expected '0', found '105' -- 2.54.0