zig/test/self_hosted.zig

914 lines
16 KiB
Zig

// test std library
use @import("std");
#attribute("test")
fn empty_function() {}
/**
* multi line doc comment
*/
/// this is a documentation comment
/// doc comment line 2
#attribute("test")
fn comments() {
comments_f1(/* mid-line comment /* nested */ */ "OK\n");
}
fn comments_f1(s: []u8) {}
#attribute("test")
fn if_statements() {
should_be_equal(1, 1);
first_eql_third(2, 1, 2);
}
fn should_be_equal(a: i32, b: i32) {
if (a != b) {
unreachable{};
} else {
return;
}
}
fn first_eql_third(a: i32, b: i32, c: i32) {
if (a == b) {
unreachable{};
} else if (b == c) {
unreachable{};
} else if (a == c) {
return;
} else {
unreachable{};
}
}
#attribute("test")
fn params() {
assert(test_params_add(22, 11) == 33);
}
fn test_params_add(a: i32, b: i32) -> i32 {
a + b
}
#attribute("test")
fn local_variables() {
test_loc_vars(2);
}
fn test_loc_vars(b: i32) {
const a: i32 = 1;
if (a + b != 3) unreachable{};
}
#attribute("test")
fn bool_literals() {
assert(true);
assert(!false);
}
#attribute("test")
fn void_parameters() {
void_fun(1, void{}, 2, {});
}
fn void_fun(a : i32, b : void, c : i32, d : void) {
const v = b;
const vv : void = if (a == 1) {v} else {};
assert(a + c == 3);
return vv;
}
#attribute("test")
fn mutable_local_variables() {
var zero : i32 = 0;
assert(zero == 0);
var i = i32(0);
while (i != 3) {
i += 1;
}
assert(i == 3);
}
#attribute("test")
fn arrays() {
var array : [5]i32 = undefined;
var i : i32 = 0;
while (i < 5) {
array[i] = i + 1;
i = array[i];
}
i = 0;
var accumulator = i32(0);
while (i < 5) {
accumulator += array[i];
i += 1;
}
assert(accumulator == 15);
assert(get_array_len(array) == 5);
}
fn get_array_len(a: []i32) -> isize {
a.len
}
#attribute("test")
fn short_circuit() {
var hit_1 = false;
var hit_2 = false;
var hit_3 = false;
var hit_4 = false;
if (true || {assert_runtime(false); false}) {
hit_1 = true;
}
if (false || { hit_2 = true; false }) {
assert_runtime(false);
}
if (true && { hit_3 = true; false }) {
assert_runtime(false);
}
if (false && {assert_runtime(false); false}) {
assert_runtime(false);
} else {
hit_4 = true;
}
assert(hit_1);
assert(hit_2);
assert(hit_3);
assert(hit_4);
}
#static_eval_enable(false)
fn assert_runtime(b: bool) {
if (!b) unreachable{}
}
#attribute("test")
fn modify_operators() {
var i : i32 = 0;
i += 5; assert(i == 5);
i -= 2; assert(i == 3);
i *= 20; assert(i == 60);
i /= 3; assert(i == 20);
i %= 11; assert(i == 9);
i <<= 1; assert(i == 18);
i >>= 2; assert(i == 4);
i = 6;
i &= 5; assert(i == 4);
i ^= 6; assert(i == 2);
i = 6;
i |= 3; assert(i == 7);
}
#attribute("test")
fn separate_block_scopes() {
{
const no_conflict : i32 = 5;
assert(no_conflict == 5);
}
const c = {
const no_conflict = i32(10);
no_conflict
};
assert(c == 10);
}
#attribute("test")
fn void_struct_fields() {
const foo = VoidStructFieldsFoo {
.a = void{},
.b = 1,
.c = void{},
};
assert(foo.b == 1);
assert(@sizeof(VoidStructFieldsFoo) == 4);
}
struct VoidStructFieldsFoo {
a : void,
b : i32,
c : void,
}
#attribute("test")
pub fn structs() {
var foo : StructFoo = undefined;
@memset(&foo, 0, @sizeof(StructFoo));
foo.a += 1;
foo.b = foo.a == 1;
test_foo(foo);
test_mutation(&foo);
assert(foo.c == 100);
}
struct StructFoo {
a : i32,
b : bool,
c : f32,
}
fn test_foo(foo : StructFoo) {
assert(foo.b);
}
fn test_mutation(foo : &StructFoo) {
foo.c = 100;
}
struct Node {
val: Val,
next: &Node,
}
struct Val {
x: i32,
}
#attribute("test")
fn struct_point_to_self() {
var root : Node = undefined;
root.val.x = 1;
var node : Node = undefined;
node.next = &root;
node.val.x = 2;
root.next = &node;
assert(node.next.next.next.val.x == 1);
}
#attribute("test")
fn struct_byval_assign() {
var foo1 : StructFoo = undefined;
var foo2 : StructFoo = undefined;
foo1.a = 1234;
foo2.a = 0;
assert(foo2.a == 0);
foo2 = foo1;
assert(foo2.a == 1234);
}
fn struct_initializer() {
const val = Val { .x = 42 };
assert(val.x == 42);
}
const g1 : i32 = 1233 + 1;
var g2 : i32 = 0;
#attribute("test")
fn global_variables() {
assert(g2 == 0);
g2 = g1;
assert(g2 == 1234);
}
#attribute("test")
fn while_loop() {
var i : i32 = 0;
while (i < 4) {
i += 1;
}
assert(i == 4);
assert(while_loop_1() == 1);
}
fn while_loop_1() -> i32 {
return while_loop_2();
}
fn while_loop_2() -> i32 {
while (true) {
return 1;
}
}
#attribute("test")
fn void_arrays() {
var array: [4]void = undefined;
array[0] = void{};
array[1] = array[2];
assert(@sizeof(@typeof(array)) == 0);
assert(array.len == 4);
}
#attribute("test")
fn three_expr_in_a_row() {
assert_false(false || false || false);
assert_false(true && true && false);
assert_false(1 | 2 | 4 != 7);
assert_false(3 ^ 6 ^ 8 != 13);
assert_false(7 & 14 & 28 != 4);
assert_false(9 << 1 << 2 != 9 << 3);
assert_false(90 >> 1 >> 2 != 90 >> 3);
assert_false(100 - 1 + 1000 != 1099);
assert_false(5 * 4 / 2 % 3 != 1);
assert_false(i32(i32(5)) != 5);
assert_false(!!false);
assert_false(i32(7) != --(i32(7)));
}
fn assert_false(b: bool) {
assert(!b);
}
#attribute("test")
fn maybe_type() {
const x : ?bool = true;
if (const y ?= x) {
if (y) {
// OK
} else {
unreachable{};
}
} else {
unreachable{};
}
const next_x : ?i32 = null;
const z = next_x ?? 1234;
assert(z == 1234);
const final_x : ?i32 = 13;
const num = final_x ?? unreachable{};
assert(num == 13);
}
#attribute("test")
fn enum_type() {
const foo1 = EnumTypeFoo.One(13);
const foo2 = EnumTypeFoo.Two(EnumType { .x = 1234, .y = 5678, });
const bar = EnumTypeBar.B;
assert(bar == EnumTypeBar.B);
assert(@member_count(EnumTypeFoo) == 3);
assert(@member_count(EnumTypeBar) == 4);
const expected_foo_size = switch (@compile_var("arch")) {
i386 => 20,
x86_64 => 24,
else => unreachable{},
};
assert(@sizeof(EnumTypeFoo) == expected_foo_size);
assert(@sizeof(EnumTypeBar) == 1);
}
struct EnumType {
x: u64,
y: u64,
}
enum EnumTypeFoo {
One: i32,
Two: EnumType,
Three: void,
}
enum EnumTypeBar {
A,
B,
C,
D,
}
#attribute("test")
fn array_literal() {
const HEX_MULT = []u16{4096, 256, 16, 1};
assert(HEX_MULT.len == 4);
assert(HEX_MULT[1] == 256);
}
#attribute("test")
fn const_number_literal() {
const one = 1;
const eleven = ten + one;
assert(eleven == 11);
}
const ten = 10;
#attribute("test")
fn error_values() {
const a = i32(error.err1);
const b = i32(error.err2);
assert(a != b);
}
error err1;
error err2;
#attribute("test")
fn fn_call_of_struct_field() {
if (call_struct_field(Foo {.ptr = a_func,}) != 13) {
unreachable{};
}
}
struct Foo {
ptr: fn() -> i32,
}
fn a_func() -> i32 { 13 }
fn call_struct_field(foo: Foo) -> i32 {
return foo.ptr();
}
#attribute("test")
fn redefinition_of_error_values_allowed() {
should_be_not_equal(error.AnError, error.SecondError);
}
error AnError;
error AnError;
error SecondError;
fn should_be_not_equal(a: error, b: error) {
if (a == b) unreachable{}
}
#attribute("test")
fn constant_enum_with_payload() {
var empty = AnEnumWithPayload.Empty;
var full = AnEnumWithPayload.Full(13);
should_be_empty(empty);
should_be_not_empty(full);
}
fn should_be_empty(x: AnEnumWithPayload) {
switch (x) {
Empty => {},
else => unreachable{},
}
}
fn should_be_not_empty(x: AnEnumWithPayload) {
switch (x) {
Empty => unreachable{},
else => {},
}
}
enum AnEnumWithPayload {
Empty,
Full: i32,
}
#attribute("test")
fn continue_in_for_loop() {
const array = []i32 {1, 2, 3, 4, 5};
var sum : i32 = 0;
for (array) |x| {
sum += x;
if (x < 3) {
continue;
}
break;
}
if (sum != 6) unreachable{}
}
#attribute("test")
fn cast_bool_to_int() {
const t = true;
const f = false;
assert(i32(t) == i32(1));
assert(i32(f) == i32(0));
non_const_cast_bool_to_int(t, f);
}
fn non_const_cast_bool_to_int(t: bool, f: bool) {
assert(i32(t) == i32(1));
assert(i32(f) == i32(0));
}
#attribute("test")
fn switch_on_enum() {
const fruit = Fruit.Orange;
non_const_switch_on_enum(fruit);
}
enum Fruit {
Apple,
Orange,
Banana,
}
#static_eval_enable(false)
fn non_const_switch_on_enum(fruit: Fruit) {
switch (fruit) {
Apple => unreachable{},
Orange => {},
Banana => unreachable{},
}
}
#attribute("test")
fn switch_statement() {
non_const_switch(SwitchStatmentFoo.C);
}
#static_eval_enable(false)
fn non_const_switch(foo: SwitchStatmentFoo) {
const val: i32 = switch (foo) {
A => 1,
B => 2,
C => 3,
D => 4,
};
if (val != 3) unreachable{};
}
enum SwitchStatmentFoo {
A,
B,
C,
D,
}
#attribute("test")
fn switch_prong_with_var() {
switch_prong_with_var_fn(SwitchProngWithVarEnum.One(13));
switch_prong_with_var_fn(SwitchProngWithVarEnum.Two(13.0));
switch_prong_with_var_fn(SwitchProngWithVarEnum.Meh);
}
enum SwitchProngWithVarEnum {
One: i32,
Two: f32,
Meh,
}
#static_eval_enable(false)
fn switch_prong_with_var_fn(a: SwitchProngWithVarEnum) {
switch(a) {
One => |x| {
if (x != 13) unreachable{};
},
Two => |x| {
if (x != 13.0) unreachable{};
},
Meh => |x| {
const v: void = x;
},
}
}
#attribute("test")
fn err_return_in_assignment() {
%%do_err_return_in_assignment();
}
#static_eval_enable(false)
fn do_err_return_in_assignment() -> %void {
var x : i32 = undefined;
x = %return make_a_non_err();
}
fn make_a_non_err() -> %i32 {
return 1;
}
#attribute("test")
fn rhs_maybe_unwrap_return() {
const x = ?true;
const y = x ?? return;
}
#attribute("test")
fn implicit_cast_fn_unreachable_return() {
wants_fn_with_void(fn_with_unreachable);
}
fn wants_fn_with_void(f: fn()) { }
fn fn_with_unreachable() -> unreachable {
unreachable {}
}
#attribute("test")
fn explicit_cast_maybe_pointers() {
const a: ?&i32 = undefined;
const b: ?&f32 = (?&f32)(a);
}
#attribute("test")
fn const_expr_eval_on_single_expr_blocks() {
assert(const_expr_eval_on_single_expr_blocks_fn(1, true) == 3);
}
fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 {
const literal = 3;
const result = if (b) {
literal
} else {
x
};
return result;
}
#attribute("test")
fn builtin_const_eval() {
const x : i32 = @const_eval(1 + 2 + 3);
assert(x == @const_eval(6));
}
#attribute("test")
fn slicing() {
var array : [20]i32 = undefined;
array[5] = 1234;
var slice = array[5...10];
if (slice.len != 5) unreachable{};
const ptr = &slice[0];
if (ptr[0] != 1234) unreachable{};
var slice_rest = array[10...];
if (slice_rest.len != 10) unreachable{};
}
#attribute("test")
fn memcpy_and_memset_intrinsics() {
var foo : [20]u8 = undefined;
var bar : [20]u8 = undefined;
@memset(&foo[0], 'A', foo.len);
@memcpy(&bar[0], &foo[0], bar.len);
if (bar[11] != 'A') unreachable{};
}
#attribute("test")
fn array_dot_len_const_expr() { }
struct ArrayDotLenConstExpr {
y: [@const_eval(some_array.len)]u8,
}
const some_array = []u8 {0, 1, 2, 3};
#attribute("test")
fn count_leading_zeroes() {
assert(@clz(u8, 0b00001010) == 4);
assert(@clz(u8, 0b10001010) == 0);
assert(@clz(u8, 0b00000000) == 8);
}
#attribute("test")
fn count_trailing_zeroes() {
assert(@ctz(u8, 0b10100000) == 5);
assert(@ctz(u8, 0b10001010) == 1);
assert(@ctz(u8, 0b00000000) == 8);
}
#attribute("test")
fn multiline_string() {
const s1 = r"AOEU(
one
two)
three)AOEU";
const s2 = "\none\ntwo)\nthree";
const s3 = r"(
one
two)
three)";
assert(str_eql(s1, s2));
assert(str_eql(s3, s2));
}
#attribute("test")
fn simple_generic_fn() {
assert(max(i32)(3, -1) == 3);
assert(max(f32)(0.123, 0.456) == 0.456);
assert(add(2)(3) == 5);
}
fn max(T: type)(a: T, b: T) -> T {
return if (a > b) a else b;
}
fn add(a: i32)(b: i32) -> i32 {
return a + b;
}
#attribute("test")
fn constant_equal_function_pointers() {
const alias = empty_fn;
assert(@const_eval(empty_fn == alias));
}
fn empty_fn() {}
#attribute("test")
fn generic_function_equality() {
assert(max(i32) == max(i32));
}
#attribute("test")
fn generic_malloc_free() {
const a = %%mem_alloc(u8)(10);
mem_free(u8)(a);
}
const some_mem : [100]u8 = undefined;
#static_eval_enable(false)
fn mem_alloc(T: type)(n: isize) -> %[]T {
return (&T)(&some_mem[0])[0...n];
}
fn mem_free(T: type)(mem: []T) { }
#attribute("test")
fn call_fn_with_empty_string() {
accepts_string("");
}
fn accepts_string(foo: []u8) { }
#attribute("test")
fn hex_escape() {
assert(str_eql("\x68\x65\x6c\x6c\x6f", "hello"));
}
error AnError;
error ALongerErrorName;
#attribute("test")
fn error_name_string() {
assert(str_eql(@err_name(error.AnError), "AnError"));
assert(str_eql(@err_name(error.ALongerErrorName), "ALongerErrorName"));
}
#attribute("test")
fn goto_and_labels() {
goto_loop();
assert(goto_counter == 10);
}
fn goto_loop() {
var i: i32 = 0;
goto cond;
loop:
i += 1;
cond:
if (!(i < 10)) goto end;
goto_counter += 1;
goto loop;
end:
}
var goto_counter: i32 = 0;
#attribute("test")
fn goto_leave_defer_scope() {
test_goto_leave_defer_scope(true);
}
#static_eval_enable(false)
fn test_goto_leave_defer_scope(b: bool) {
var it_worked = false;
goto entry;
exit:
if (it_worked) {
return;
}
unreachable{};
entry:
defer it_worked = true;
if (b) goto exit;
}
#attribute("test")
fn cast_undefined() {
const array: [100]u8 = undefined;
const slice = ([]u8)(array);
test_cast_undefined(slice);
}
fn test_cast_undefined(x: []u8) {}
#attribute("test")
fn cast_small_unsigned_to_larger_signed() {
assert(cast_small_unsigned_to_larger_signed_1(200) == i16(200));
assert(cast_small_unsigned_to_larger_signed_2(9999) == isize(9999));
}
fn cast_small_unsigned_to_larger_signed_1(x: u8) -> i16 { x }
fn cast_small_unsigned_to_larger_signed_2(x: u16) -> isize { x }
#attribute("test")
fn implicit_cast_after_unreachable() {
assert(outer() == 1234);
}
fn inner() -> i32 { 1234 }
fn outer() -> isize {
return inner();
}
#attribute("test")
fn else_if_expression() {
assert(else_if_expression_f(1) == 1);
}
fn else_if_expression_f(c: u8) -> u8 {
if (c == 0) {
0
} else if (c == 1) {
1
} else {
2
}
}
#attribute("test")
fn err_binary_operator() {
const a = err_binary_operator_g(true) %% 3;
const b = err_binary_operator_g(false) %% 3;
assert(a == 3);
assert(b == 10);
}
error ItBroke;
fn err_binary_operator_g(x: bool) -> %isize {
if (x) {
error.ItBroke
} else {
10
}
}
#attribute("test")
fn unwrap_simple_value_from_error() {
const i = %%unwrap_simple_value_from_error_do();
assert(i == 13);
}
fn unwrap_simple_value_from_error_do() -> %isize { 13 }
#attribute("test")
fn store_member_function_in_variable() {
const instance = MemberFnTestFoo { .x = 1234, };
const member_fn = MemberFnTestFoo.member;
const result = member_fn(instance);
assert(result == 1234);
}
struct MemberFnTestFoo {
x: i32,
fn member(foo: MemberFnTestFoo) -> i32 { foo.x }
}
#attribute("test")
fn call_member_function_directly() {
const instance = MemberFnTestFoo { .x = 1234, };
const result = MemberFnTestFoo.member(instance);
assert(result == 1234);
}
#attribute("test")
fn member_functions() {
const r = MemberFnRand {.seed = 1234};
assert(r.get_seed() == 1234);
}
struct MemberFnRand {
seed: u32,
pub fn get_seed(r: MemberFnRand) -> u32 {
r.seed
}
}