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_spirv) return error.SkipZigTest;
    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_arm) return error.SkipZigTest; // TODO
    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
    if (builtin.zig_backend == .stage2_spirv) 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 "function branch hints" {
    const S = struct {
        fn none() void {
            @branchHint(.none);
        }
        fn likely() void {
            @branchHint(.likely);
        }
        fn unlikely() void {
            @branchHint(.unlikely);
        }
        fn cold() void {
            @branchHint(.cold);
        }
        fn unpredictable() void {
            @branchHint(.unpredictable);
        }
    };
    S.none();
    S.likely();
    S.unlikely();
    S.cold();
    S.unpredictable();
    comptime S.none();
    comptime S.likely();
    comptime S.unlikely();
    comptime S.cold();
    comptime S.unpredictable();
}

test "if branch hints" {
    var t: bool = undefined;
    t = true;
    if (t) {
        @branchHint(.likely);
    } else {
        @branchHint(.cold);
    }
}

test "switch branch hints" {
    var t: bool = undefined;
    t = true;
    switch (t) {
        true => {
            @branchHint(.likely);
        },
        false => {
            @branchHint(.cold);
        },
    }
}

test "orelse branch hints" {
    var x: ?u32 = undefined;
    x = 123;
    const val = x orelse val: {
        @branchHint(.cold);
        break :val 456;
    };
    try expect(val == 123);
}

test "catch branch hints" {
    var x: error{Bad}!u32 = undefined;
    x = 123;
    const val = x catch val: {
        @branchHint(.cold);
        break :val 456;
    };
    try expect(val == 123);
}

test "and/or branch hints" {
    var t: bool = undefined;
    t = true;
    try expect(t or b: {
        @branchHint(.unlikely);
        break :b false;
    });
    try expect(t and b: {
        @branchHint(.likely);
        break :b 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_spirv) return error.SkipZigTest;
    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_spirv) return error.SkipZigTest;
    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
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    const s1 =
        \\one
        //\\two
        \\three
        //\\four
        \\five
    ;
    const s2 = "one\nthree\nfive";
    try expect(mem.eql(u8, s1, s2));
}

test "string concatenation simple" {
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    try expect(mem.eql(u8, "ab" ** 5, "ababababab"));
}

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" {
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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_spirv) 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_arm) return error.SkipZigTest;
    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
    if (builtin.zig_backend == .stage2_spirv) 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)();
}

const OpaqueA = opaque {};
test "variable is allowed to be a pointer to an opaque type" {
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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_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" {
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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_sparc64) return error.SkipZigTest; // TODO
    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
    if (builtin.zig_backend == .stage2_spirv) 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_sparc64) return error.SkipZigTest; // TODO
    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
    if (builtin.zig_backend == .stage2_spirv) 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_sparc64) return error.SkipZigTest; // TODO
    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
    if (builtin.zig_backend == .stage2_spirv) 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_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
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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_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_spirv) 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_spirv) 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
    if (builtin.zig_backend == .stage2_spirv) 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" {
    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_spirv) 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_arm) return error.SkipZigTest;
    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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" {
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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_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_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_sparc64) return error.SkipZigTest; // TODO
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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_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_spirv) 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_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_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_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;
    }

    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 "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_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" {
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    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_wasm) return error.SkipZigTest;
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
    if (builtin.zig_backend == .stage2_llvm and (builtin.abi == .gnuabin32 or builtin.abi == .muslabin32)) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23805

    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);
}

fn testSignedCmp(comptime T: type) !void {
    var z: T = 0;
    var p: T = 123;
    var n: T = -123;
    var min: T = std.math.minInt(T);
    var max: T = std.math.maxInt(T);
    var half_min: T = std.math.minInt(T) / 2;
    var half_max: T = std.math.minInt(T) / 2;
    _ = .{ &z, &p, &n, &min, &max, &half_min, &half_max };
    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));

    try expect(min <= max and z <= max and p <= max and n <= max and half_max <= max and half_min <= max);
    try expect(min <= max and min <= z and min <= p and min <= n and min <= half_min and min <= half_max);
}

fn testUnsignedCmp(comptime T: type) !void {
    var z: T = 0;
    var p: T = 123;
    var max: T = std.math.maxInt(T);
    var half_max: T = std.math.minInt(T) / 2;
    _ = .{ &z, &p, &max, &half_max };
    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));

    try expect(z <= max and p <= max and half_max <= max);
    try expect(half_max != max);
}

test "integer compare <= 64 bits" {
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    inline for (.{ u8, u16, u32, u64, usize, u10, u20, u30, u60 }) |T| {
        try testUnsignedCmp(T);
        try comptime testUnsignedCmp(T);
    }
    inline for (.{ i8, i16, i32, i64, isize, i10, i20, i30, i60 }) |T| {
        try testSignedCmp(T);
        try comptime testSignedCmp(T);
    }
}

test "integer compare <= 128 bits" {
    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

    inline for (.{ u65, u96, u127, u128 }) |T| {
        try testUnsignedCmp(T);
        try comptime testUnsignedCmp(T);
    }
    inline for (.{ i65, i96, i127, i128 }) |T| {
        try testSignedCmp(T);
        try comptime testSignedCmp(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) == .error_set) {
                v.* += 1;
                return;
            }
            switch (@typeInfo(Key)) {
                .error_union => 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_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_aarch64) return error.SkipZigTest;
    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_spirv) return error.SkipZigTest;
    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

    if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .macos) {
        return error.SkipZigTest; // TODO
    }
    if (builtin.cpu.arch == .s390x and builtin.zig_backend == .stage2_llvm) 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();
}
