// 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 } }