zig/test/behavior/eval.zig
Andrew Kelley 9afc4fe0e2 Sema: solve a false positive "depends on itself"
This improves the ABI alignment resolution code.

This commit fully enables the MachO linker code in stage3. Note,
however, that there are still miscompilations in stage3.
2022-05-06 22:40:57 -07:00

1113 lines
29 KiB
Zig

const builtin = @import("builtin");
const std = @import("std");
const assert = std.debug.assert;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
test "compile time recursion" {
try expect(some_data.len == 21);
}
var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined;
fn fibonacci(x: i32) i32 {
if (x <= 1) return 1;
return fibonacci(x - 1) + fibonacci(x - 2);
}
fn unwrapAndAddOne(blah: ?i32) i32 {
return blah.? + 1;
}
const should_be_1235 = unwrapAndAddOne(1234);
test "static add one" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
try expect(should_be_1235 == 1235);
}
test "inlined loop" {
comptime var i = 0;
comptime var sum = 0;
inline while (i <= 5) : (i += 1)
sum += i;
try expect(sum == 15);
}
fn gimme1or2(comptime a: bool) i32 {
const x: i32 = 1;
const y: i32 = 2;
comptime var z: i32 = if (a) x else y;
return z;
}
test "inline variable gets result of const if" {
try expect(gimme1or2(true) == 1);
try expect(gimme1or2(false) == 2);
}
test "static function evaluation" {
try expect(statically_added_number == 3);
}
const statically_added_number = staticAdd(1, 2);
fn staticAdd(a: i32, b: i32) i32 {
return a + b;
}
test "const expr eval on single expr blocks" {
try expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
comptime try expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
}
fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
const literal = 3;
const result = if (b) b: {
break :b literal;
} else b: {
break :b x;
};
return result;
}
test "constant expressions" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
var array: [array_size]u8 = undefined;
try expect(@sizeOf(@TypeOf(array)) == 20);
}
const array_size: u8 = 20;
fn max(comptime T: type, a: T, b: T) T {
if (T == bool) {
return a or b;
} else if (a > b) {
return a;
} else {
return b;
}
}
fn letsTryToCompareBools(a: bool, b: bool) bool {
return max(bool, a, b);
}
test "inlined block and runtime block phi" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
try expect(letsTryToCompareBools(true, true));
try expect(letsTryToCompareBools(true, false));
try expect(letsTryToCompareBools(false, true));
try expect(!letsTryToCompareBools(false, false));
comptime {
try expect(letsTryToCompareBools(true, true));
try expect(letsTryToCompareBools(true, false));
try expect(letsTryToCompareBools(false, true));
try expect(!letsTryToCompareBools(false, false));
}
}
test "eval @setRuntimeSafety at compile-time" {
const result = comptime fnWithSetRuntimeSafety();
try expect(result == 1234);
}
fn fnWithSetRuntimeSafety() i32 {
@setRuntimeSafety(true);
return 1234;
}
test "compile-time downcast when the bits fit" {
comptime {
const spartan_count: u16 = 255;
const byte = @intCast(u8, spartan_count);
try expect(byte == 255);
}
}
test "pointer to type" {
comptime {
var T: type = i32;
try expect(T == i32);
var ptr = &T;
try expect(@TypeOf(ptr) == *type);
ptr.* = f32;
try expect(T == f32);
try expect(*T == *f32);
}
}
test "a type constructed in a global expression" {
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
var l: List = undefined;
l.array[0] = 10;
l.array[1] = 11;
l.array[2] = 12;
const ptr = @ptrCast([*]u8, &l.array);
try expect(ptr[0] == 10);
try expect(ptr[1] == 11);
try expect(ptr[2] == 12);
}
const List = blk: {
const T = [10]u8;
break :blk struct {
array: T,
};
};
test "comptime function with the same args is memoized" {
comptime {
try expect(MakeType(i32) == MakeType(i32));
try expect(MakeType(i32) != MakeType(f64));
}
}
fn MakeType(comptime T: type) type {
return struct {
field: T,
};
}
test "try to trick eval with runtime if" {
try expect(testTryToTrickEvalWithRuntimeIf(true) == 10);
}
fn testTryToTrickEvalWithRuntimeIf(b: bool) usize {
comptime var i: usize = 0;
inline while (i < 10) : (i += 1) {
const result = if (b) false else true;
_ = result;
}
comptime {
return i;
}
}
test "@setEvalBranchQuota" {
comptime {
// 1001 for the loop and then 1 more for the expect fn call
@setEvalBranchQuota(1002);
var i = 0;
var sum = 0;
while (i < 1001) : (i += 1) {
sum += i;
}
try expect(sum == 500500);
}
}
test "constant struct with negation" {
try expect(vertices[0].x == @as(f32, -0.6));
}
const Vertex = struct {
x: f32,
y: f32,
r: f32,
g: f32,
b: f32,
};
const vertices = [_]Vertex{
Vertex{
.x = -0.6,
.y = -0.4,
.r = 1.0,
.g = 0.0,
.b = 0.0,
},
Vertex{
.x = 0.6,
.y = -0.4,
.r = 0.0,
.g = 1.0,
.b = 0.0,
},
Vertex{
.x = 0.0,
.y = 0.6,
.r = 0.0,
.g = 0.0,
.b = 1.0,
},
};
test "statically initialized list" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
try expect(static_point_list[0].x == 1);
try expect(static_point_list[0].y == 2);
try expect(static_point_list[1].x == 3);
try expect(static_point_list[1].y == 4);
}
const Point = struct {
x: i32,
y: i32,
};
const static_point_list = [_]Point{
makePoint(1, 2),
makePoint(3, 4),
};
fn makePoint(x: i32, y: i32) Point {
return Point{
.x = x,
.y = y,
};
}
test "statically initialized array literal" {
const y: [4]u8 = st_init_arr_lit_x;
try expect(y[3] == 4);
}
const st_init_arr_lit_x = [_]u8{ 1, 2, 3, 4 };
const CmdFn = struct {
name: []const u8,
func: fn (i32) i32,
};
const cmd_fns = [_]CmdFn{
CmdFn{
.name = "one",
.func = one,
},
CmdFn{
.name = "two",
.func = two,
},
CmdFn{
.name = "three",
.func = three,
},
};
fn one(value: i32) i32 {
return value + 1;
}
fn two(value: i32) i32 {
return value + 2;
}
fn three(value: i32) i32 {
return value + 3;
}
fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
var result: i32 = start_value;
comptime var i = 0;
inline while (i < cmd_fns.len) : (i += 1) {
if (cmd_fns[i].name[0] == prefix_char) {
result = cmd_fns[i].func(result);
}
}
return result;
}
test "comptime iterate over fn ptr list" {
try expect(performFn('t', 1) == 6);
try expect(performFn('o', 0) == 1);
try expect(performFn('w', 99) == 99);
}
test "create global array with for loop" {
try expect(global_array[5] == 5 * 5);
try expect(global_array[9] == 9 * 9);
}
const global_array = x: {
var result: [10]usize = undefined;
for (result) |*item, index| {
item.* = index * index;
}
break :x result;
};
fn generateTable(comptime T: type) [1010]T {
var res: [1010]T = undefined;
var i: usize = 0;
while (i < 1010) : (i += 1) {
res[i] = @intCast(T, i);
}
return res;
}
fn doesAlotT(comptime T: type, value: usize) T {
@setEvalBranchQuota(5000);
const table = comptime blk: {
break :blk generateTable(T);
};
return table[value];
}
test "@setEvalBranchQuota at same scope as generic function call" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
try expect(doesAlotT(u32, 2) == 2);
}
pub const Info = struct {
version: u8,
};
pub const diamond_info = Info{ .version = 0 };
test "comptime modification of const struct field" {
comptime {
var res = diamond_info;
res.version = 1;
try expect(diamond_info.version == 0);
try expect(res.version == 1);
}
}
test "refer to the type of a generic function" {
const Func = fn (type) void;
const f: Func = doNothingWithType;
f(i32);
}
fn doNothingWithType(comptime T: type) void {
_ = T;
}
test "zero extend from u0 to u1" {
var zero_u0: u0 = 0;
var zero_u1: u1 = zero_u0;
try expect(zero_u1 == 0);
}
test "return 0 from function that has u0 return type" {
const S = struct {
fn foo_zero() u0 {
return 0;
}
};
comptime {
if (S.foo_zero() != 0) {
@compileError("test failed");
}
}
}
test "statically initialized struct" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
st_init_str_foo.x += 1;
try expect(st_init_str_foo.x == 14);
}
const StInitStrFoo = struct {
x: i32,
y: bool,
};
var st_init_str_foo = StInitStrFoo{
.x = 13,
.y = true,
};
test "inline for with same type but different values" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
var res: usize = 0;
inline for ([_]type{ [2]u8, [1]u8, [2]u8 }) |T| {
var a: T = undefined;
res += a.len;
}
try expect(res == 5);
}
test "f32 at compile time is lossy" {
try expect(@as(f32, 1 << 24) + 1 == 1 << 24);
}
test "f64 at compile time is lossy" {
try expect(@as(f64, 1 << 53) + 1 == 1 << 53);
}
test {
if (builtin.zig_backend != .stage1 and builtin.os.tag == .macos) return error.SkipZigTest;
comptime try expect(@as(f128, 1 << 113) == 10384593717069655257060992658440192);
}
fn copyWithPartialInline(s: []u32, b: []u8) void {
comptime var i: usize = 0;
inline while (i < 4) : (i += 1) {
s[i] = 0;
s[i] |= @as(u32, b[i * 4 + 0]) << 24;
s[i] |= @as(u32, b[i * 4 + 1]) << 16;
s[i] |= @as(u32, b[i * 4 + 2]) << 8;
s[i] |= @as(u32, b[i * 4 + 3]) << 0;
}
}
test "binary math operator in partially inlined function" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
var s: [4]u32 = undefined;
var b: [16]u8 = undefined;
for (b) |*r, i|
r.* = @intCast(u8, i + 1);
copyWithPartialInline(s[0..], b[0..]);
try expect(s[0] == 0x1020304);
try expect(s[1] == 0x5060708);
try expect(s[2] == 0x90a0b0c);
try expect(s[3] == 0xd0e0f10);
}
test "comptime shl" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
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
var a: u128 = 3;
var b: u7 = 63;
var c: u128 = 3 << 63;
try expect((a << b) == c);
}
test "comptime bitwise operators" {
comptime {
try expect(3 & 1 == 1);
try expect(3 & -1 == 3);
try expect(-3 & -1 == -3);
try expect(3 | -1 == -1);
try expect(-3 | -1 == -1);
try expect(3 ^ -1 == -4);
try expect(-3 ^ -1 == 2);
try expect(~@as(i8, -1) == 0);
try expect(~@as(i128, -1) == 0);
try expect(18446744073709551615 & 18446744073709551611 == 18446744073709551611);
try expect(-18446744073709551615 & -18446744073709551611 == -18446744073709551615);
try expect(~@as(u128, 0) == 0xffffffffffffffffffffffffffffffff);
}
}
test "comptime shlWithOverflow" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const ct_shifted: u64 = comptime amt: {
var amt = @as(u64, 0);
_ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
break :amt amt;
};
const rt_shifted: u64 = amt: {
var amt = @as(u64, 0);
_ = @shlWithOverflow(u64, ~@as(u64, 0), 16, &amt);
break :amt amt;
};
try expect(ct_shifted == rt_shifted);
}
test "const ptr to variable data changes at runtime" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
try expect(foo_ref.name[0] == 'a');
foo_ref.name = "b";
try expect(foo_ref.name[0] == 'b');
}
const Foo = struct {
name: []const u8,
};
var foo_contents = Foo{ .name = "a" };
const foo_ref = &foo_contents;
test "runtime 128 bit integer division" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
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
var a: u128 = 152313999999999991610955792383;
var b: u128 = 10000000000000000000;
var c = a / b;
try expect(c == 15231399999);
}
test "@tagName of @typeInfo" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const str = @tagName(@typeInfo(u8));
try expect(std.mem.eql(u8, str, "Int"));
}
test "static eval list init" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
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
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 == .stage2_aarch64) 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 "call method on bound fn referring to var instance" {
if (builtin.zig_backend != .stage1) {
// Let's delay solving this one; I want to try to eliminate bound functions from
// the language.
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 == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) 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" {
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 == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) 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 "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" {
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 "*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" {
if (builtin.zig_backend != .stage1) {
// note: our plan is to change the language to support runtime array
// concatenation instead of making this test pass.
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) {
// note: our plan is to change the language to support runtime array
// multiplication instead of making this test pass.
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" {
comptime {
var x: ?i32 = null;
x = 2;
x.? *= 10;
try expectEqual(20, x.?);
}
}
test "two comptime calls with array default initialized to undefined" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
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();
}
}
test "const type-annotated local initialized with function call has correct type" {
const S = struct {
fn foo() comptime_int {
return 1234;
}
};
const x: u64 = S.foo();
try expect(@TypeOf(x) == u64);
try expect(x == 1234);
}
test "comptime pointer load through elem_ptr" {
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 fails this test
const S = struct {
x: usize,
};
comptime {
var array: [10]S = undefined;
for (array) |*elem, i| {
elem.* = .{
.x = i,
};
}
var ptr = @ptrCast([*]S, &array);
var x = ptr[0].x;
assert(x == 0);
ptr += 1;
assert(ptr[1].x == 2);
}
}
test "debug variable type resolved through indirect zero-bit types" {
const T = struct { key: []void };
const slice: []const T = &[_]T{};
_ = slice;
}
test "const local with comptime init through array init" {
const E1 = enum {
A,
fn a() void {}
};
const S = struct {
fn declarations(comptime T: type) []const std.builtin.Type.Declaration {
return @typeInfo(T).Enum.decls;
}
};
const decls = comptime [_][]const std.builtin.Type.Declaration{
S.declarations(E1),
};
try comptime expect(decls[0][0].name[0] == 'a');
}
test "closure capture type of runtime-known parameter" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const S = struct {
fn b(c: anytype) !void {
const D = struct { c: @TypeOf(c) };
var d = D{ .c = c };
try expect(d.c == 1234);
}
};
var c: i32 = 1234;
try S.b(c);
}
test "comptime break passing through runtime condition converted to runtime break" {
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 {
fn doTheTest() !void {
var runtime: u8 = 'b';
inline for ([3]u8{ 'a', 'b', 'c' }) |byte| {
bar();
if (byte == runtime) {
foo(byte);
break;
}
}
try expect(ok);
try expect(count == 2);
}
var ok = false;
var count: usize = 0;
fn foo(byte: u8) void {
ok = byte == 'b';
}
fn bar() void {
count += 1;
}
};
try S.doTheTest();
}
test "comptime break to outer loop passing through runtime condition converted to runtime break" {
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 {
fn doTheTest() !void {
var runtime: u8 = 'b';
outer: inline for ([3]u8{ 'A', 'B', 'C' }) |outer_byte| {
inline for ([3]u8{ 'a', 'b', 'c' }) |byte| {
bar(outer_byte);
if (byte == runtime) {
foo(byte);
break :outer;
}
}
}
try expect(ok);
try expect(count == 2);
}
var ok = false;
var count: usize = 0;
fn foo(byte: u8) void {
ok = byte == 'b';
}
fn bar(byte: u8) void {
_ = byte;
count += 1;
}
};
try S.doTheTest();
}
test "comptime break operand passing through runtime condition converted to runtime break" {
const S = struct {
fn doTheTest(runtime: u8) !void {
const result = inline for ([3]u8{ 'a', 'b', 'c' }) |byte| {
if (byte == runtime) {
break runtime;
}
} else 'z';
try expect(result == 'b');
}
};
try S.doTheTest('b');
comptime try S.doTheTest('b');
}
test "comptime break operand passing through runtime switch converted to runtime break" {
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const S = struct {
fn doTheTest(runtime: u8) !void {
const result = inline for ([3]u8{ 'a', 'b', 'c' }) |byte| {
switch (runtime) {
byte => break runtime,
else => {},
}
} else 'z';
try expect(result == 'b');
}
};
try S.doTheTest('b');
comptime try S.doTheTest('b');
}
test "no dependency loop for alignment of self struct" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const S = struct {
fn doTheTest() !void {
var a: namespace.A = undefined;
a.d = .{ .g = &buf };
a.d.g[3] = 42;
a.d.g[3] += 1;
try expect(a.d.g[3] == 43);
}
var buf: [10]u8 align(@alignOf([*]u8)) = undefined;
const namespace = struct {
const B = struct { a: A };
const A = C(B);
};
pub fn C(comptime B: type) type {
return struct {
d: D(F) = .{},
const F = struct { b: B };
};
}
pub fn D(comptime F: type) type {
return struct {
g: [*]align(@alignOf(F)) u8 = undefined,
};
}
};
try S.doTheTest();
}
test "no dependency loop for alignment of self bare union" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const S = struct {
fn doTheTest() !void {
var a: namespace.A = undefined;
a.d = .{ .g = &buf };
a.d.g[3] = 42;
a.d.g[3] += 1;
try expect(a.d.g[3] == 43);
}
var buf: [10]u8 align(@alignOf([*]u8)) = undefined;
const namespace = struct {
const B = union { a: A, b: void };
const A = C(B);
};
pub fn C(comptime B: type) type {
return struct {
d: D(F) = .{},
const F = struct { b: B };
};
}
pub fn D(comptime F: type) type {
return struct {
g: [*]align(@alignOf(F)) u8 = undefined,
};
}
};
try S.doTheTest();
}
test "no dependency loop for alignment of self tagged union" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const S = struct {
fn doTheTest() !void {
var a: namespace.A = undefined;
a.d = .{ .g = &buf };
a.d.g[3] = 42;
a.d.g[3] += 1;
try expect(a.d.g[3] == 43);
}
var buf: [10]u8 align(@alignOf([*]u8)) = undefined;
const namespace = struct {
const B = union(enum) { a: A, b: void };
const A = C(B);
};
pub fn C(comptime B: type) type {
return struct {
d: D(F) = .{},
const F = struct { b: B };
};
}
pub fn D(comptime F: type) type {
return struct {
g: [*]align(@alignOf(F)) u8 = undefined,
};
}
};
try S.doTheTest();
}