mirror of
https://github.com/ziglang/zig.git
synced 2024-12-03 10:28:48 +00:00
152a2ceaf7
This commit also performs some refactors to `TypedValue.print` in preparation for improved comptime pointer access logic. Once that logic exists, `TypedValue.print` can use Sema to access pointers for more helpful printing. This commit also implements proposal #19435, because the existing logic there relied on some blatantly incorrect code in `Value.sliceLen`. Resolves: #19435
1364 lines
37 KiB
Zig
1364 lines
37 KiB
Zig
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const assert = std.debug.assert;
|
|
const mem = std.mem;
|
|
const expect = std.testing.expect;
|
|
const expectEqualStrings = std.testing.expectEqualStrings;
|
|
|
|
// normal comment
|
|
|
|
/// this is a documentation comment
|
|
/// doc comment line 2
|
|
fn emptyFunctionWithComments() void {}
|
|
|
|
test "empty function with comments" {
|
|
emptyFunctionWithComments();
|
|
}
|
|
|
|
test "truncate" {
|
|
try expect(testTruncate(0x10fd) == 0xfd);
|
|
comptime assert(testTruncate(0x10fd) == 0xfd);
|
|
}
|
|
fn testTruncate(x: u32) u8 {
|
|
return @as(u8, @truncate(x));
|
|
}
|
|
|
|
test "truncate to non-power-of-two integers" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
try testTrunc(u32, u1, 0b10101, 0b1);
|
|
try testTrunc(u32, u1, 0b10110, 0b0);
|
|
try testTrunc(u32, u2, 0b10101, 0b01);
|
|
try testTrunc(u32, u2, 0b10110, 0b10);
|
|
try testTrunc(i32, i5, -4, -4);
|
|
try testTrunc(i32, i5, 4, 4);
|
|
try testTrunc(i32, i5, -28, 4);
|
|
try testTrunc(i32, i5, 28, -4);
|
|
try testTrunc(i32, i5, std.math.maxInt(i32), -1);
|
|
}
|
|
|
|
test "truncate to non-power-of-two integers from 128-bit" {
|
|
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_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
|
|
|
try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010101, 0x01);
|
|
try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010110, 0x00);
|
|
try testTrunc(u128, u2, 0xffffffff_ffffffff_ffffffff_01010101, 0x01);
|
|
try testTrunc(u128, u2, 0xffffffff_ffffffff_ffffffff_01010102, 0x02);
|
|
try testTrunc(i128, i5, -4, -4);
|
|
try testTrunc(i128, i5, 4, 4);
|
|
try testTrunc(i128, i5, -28, 4);
|
|
try testTrunc(i128, i5, 28, -4);
|
|
try testTrunc(i128, i5, std.math.maxInt(i128), -1);
|
|
}
|
|
|
|
fn testTrunc(comptime Big: type, comptime Little: type, big: Big, little: Little) !void {
|
|
try expect(@as(Little, @truncate(big)) == little);
|
|
}
|
|
|
|
const g1: i32 = 1233 + 1;
|
|
var g2: i32 = 0;
|
|
|
|
test "global variables" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
try expect(g2 == 0);
|
|
g2 = g1;
|
|
try expect(g2 == 1234);
|
|
}
|
|
|
|
test "comptime keyword on expressions" {
|
|
const x: i32 = comptime x: {
|
|
break :x 1 + 2 + 3;
|
|
};
|
|
try expect(x == comptime 6);
|
|
}
|
|
|
|
test "type equality" {
|
|
try expect(*const u8 != *u8);
|
|
}
|
|
|
|
test "pointer dereferencing" {
|
|
var x = @as(i32, 3);
|
|
const y = &x;
|
|
|
|
y.* += 1;
|
|
|
|
try expect(x == 4);
|
|
try expect(y.* == 4);
|
|
}
|
|
|
|
test "const expression eval handling of variables" {
|
|
var x = true;
|
|
while (x) {
|
|
x = false;
|
|
}
|
|
}
|
|
|
|
test "character literals" {
|
|
try expect('\'' == single_quote);
|
|
}
|
|
const single_quote = '\'';
|
|
|
|
test "non const ptr to aliased type" {
|
|
const int = i32;
|
|
try expect(?*int == ?*i32);
|
|
}
|
|
|
|
test "cold function" {
|
|
thisIsAColdFn();
|
|
comptime thisIsAColdFn();
|
|
}
|
|
|
|
fn thisIsAColdFn() void {
|
|
@setCold(true);
|
|
}
|
|
|
|
test "unicode escape in character literal" {
|
|
var a: u24 = '\u{01f4a9}';
|
|
_ = &a;
|
|
try expect(a == 128169);
|
|
}
|
|
|
|
test "unicode character in character literal" {
|
|
try expect('💩' == 128169);
|
|
}
|
|
|
|
fn first4KeysOfHomeRow() []const u8 {
|
|
return "aoeu";
|
|
}
|
|
|
|
test "return string from function" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
|
|
}
|
|
|
|
test "hex escape" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
|
|
}
|
|
|
|
test "multiline string" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const s1 =
|
|
\\one
|
|
\\two)
|
|
\\three
|
|
;
|
|
const s2 = "one\ntwo)\nthree";
|
|
try expect(mem.eql(u8, s1, s2));
|
|
}
|
|
|
|
test "multiline string comments at start" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const s1 =
|
|
//\\one
|
|
\\two)
|
|
\\three
|
|
;
|
|
const s2 = "two)\nthree";
|
|
try expect(mem.eql(u8, s1, s2));
|
|
}
|
|
|
|
test "multiline string comments at end" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const s1 =
|
|
\\one
|
|
\\two)
|
|
//\\three
|
|
;
|
|
const s2 = "one\ntwo)";
|
|
try expect(mem.eql(u8, s1, s2));
|
|
}
|
|
|
|
test "multiline string comments in middle" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const s1 =
|
|
\\one
|
|
//\\two)
|
|
\\three
|
|
;
|
|
const s2 = "one\nthree";
|
|
try expect(mem.eql(u8, s1, s2));
|
|
}
|
|
|
|
test "multiline string comments at multiple places" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const s1 =
|
|
\\one
|
|
//\\two
|
|
\\three
|
|
//\\four
|
|
\\five
|
|
;
|
|
const s2 = "one\nthree\nfive";
|
|
try expect(mem.eql(u8, s1, s2));
|
|
}
|
|
|
|
test "string concatenation simple" {
|
|
try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
|
|
}
|
|
|
|
test "array mult operator" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
try expect(mem.eql(u8, "ab" ** 5, "ababababab"));
|
|
}
|
|
|
|
const OpaqueA = opaque {};
|
|
const OpaqueB = opaque {};
|
|
|
|
test "opaque types" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
|
|
|
try expect(*OpaqueA != *OpaqueB);
|
|
|
|
try expect(mem.eql(u8, @typeName(OpaqueA), "behavior.basic.OpaqueA"));
|
|
try expect(mem.eql(u8, @typeName(OpaqueB), "behavior.basic.OpaqueB"));
|
|
}
|
|
|
|
const global_a: i32 = 1234;
|
|
const global_b: *const i32 = &global_a;
|
|
const global_c: *const f32 = @as(*const f32, @ptrCast(global_b));
|
|
test "compile time global reinterpret" {
|
|
const d = @as(*const i32, @ptrCast(global_c));
|
|
try expect(d.* == 1234);
|
|
}
|
|
|
|
test "cast undefined" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const array: [100]u8 = undefined;
|
|
const slice = @as([]const u8, &array);
|
|
testCastUndefined(slice);
|
|
}
|
|
fn testCastUndefined(x: []const u8) void {
|
|
_ = x;
|
|
}
|
|
|
|
test "implicit cast after unreachable" {
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
try expect(outer() == 1234);
|
|
}
|
|
fn inner() i32 {
|
|
return 1234;
|
|
}
|
|
fn outer() i64 {
|
|
return inner();
|
|
}
|
|
|
|
test "comptime if inside runtime while which unconditionally breaks" {
|
|
testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
|
|
comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
|
|
}
|
|
fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void {
|
|
while (cond) {
|
|
if (false) {}
|
|
break;
|
|
}
|
|
}
|
|
|
|
test "implicit comptime while" {
|
|
while (false) {
|
|
@compileError("bad");
|
|
}
|
|
}
|
|
|
|
fn fnThatClosesOverLocalConst() type {
|
|
const c = 1;
|
|
return struct {
|
|
fn g() i32 {
|
|
return c;
|
|
}
|
|
};
|
|
}
|
|
|
|
test "function closes over local const" {
|
|
const x = fnThatClosesOverLocalConst().g();
|
|
try expect(x == 1);
|
|
}
|
|
|
|
test "volatile load and store" {
|
|
var number: i32 = 1234;
|
|
const ptr = @as(*volatile i32, &number);
|
|
ptr.* += 1;
|
|
try expect(ptr.* == 1235);
|
|
}
|
|
|
|
fn fA() []const u8 {
|
|
return "a";
|
|
}
|
|
fn fB() []const u8 {
|
|
return "b";
|
|
}
|
|
|
|
test "call function pointer in struct" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
|
|
|
try expect(mem.eql(u8, f3(true), "a"));
|
|
try expect(mem.eql(u8, f3(false), "b"));
|
|
}
|
|
|
|
fn f3(x: bool) []const u8 {
|
|
var wrapper: FnPtrWrapper = .{
|
|
.fn_ptr = fB,
|
|
};
|
|
|
|
if (x) {
|
|
wrapper.fn_ptr = fA;
|
|
}
|
|
|
|
return wrapper.fn_ptr();
|
|
}
|
|
|
|
const FnPtrWrapper = struct {
|
|
fn_ptr: *const fn () []const u8,
|
|
};
|
|
|
|
test "const ptr from var variable" {
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
var x: u64 = undefined;
|
|
var y: u64 = undefined;
|
|
|
|
x = 78;
|
|
copy(&x, &y);
|
|
|
|
try expect(x == y);
|
|
}
|
|
|
|
fn copy(src: *const u64, dst: *u64) void {
|
|
dst.* = src.*;
|
|
}
|
|
|
|
test "call result of if else expression" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
|
|
|
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 "variable is allowed to be a pointer to an opaque type" {
|
|
var x: i32 = 1234;
|
|
_ = hereIsAnOpaqueType(@as(*OpaqueA, @ptrCast(&x)));
|
|
}
|
|
fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
|
|
var a = ptr;
|
|
_ = &a;
|
|
return a;
|
|
}
|
|
|
|
test "take address of parameter" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
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" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
const rect_2d_vertexes = [_][1]f32{
|
|
[_]f32{1.0},
|
|
[_]f32{2.0},
|
|
};
|
|
try testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
|
|
}
|
|
|
|
test "array 2D const double ptr with offset" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
const rect_2d_vertexes = [_][2]f32{
|
|
[_]f32{ 3.0, 4.239 },
|
|
[_]f32{ 1.0, 2.0 },
|
|
};
|
|
try testArray2DConstDoublePtr(&rect_2d_vertexes[1][0]);
|
|
}
|
|
|
|
test "array 3D const double ptr with offset" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
const rect_3d_vertexes = [_][2][2]f32{
|
|
[_][2]f32{
|
|
[_]f32{ 3.0, 4.239 },
|
|
[_]f32{ 3.5, 7.2 },
|
|
},
|
|
[_][2]f32{
|
|
[_]f32{ 3.0, 4.239 },
|
|
[_]f32{ 1.0, 2.0 },
|
|
},
|
|
};
|
|
try testArray2DConstDoublePtr(&rect_3d_vertexes[1][1][0]);
|
|
}
|
|
|
|
fn testArray2DConstDoublePtr(ptr: *const f32) !void {
|
|
const ptr2 = @as([*]const f32, @ptrCast(ptr));
|
|
try expect(ptr2[0] == 1.0);
|
|
try expect(ptr2[1] == 2.0);
|
|
}
|
|
|
|
test "double implicit cast in same expression" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
var x = @as(i32, @as(u16, nine()));
|
|
_ = &x;
|
|
try expect(x == 9);
|
|
}
|
|
fn nine() u8 {
|
|
return 9;
|
|
}
|
|
|
|
test "struct inside function" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
try testStructInFn();
|
|
try comptime 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" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
try expect(getNull() == null);
|
|
}
|
|
|
|
fn getNull() ?*i32 {
|
|
return null;
|
|
}
|
|
|
|
test "global variable assignment with optional unwrapping with var initialized to undefined" {
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
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" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
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 = @as(*const u8, @ptrCast(&emptyFn));
|
|
test "comptime cast fn to ptr" {
|
|
const addr2 = @as(*const u8, @ptrCast(&emptyFn));
|
|
comptime assert(addr1 == addr2);
|
|
}
|
|
|
|
test "equality compare fn ptrs" {
|
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // Uses function pointers
|
|
|
|
var a = &emptyFn;
|
|
_ = &a;
|
|
try expect(a == a);
|
|
}
|
|
|
|
test "self reference through fn ptr field" {
|
|
if (builtin.zig_backend == .stage2_spirv64) 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_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
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" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const S = struct {
|
|
fn doTheTest() !void {
|
|
var index: usize = 1;
|
|
_ = &index;
|
|
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" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
|
|
const s1 =
|
|
\\one
|
|
\\two)
|
|
\\three
|
|
;
|
|
const s2 = "one\ntwo)\nthree";
|
|
try expect(std.mem.orderZ(u8, s1, s2) == .eq);
|
|
}
|
|
|
|
test "string escapes" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) 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" {
|
|
const a: ?*i32 = undefined;
|
|
const b: ?*f32 = @as(?*f32, @ptrCast(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" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const a = "OK" ++ " IT " ++ "WORKED";
|
|
const b = "OK IT WORKED";
|
|
|
|
comptime assert(@TypeOf(a) == *const [12:0]u8);
|
|
comptime assert(@TypeOf(b) == *const [12:0]u8);
|
|
|
|
const len = b.len;
|
|
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 "result location is optional inside error union" {
|
|
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_sparc64) 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 "auto created variables have correct alignment" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const S = struct {
|
|
fn foo(str: [*]const u8) u32 {
|
|
for (@as([*]align(1) const u32, @ptrCast(str))[0..1]) |v| {
|
|
return v;
|
|
}
|
|
return 0;
|
|
}
|
|
};
|
|
try expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a);
|
|
comptime assert(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a);
|
|
}
|
|
|
|
test "extern variable with non-pointer opaque type" {
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
|
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_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
|
|
|
@export(var_to_export, .{ .name = "opaque_extern_var" });
|
|
try expect(@as(*align(1) u32, @ptrCast(&opaque_extern_var)).* == 42);
|
|
}
|
|
extern var opaque_extern_var: opaque {};
|
|
var var_to_export: u32 = 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;
|
|
}
|
|
|
|
test "if expression type coercion" {
|
|
var cond: bool = true;
|
|
_ = &cond;
|
|
const x: u16 = if (cond) 1 else 0;
|
|
try expect(@as(u16, x) == 1);
|
|
}
|
|
|
|
test "discarding the result of various expressions" {
|
|
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_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const S = struct {
|
|
fn foo() !u32 {
|
|
return 1;
|
|
}
|
|
fn bar() ?u32 {
|
|
return 1;
|
|
}
|
|
};
|
|
_ = S.bar() orelse {
|
|
// do nothing
|
|
};
|
|
_ = S.foo() catch {
|
|
// do nothing
|
|
};
|
|
_ = switch (1) {
|
|
1 => 1,
|
|
2 => {},
|
|
else => return,
|
|
};
|
|
_ = try S.foo();
|
|
_ = if (S.bar()) |some| some else {};
|
|
_ = blk: {
|
|
if (S.bar()) |some| break :blk some;
|
|
break :blk;
|
|
};
|
|
_ = while (S.bar()) |some| break some else {};
|
|
_ = for ("foo") |char| break char else {};
|
|
}
|
|
|
|
test "labeled block implicitly ends in a break" {
|
|
var a = false;
|
|
_ = &a;
|
|
blk: {
|
|
if (a) break :blk;
|
|
}
|
|
}
|
|
|
|
test "catch in block has correct result location" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const S = struct {
|
|
fn open() error{A}!@This() {
|
|
return @This(){};
|
|
}
|
|
fn foo(_: @This()) u32 {
|
|
return 1;
|
|
}
|
|
};
|
|
const config_h_text: u32 = blk: {
|
|
var dir = S.open() catch unreachable;
|
|
break :blk dir.foo();
|
|
};
|
|
try expect(config_h_text == 1);
|
|
}
|
|
|
|
test "labeled block with runtime branch forwards its result location type to break statements" {
|
|
const E = enum { a, b };
|
|
var a = false;
|
|
_ = &a;
|
|
const e: E = blk: {
|
|
if (a) {
|
|
break :blk .a;
|
|
}
|
|
break :blk .b;
|
|
};
|
|
try expect(e == .b);
|
|
}
|
|
|
|
test "try in labeled block doesn't cast to wrong type" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const S = struct {
|
|
a: u32,
|
|
fn foo() anyerror!u32 {
|
|
return 1;
|
|
}
|
|
};
|
|
const s: ?*S = blk: {
|
|
var a = try S.foo();
|
|
_ = &a;
|
|
break :blk null;
|
|
};
|
|
_ = s;
|
|
}
|
|
|
|
test "vector initialized with array init syntax has proper type" {
|
|
comptime {
|
|
const actual = -@Vector(4, i32){ 1, 2, 3, 4 };
|
|
try std.testing.expectEqual(@Vector(4, i32){ -1, -2, -3, -4 }, actual);
|
|
}
|
|
}
|
|
|
|
test "weird array and tuple initializations" {
|
|
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_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const E = enum { a, b };
|
|
const S = struct { e: E };
|
|
var a = false;
|
|
_ = &a;
|
|
const b = S{ .e = .a };
|
|
|
|
_ = &[_]S{
|
|
if (a) .{ .e = .a } else .{ .e = .b },
|
|
};
|
|
|
|
if (true) return error.SkipZigTest;
|
|
|
|
const S2 = @TypeOf(.{ false, b });
|
|
_ = &S2{
|
|
true,
|
|
if (a) .{ .e = .a } else .{ .e = .b },
|
|
};
|
|
const S3 = @TypeOf(.{ .a = false, .b = b });
|
|
_ = &S3{
|
|
.a = true,
|
|
.b = if (a) .{ .e = .a } else .{ .e = .b },
|
|
};
|
|
}
|
|
|
|
test "array type comes from generic function" {
|
|
const S = struct {
|
|
fn A() type {
|
|
return struct { a: u8 = 0 };
|
|
}
|
|
};
|
|
const args = [_]S.A(){.{}};
|
|
_ = args;
|
|
}
|
|
|
|
test "generic function uses return type of other generic function" {
|
|
if (true) {
|
|
// This test has been failing sporadically on the CI.
|
|
// It's not enough to verify that it works locally; we need to diagnose why
|
|
// it fails on the CI sometimes before turning it back on.
|
|
// https://github.com/ziglang/zig/issues/12208
|
|
return error.SkipZigTest;
|
|
}
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
|
|
|
const S = struct {
|
|
fn call(
|
|
f: anytype,
|
|
args: anytype,
|
|
) @TypeOf(@call(.auto, f, @as(@TypeOf(args), undefined))) {
|
|
return @call(.auto, f, args);
|
|
}
|
|
|
|
fn func(arg: anytype) @TypeOf(arg) {
|
|
return arg;
|
|
}
|
|
};
|
|
try std.testing.expect(S.call(S.func, .{@as(u8, 1)}) == 1);
|
|
}
|
|
|
|
test "const alloc with comptime-known initializer is made comptime-known" {
|
|
const S = struct {
|
|
a: bool,
|
|
b: [2]u8,
|
|
};
|
|
{
|
|
const s: S = .{
|
|
.a = false,
|
|
.b = .{ 1, 2 },
|
|
};
|
|
if (s.a) @compileError("bad");
|
|
}
|
|
{
|
|
const s: S = .{
|
|
.a = false,
|
|
.b = [2]u8{ 1, 2 },
|
|
};
|
|
if (s.a) @compileError("bad");
|
|
}
|
|
{
|
|
const s: S = comptime .{
|
|
.a = false,
|
|
.b = .{ 1, 2 },
|
|
};
|
|
if (s.a) @compileError("bad");
|
|
}
|
|
{
|
|
const Const = struct {
|
|
limbs: []const usize,
|
|
positive: bool,
|
|
};
|
|
const biggest: Const = .{
|
|
.limbs = &([1]usize{comptime std.math.maxInt(usize)} ** 128),
|
|
.positive = false,
|
|
};
|
|
if (biggest.positive) @compileError("bad");
|
|
}
|
|
{
|
|
const U = union(enum) {
|
|
a: usize,
|
|
};
|
|
const u: U = .{
|
|
.a = comptime std.math.maxInt(usize),
|
|
};
|
|
if (u.a == 0) @compileError("bad");
|
|
}
|
|
}
|
|
|
|
comptime {
|
|
// coerce result ptr outside a function
|
|
const S = struct { a: comptime_int };
|
|
var s: S = undefined;
|
|
s = S{ .a = 1 };
|
|
assert(s.a == 1);
|
|
}
|
|
|
|
test "switch inside @as gets correct type" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
var a: u32 = 0;
|
|
_ = &a;
|
|
var b: [2]u32 = undefined;
|
|
b[0] = @as(u32, switch (a) {
|
|
1 => 1,
|
|
else => 0,
|
|
});
|
|
}
|
|
|
|
test "inline call of function with a switch inside the return statement" {
|
|
const S = struct {
|
|
inline fn foo(x: anytype) @TypeOf(x) {
|
|
return switch (x) {
|
|
1 => 1,
|
|
else => unreachable,
|
|
};
|
|
}
|
|
};
|
|
try expect(S.foo(1) == 1);
|
|
}
|
|
|
|
test "ambiguous reference error ignores current declaration" {
|
|
const S = struct {
|
|
const foo = 666;
|
|
|
|
const a = @This();
|
|
const b = struct {
|
|
const foo = a.foo;
|
|
const bar = struct {
|
|
bar: u32 = b.foo,
|
|
};
|
|
|
|
comptime {
|
|
_ = b.foo;
|
|
}
|
|
};
|
|
|
|
usingnamespace b;
|
|
};
|
|
try expect(S.b.foo == 666);
|
|
}
|
|
|
|
test "pointer to zero sized global is mutable" {
|
|
const S = struct {
|
|
const Thing = struct {};
|
|
|
|
var thing: Thing = undefined;
|
|
};
|
|
try expect(@TypeOf(&S.thing) == *S.Thing);
|
|
}
|
|
|
|
test "returning an opaque type from a function" {
|
|
const S = struct {
|
|
fn foo(comptime a: u32) type {
|
|
return opaque {
|
|
const b = a;
|
|
};
|
|
}
|
|
};
|
|
try expect(S.foo(123).b == 123);
|
|
}
|
|
|
|
test "orelse coercion as function argument" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
|
|
const Loc = struct { start: i32 = -1 };
|
|
const Container = struct {
|
|
a: ?Loc = null,
|
|
fn init(a: Loc) @This() {
|
|
return .{
|
|
.a = a,
|
|
};
|
|
}
|
|
};
|
|
var optional: ?Loc = .{};
|
|
_ = &optional;
|
|
const foo = Container.init(optional orelse .{});
|
|
try expect(foo.a.?.start == -1);
|
|
}
|
|
|
|
test "runtime-known globals initialized with undefined" {
|
|
const S = struct {
|
|
var array: [10]u32 = [_]u32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
|
var vp: [*]u32 = undefined;
|
|
var s: []u32 = undefined;
|
|
};
|
|
|
|
S.vp = &S.array;
|
|
S.s = S.vp[0..5];
|
|
|
|
try expect(S.s[0] == 1);
|
|
try expect(S.s[4] == 5);
|
|
}
|
|
|
|
test "arrays and vectors with big integers" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) 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;
|
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
|
|
|
// TODO: only aarch64-windows didn't pass in the PR that added this code.
|
|
// figure out why if you can run this target.
|
|
if (builtin.os.tag == .windows and builtin.cpu.arch == .aarch64) return error.SkipZigTest;
|
|
|
|
inline for (.{ u65528, u65529, u65535 }) |Int| {
|
|
var a: [1]Int = undefined;
|
|
a[0] = std.math.maxInt(Int);
|
|
try expect(a[0] == comptime std.math.maxInt(Int));
|
|
var b: @Vector(1, Int) = undefined;
|
|
b[0] = std.math.maxInt(Int);
|
|
try expect(b[0] == comptime std.math.maxInt(Int));
|
|
}
|
|
}
|
|
|
|
test "pointer to struct literal with runtime field is constant" {
|
|
const S = struct { data: usize };
|
|
var runtime_zero: usize = 0;
|
|
_ = &runtime_zero;
|
|
const ptr = &S{ .data = runtime_zero };
|
|
try expect(@typeInfo(@TypeOf(ptr)).Pointer.is_const);
|
|
}
|
|
|
|
test "integer compare" {
|
|
const S = struct {
|
|
fn doTheTestSigned(comptime T: type) !void {
|
|
var z: T = 0;
|
|
var p: T = 123;
|
|
var n: T = -123;
|
|
_ = .{ &z, &p, &n };
|
|
try expect(z == z and z != p and z != n);
|
|
try expect(p == p and p != n and n == n);
|
|
try expect(z > n and z < p and z >= n and z <= p);
|
|
try expect(!(z < n or z > p or z <= n or z >= p or z > z or z < z));
|
|
try expect(p > n and n < p and p >= n and n <= p and p >= p and p <= p and n >= n and n <= n);
|
|
try expect(!(p < n or n > p or p <= n or n >= p or p > p or p < p or n > n or n < n));
|
|
try expect(z == 0 and z != 123 and z != -123 and 0 == z and 0 != p and 0 != n);
|
|
try expect(z > -123 and p > -123 and !(n > 123));
|
|
try expect(z < 123 and !(p < 123) and n < 123);
|
|
try expect(-123 <= z and -123 <= p and -123 <= n);
|
|
try expect(123 >= z and 123 >= p and 123 >= n);
|
|
try expect(!(0 != z or 123 != p or -123 != n));
|
|
try expect(!(z > 0 or -123 > p or 123 < n));
|
|
}
|
|
fn doTheTestUnsigned(comptime T: type) !void {
|
|
var z: T = 0;
|
|
var p: T = 123;
|
|
_ = .{ &z, &p };
|
|
try expect(z == z and z != p);
|
|
try expect(p == p);
|
|
try expect(z < p and z <= p);
|
|
try expect(!(z > p or z >= p or z > z or z < z));
|
|
try expect(p >= p and p <= p);
|
|
try expect(!(p > p or p < p));
|
|
try expect(z == 0 and z != 123 and z != -123 and 0 == z and 0 != p);
|
|
try expect(z > -123 and p > -123);
|
|
try expect(z < 123 and !(p < 123));
|
|
try expect(-123 <= z and -123 <= p);
|
|
try expect(123 >= z and 123 >= p);
|
|
try expect(!(0 != z or 123 != p));
|
|
try expect(!(z > 0 or -123 > p));
|
|
}
|
|
};
|
|
inline for (.{ u8, u16, u32, u64, usize, u10, u20, u30, u60 }) |T| {
|
|
try S.doTheTestUnsigned(T);
|
|
try comptime S.doTheTestUnsigned(T);
|
|
}
|
|
inline for (.{ i8, i16, i32, i64, isize, i10, i20, i30, i60 }) |T| {
|
|
try S.doTheTestSigned(T);
|
|
try comptime S.doTheTestSigned(T);
|
|
}
|
|
}
|
|
|
|
test "reference to inferred local variable works as expected" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const Crasher = struct {
|
|
lets_crash: u64 = 0,
|
|
};
|
|
|
|
var a: Crasher = undefined;
|
|
const crasher_ptr = &a;
|
|
var crasher_local = crasher_ptr.*;
|
|
const crasher_local_ptr = &crasher_local;
|
|
crasher_local_ptr.lets_crash = 1;
|
|
|
|
try expect(crasher_local.lets_crash != a.lets_crash);
|
|
}
|
|
|
|
test "@Type returned from block" {
|
|
const T = comptime b: {
|
|
break :b @Type(.{ .Int = .{
|
|
.signedness = .unsigned,
|
|
.bits = 8,
|
|
} });
|
|
};
|
|
try std.testing.expect(T == u8);
|
|
}
|
|
|
|
test "comptime variable initialized with addresses of literals" {
|
|
comptime var st = .{
|
|
.foo = &1,
|
|
.bar = &2,
|
|
};
|
|
_ = &st;
|
|
|
|
inline for (@typeInfo(@TypeOf(st)).Struct.fields) |field| {
|
|
_ = field;
|
|
}
|
|
}
|
|
|
|
test "pointer to tuple field can be dereferenced at comptime" {
|
|
comptime {
|
|
const tuple_with_ptrs = .{ &0, &0 };
|
|
const field_ptr = (&tuple_with_ptrs.@"0");
|
|
_ = field_ptr.*;
|
|
}
|
|
}
|
|
|
|
test "proper value is returned from labeled block" {
|
|
const S = struct {
|
|
fn hash(v: *u32, key: anytype) void {
|
|
const Key = @TypeOf(key);
|
|
if (@typeInfo(Key) == .ErrorSet) {
|
|
v.* += 1;
|
|
return;
|
|
}
|
|
switch (@typeInfo(Key)) {
|
|
.ErrorUnion => blk: {
|
|
const payload = key catch |err| {
|
|
hash(v, err);
|
|
break :blk;
|
|
};
|
|
|
|
hash(v, payload);
|
|
},
|
|
|
|
else => unreachable,
|
|
}
|
|
}
|
|
};
|
|
const g: error{Test}!void = error.Test;
|
|
|
|
var v: u32 = 0;
|
|
S.hash(&v, g);
|
|
try expect(v == 1);
|
|
}
|
|
|
|
test "const inferred array of slices" {
|
|
const T = struct { v: bool };
|
|
|
|
const decls = [_][]const T{
|
|
&[_]T{
|
|
.{ .v = false },
|
|
},
|
|
};
|
|
_ = decls;
|
|
}
|
|
|
|
test "var inferred array of slices" {
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const T = struct { v: bool };
|
|
|
|
var decls = [_][]const T{
|
|
&[_]T{
|
|
.{ .v = false },
|
|
},
|
|
};
|
|
_ = &decls;
|
|
}
|
|
|
|
test "copy array of self-referential struct" {
|
|
const ListNode = struct {
|
|
next: ?*const @This() = null,
|
|
};
|
|
comptime var nodes = [_]ListNode{ .{}, .{} };
|
|
nodes[0].next = &nodes[1];
|
|
const copied_nodes = nodes;
|
|
_ = copied_nodes;
|
|
}
|
|
|
|
test "break out of block based on comptime known values" {
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
|
|
const S = struct {
|
|
const source = "A-";
|
|
|
|
fn parseNote() ?i32 {
|
|
const letter = source[0];
|
|
const modifier = source[1];
|
|
|
|
const semitone = blk: {
|
|
if (letter == 'C' and modifier == '-') break :blk @as(i32, 0);
|
|
if (letter == 'C' and modifier == '#') break :blk @as(i32, 1);
|
|
if (letter == 'D' and modifier == '-') break :blk @as(i32, 2);
|
|
if (letter == 'D' and modifier == '#') break :blk @as(i32, 3);
|
|
if (letter == 'E' and modifier == '-') break :blk @as(i32, 4);
|
|
if (letter == 'F' and modifier == '-') break :blk @as(i32, 5);
|
|
if (letter == 'F' and modifier == '#') break :blk @as(i32, 6);
|
|
if (letter == 'G' and modifier == '-') break :blk @as(i32, 7);
|
|
if (letter == 'G' and modifier == '#') break :blk @as(i32, 8);
|
|
if (letter == 'A' and modifier == '-') break :blk @as(i32, 9);
|
|
if (letter == 'A' and modifier == '#') break :blk @as(i32, 10);
|
|
if (letter == 'B' and modifier == '-') break :blk @as(i32, 11);
|
|
return null;
|
|
};
|
|
|
|
return semitone;
|
|
}
|
|
};
|
|
const result = S.parseNote();
|
|
try std.testing.expect(result.? == 9);
|
|
}
|
|
|
|
test "allocation and looping over 3-byte integer" {
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
|
|
|
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .macos) {
|
|
return error.SkipZigTest; // TODO
|
|
}
|
|
|
|
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .wasm32) {
|
|
return error.SkipZigTest; // TODO
|
|
}
|
|
|
|
try expect(@sizeOf(u24) == 4);
|
|
try expect(@sizeOf([1]u24) == 4);
|
|
try expect(@alignOf(u24) == 4);
|
|
try expect(@alignOf([1]u24) == 4);
|
|
|
|
var x = try std.testing.allocator.alloc(u24, 2);
|
|
defer std.testing.allocator.free(x);
|
|
try expect(x.len == 2);
|
|
x[0] = 0xFFFFFF;
|
|
x[1] = 0xFFFFFF;
|
|
|
|
const bytes = std.mem.sliceAsBytes(x);
|
|
try expect(@TypeOf(bytes) == []align(4) u8);
|
|
try expect(bytes.len == 8);
|
|
|
|
for (bytes) |*b| {
|
|
b.* = 0x00;
|
|
}
|
|
|
|
try expect(x[0] == 0x00);
|
|
try expect(x[1] == 0x00);
|
|
}
|
|
|
|
test "loading array from struct is not optimized away" {
|
|
const S = struct {
|
|
arr: [1]u32 = .{0},
|
|
fn doTheTest(self: *@This()) !void {
|
|
const o = self.arr;
|
|
self.arr[0] = 1;
|
|
try expect(o[0] == 0);
|
|
}
|
|
};
|
|
var s = S{};
|
|
try s.doTheTest();
|
|
}
|