mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
3710 lines
82 KiB
Rust
3710 lines
82 KiB
Rust
#[cfg(feature = "gen-llvm")]
|
|
use crate::helpers::llvm::assert_evals_to;
|
|
|
|
#[cfg(feature = "gen-dev")]
|
|
use crate::helpers::dev::assert_evals_to;
|
|
|
|
#[cfg(feature = "gen-wasm")]
|
|
use crate::helpers::wasm::assert_evals_to;
|
|
|
|
use indoc::indoc;
|
|
#[allow(unused_imports)]
|
|
use roc_std::RocStr;
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn basic_int() {
|
|
assert_evals_to!("123", 123, i64);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn basic_float() {
|
|
assert_evals_to!("1234.0", 1234.0, f64);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn branch_first_float() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when 1.23 is
|
|
1.23 -> 12
|
|
_ -> 34
|
|
"#
|
|
),
|
|
12,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn branch_second_float() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when 2.34 is
|
|
1.23 -> 63
|
|
_ -> 48
|
|
"#
|
|
),
|
|
48,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn branch_third_float() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when 10.0 is
|
|
1.0 -> 63
|
|
2.0 -> 48
|
|
_ -> 112
|
|
"#
|
|
),
|
|
112,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn branch_first_int() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when 1 is
|
|
1 -> 12
|
|
_ -> 34
|
|
"#
|
|
),
|
|
12,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn branch_second_int() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when 2 is
|
|
1 -> 63
|
|
_ -> 48
|
|
"#
|
|
),
|
|
48,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
|
fn branch_third_int() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when 10 is
|
|
1 -> 63
|
|
2 -> 48
|
|
_ -> 112
|
|
"#
|
|
),
|
|
112,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn branch_store_variable() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when 0 is
|
|
1 -> 12
|
|
a -> a
|
|
"#
|
|
),
|
|
0,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
|
fn when_one_element_tag() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
x : [Pair (Int a) (Int a)]
|
|
x = Pair 0x2 0x3
|
|
|
|
when x is
|
|
Pair l r -> l + r
|
|
"#
|
|
),
|
|
5,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn when_two_element_tag_first() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
x : [A (Int a), B (Int a)]
|
|
x = A 0x2
|
|
|
|
when x is
|
|
A v -> v
|
|
B v -> v
|
|
"#
|
|
),
|
|
2,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn when_two_element_tag_second() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
x : [A (Int a), B (Int a)]
|
|
x = B 0x3
|
|
|
|
when x is
|
|
A v -> v
|
|
B v -> v
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn gen_when_one_branch() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when 1.23 is
|
|
_ -> 23
|
|
"#
|
|
),
|
|
23,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn gen_large_when_int() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
foo = \num ->
|
|
when num is
|
|
0 -> 200
|
|
-3 -> 111 # TODO adding more negative numbers reproduces parsing bugs here
|
|
3 -> 789
|
|
1 -> 123
|
|
2 -> 456
|
|
_ -> 1000
|
|
|
|
foo -3
|
|
"#
|
|
),
|
|
111,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-wasm"))]
|
|
fn gen_large_when_float() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
foo = \num ->
|
|
when num is
|
|
0.5 -> 200.1
|
|
-3.6 -> 111.2 # TODO adding more negative numbers reproduces parsing bugs here
|
|
3.6 -> 789.5
|
|
1.7 -> 123.3
|
|
2.8 -> 456.4
|
|
_ -> 1000.6
|
|
|
|
foo -3.6
|
|
"#
|
|
),
|
|
111.2,
|
|
f64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn or_pattern() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when 2 is
|
|
1 | 2 -> 42
|
|
_ -> 1
|
|
"#
|
|
),
|
|
42,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn apply_identity() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
identity = \a -> a
|
|
|
|
identity 5
|
|
"#
|
|
),
|
|
5,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn apply_unnamed_identity() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
wrapper = \{} ->
|
|
(\a -> a) 5
|
|
|
|
wrapper {}
|
|
"#
|
|
),
|
|
5,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn return_unnamed_fn() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
wrapper = \{} ->
|
|
alwaysFloatIdentity : Int * -> (Frac a -> Frac a)
|
|
alwaysFloatIdentity = \_ ->
|
|
(\a -> a)
|
|
|
|
(alwaysFloatIdentity 2) 1.23
|
|
|
|
wrapper {}
|
|
"#
|
|
),
|
|
1.23,
|
|
f64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn gen_when_fn() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
limitedNegate = \num ->
|
|
when num is
|
|
1 -> -1
|
|
-1 -> 1
|
|
_ -> num
|
|
|
|
limitedNegate 1
|
|
"#
|
|
),
|
|
-1,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn gen_basic_def() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
answer = 42
|
|
|
|
answer
|
|
"#
|
|
),
|
|
42,
|
|
i64
|
|
);
|
|
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
float = 1.23
|
|
|
|
float
|
|
"#
|
|
),
|
|
1.23,
|
|
f64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn gen_multiple_defs() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
answer = 42
|
|
|
|
float = 1.23
|
|
|
|
if float > 3 then answer else answer
|
|
"#
|
|
),
|
|
42,
|
|
i64
|
|
);
|
|
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
answer = 42
|
|
|
|
float = 1.23
|
|
|
|
if answer > 3 then float else float
|
|
"#
|
|
),
|
|
1.23,
|
|
f64
|
|
);
|
|
}
|
|
|
|
// These tests caught a bug in how Defs are converted to the mono IR
|
|
// but they have UnusedDef or UnusedArgument problems, and don't run any more
|
|
// #[test]
|
|
// #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
// fn gen_chained_defs() {
|
|
// assert_evals_to!(
|
|
// indoc!(
|
|
// r#"
|
|
// x = i1
|
|
// i3 = i2
|
|
// i1 = 1337
|
|
// i2 = i1
|
|
// y = 12.4
|
|
//
|
|
// i3
|
|
// "#
|
|
// ),
|
|
// 1337,
|
|
// i64
|
|
// );
|
|
// }
|
|
//
|
|
// #[test]
|
|
// #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
// fn gen_nested_defs_old() {
|
|
// assert_evals_to!(
|
|
// indoc!(
|
|
// r#"
|
|
// x = 5
|
|
//
|
|
// answer =
|
|
// i3 = i2
|
|
//
|
|
// nested =
|
|
// a = 1.0
|
|
// b = 5
|
|
//
|
|
// i1
|
|
//
|
|
// i1 = 1337
|
|
// i2 = i1
|
|
//
|
|
//
|
|
// nested
|
|
//
|
|
// # None of this should affect anything, even though names
|
|
// # overlap with the previous nested defs
|
|
// unused =
|
|
// nested = 17
|
|
//
|
|
// i1 = 84.2
|
|
//
|
|
// nested
|
|
//
|
|
// y = 12.4
|
|
//
|
|
// answer
|
|
// "#
|
|
// ),
|
|
// 1337,
|
|
// i64
|
|
// );
|
|
// }
|
|
//
|
|
// #[test]
|
|
// #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
// fn let_x_in_x() {
|
|
// assert_evals_to!(
|
|
// indoc!(
|
|
// r#"
|
|
// x = 5
|
|
//
|
|
// answer =
|
|
// 1337
|
|
//
|
|
// unused =
|
|
// nested = 17
|
|
// nested
|
|
//
|
|
// answer
|
|
// "#
|
|
// ),
|
|
// 1337,
|
|
// i64
|
|
// );
|
|
// }
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn factorial() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
factorial = \n, accum ->
|
|
when n is
|
|
0 ->
|
|
accum
|
|
|
|
_ ->
|
|
factorial (n - 1) (n * accum)
|
|
|
|
factorial 10 1
|
|
"#
|
|
),
|
|
3628800,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn peano1() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Peano : [S Peano, Z]
|
|
|
|
three : Peano
|
|
three = S (S (S Z))
|
|
|
|
when three is
|
|
Z -> 2
|
|
S _ -> 1
|
|
"#
|
|
),
|
|
1,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn peano2() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Peano : [S Peano, Z]
|
|
|
|
three : Peano
|
|
three = S (S (S Z))
|
|
|
|
when three is
|
|
S (S _) -> 1
|
|
S (_) -> 0
|
|
Z -> 0
|
|
"#
|
|
),
|
|
1,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn top_level_constant() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
float = 1.2315
|
|
|
|
main =
|
|
float + float
|
|
"#
|
|
),
|
|
1.2315 + 1.2315,
|
|
f64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn top_level_destructure() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
{a, b} = { a: 1, b: 2 }
|
|
|
|
main =
|
|
|
|
a + b
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_len_0() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
LinkedList a : [Nil, Cons a (LinkedList a)]
|
|
|
|
len : LinkedList a -> Int *
|
|
len = \list ->
|
|
when list is
|
|
Nil -> 0
|
|
Cons _ rest -> 1 + len rest
|
|
|
|
main =
|
|
nil : LinkedList F64
|
|
nil = Nil
|
|
|
|
len nil
|
|
"#
|
|
),
|
|
0,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_len_twice_0() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
LinkedList a : [Nil, Cons a (LinkedList a)]
|
|
|
|
nil : LinkedList I64
|
|
nil = Nil
|
|
|
|
length : LinkedList a -> Int *
|
|
length = \list ->
|
|
when list is
|
|
Nil -> 0
|
|
Cons _ rest -> 1 + length rest
|
|
|
|
main =
|
|
length nil + length nil
|
|
"#
|
|
),
|
|
0,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_len_1() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
LinkedList a : [Nil, Cons a (LinkedList a)]
|
|
|
|
one : LinkedList (Int *)
|
|
one = Cons 1 Nil
|
|
|
|
length : LinkedList a -> Int *
|
|
length = \list ->
|
|
when list is
|
|
Nil -> 0
|
|
Cons _ rest -> 1 + length rest
|
|
|
|
main =
|
|
length one
|
|
"#
|
|
),
|
|
1,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_len_twice_1() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
LinkedList a : [Nil, Cons a (LinkedList a)]
|
|
|
|
one : LinkedList (Int *)
|
|
one = Cons 1 Nil
|
|
|
|
length : LinkedList a -> Int *
|
|
length = \list ->
|
|
when list is
|
|
Nil -> 0
|
|
Cons _ rest -> 1 + length rest
|
|
|
|
main =
|
|
length one + length one
|
|
"#
|
|
),
|
|
2,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_len_3() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
LinkedList a : [Nil, Cons a (LinkedList a)]
|
|
|
|
three : LinkedList (Int *)
|
|
three = Cons 3 (Cons 2 (Cons 1 Nil))
|
|
|
|
length : LinkedList a -> Int *
|
|
length = \list ->
|
|
when list is
|
|
Nil -> 0
|
|
Cons _ rest -> 1 + length rest
|
|
|
|
|
|
main =
|
|
length three
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_sum_num_a() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
LinkedList a : [Nil, Cons a (LinkedList a)]
|
|
|
|
three : LinkedList (Int *)
|
|
three = Cons 3 (Cons 2 (Cons 1 Nil))
|
|
|
|
|
|
sum : LinkedList (Num a) -> Num a
|
|
sum = \list ->
|
|
when list is
|
|
Nil -> 0
|
|
Cons x rest -> x + sum rest
|
|
|
|
main =
|
|
sum three
|
|
"#
|
|
),
|
|
3 + 2 + 1,
|
|
i64
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_sum_int() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
LinkedList a : [Nil, Cons a (LinkedList a)]
|
|
|
|
zero : LinkedList (Int *)
|
|
zero = Nil
|
|
|
|
sum : LinkedList (Int a) -> Int a
|
|
sum = \list ->
|
|
when list is
|
|
Nil -> 0
|
|
Cons x rest -> x + sum rest
|
|
|
|
main =
|
|
sum zero
|
|
"#
|
|
),
|
|
0,
|
|
i64
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_map() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
LinkedList a : [Nil, Cons a (LinkedList a)]
|
|
|
|
three : LinkedList (Int *)
|
|
three = Cons 3 (Cons 2 (Cons 1 Nil))
|
|
|
|
sum : LinkedList (Num a) -> Num a
|
|
sum = \list ->
|
|
when list is
|
|
Nil -> 0
|
|
Cons x rest -> x + sum rest
|
|
|
|
map : (a -> b), LinkedList a -> LinkedList b
|
|
map = \f, list ->
|
|
when list is
|
|
Nil -> Nil
|
|
Cons x rest -> Cons (f x) (map f rest)
|
|
|
|
main =
|
|
sum (map (\_ -> 1) three)
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn when_nested_maybe() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Maybe a : [Nothing, Just a]
|
|
|
|
x : Maybe (Maybe (Int a))
|
|
x = Just (Just 41)
|
|
|
|
when x is
|
|
Just (Just v) -> v + 0x1
|
|
_ -> 0x1
|
|
"#
|
|
),
|
|
42,
|
|
i64
|
|
);
|
|
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Maybe a : [Nothing, Just a]
|
|
|
|
x : Maybe (Maybe (Int *))
|
|
x = Just Nothing
|
|
|
|
when x is
|
|
Just (Just v) -> v + 0x1
|
|
Just Nothing -> 0x2
|
|
Nothing -> 0x1
|
|
"#
|
|
),
|
|
2,
|
|
i64
|
|
);
|
|
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Maybe a : [Nothing, Just a]
|
|
|
|
x : Maybe (Maybe (Int *))
|
|
x = Nothing
|
|
|
|
when x is
|
|
Just (Just v) -> v + 0x1
|
|
Just Nothing -> 0x2
|
|
Nothing -> 0x1
|
|
"#
|
|
),
|
|
1,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn when_peano() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Peano : [S Peano, Z]
|
|
|
|
three : Peano
|
|
three = S (S (S Z))
|
|
|
|
when three is
|
|
S (S _) -> 1
|
|
S (_) -> 2
|
|
Z -> 3
|
|
"#
|
|
),
|
|
1,
|
|
i64
|
|
);
|
|
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Peano : [S Peano, Z]
|
|
|
|
three : Peano
|
|
three = S Z
|
|
|
|
when three is
|
|
S (S _) -> 1
|
|
S (_) -> 2
|
|
Z -> 3
|
|
"#
|
|
),
|
|
2,
|
|
i64
|
|
);
|
|
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Peano : [S Peano, Z]
|
|
|
|
three : Peano
|
|
three = Z
|
|
|
|
when three is
|
|
S (S _) -> 1
|
|
S (_) -> 2
|
|
Z -> 3
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[should_panic(expected = "Roc failed with message: ")]
|
|
fn overflow_frees_list() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
myList = [1,2,3]
|
|
|
|
# integer overflow; must use the list so it is defined before the overflow
|
|
# the list will then be freed in a cleanup block
|
|
n : I64
|
|
n = 9_223_372_036_854_775_807 + (Num.intCast (List.len myList))
|
|
|
|
index : Nat
|
|
index = Num.intCast n
|
|
|
|
List.get myList index
|
|
"#
|
|
),
|
|
(3, 0),
|
|
(i64, i8)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[should_panic(expected = "Roc failed with message: ")]
|
|
fn undefined_variable() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
if True then
|
|
x + z
|
|
else
|
|
y + z
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[should_panic(expected = "Roc failed with message: ")]
|
|
fn annotation_without_body() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
foo : Int *
|
|
|
|
|
|
foo
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn simple_closure() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
x = 42
|
|
|
|
f = \{} -> x
|
|
|
|
|
|
main =
|
|
f {}
|
|
"#
|
|
),
|
|
42,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn nested_closure() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
foo = \{} ->
|
|
x = 41
|
|
y = 1
|
|
f = \{} -> x + y
|
|
f
|
|
|
|
main =
|
|
g = foo {}
|
|
g {}
|
|
"#
|
|
),
|
|
42,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn closure_in_list() {
|
|
use roc_std::RocList;
|
|
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
foo = \{} ->
|
|
x = 41
|
|
|
|
f = \{} -> x
|
|
|
|
[f]
|
|
|
|
main =
|
|
items = foo {}
|
|
|
|
items
|
|
"#
|
|
),
|
|
RocList::from_slice(&[41]),
|
|
RocList<i64>
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn specialize_closure() {
|
|
use roc_std::RocList;
|
|
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
foo = \{} ->
|
|
x = 41
|
|
y = [1]
|
|
|
|
f = \{} -> x
|
|
g = \{} -> x + Num.intCast (List.len y)
|
|
|
|
[f, g]
|
|
|
|
apply = \f -> f {}
|
|
|
|
main =
|
|
items = foo {}
|
|
|
|
List.map items apply
|
|
"#
|
|
),
|
|
RocList::from_slice(&[41, 42]),
|
|
RocList<i64>
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn io_poc_effect() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Effect a := {} -> a
|
|
|
|
succeed : a -> Effect a
|
|
succeed = \x -> @Effect \{} -> x
|
|
|
|
runEffect : Effect a -> a
|
|
runEffect = \@Effect thunk -> thunk {}
|
|
|
|
foo : Effect F64
|
|
foo =
|
|
succeed 1.23
|
|
|
|
main : F64
|
|
main =
|
|
runEffect foo
|
|
|
|
"#
|
|
),
|
|
1.23,
|
|
f64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn io_poc_desugared() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
# succeed : a -> ({} -> a)
|
|
succeed = \x -> \_ -> x
|
|
|
|
foo : Str -> F64
|
|
foo =
|
|
succeed 1.23
|
|
|
|
# runEffect : ({} -> a) -> a
|
|
runEffect = \thunk -> thunk ""
|
|
|
|
main : F64
|
|
main =
|
|
runEffect foo
|
|
"#
|
|
),
|
|
1.23,
|
|
f64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm"))]
|
|
fn return_wrapped_function_pointer() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Effect a := {} -> a
|
|
|
|
foo : Effect {}
|
|
foo = @Effect \{} -> {}
|
|
|
|
main : Effect {}
|
|
main = foo
|
|
"#
|
|
),
|
|
1,
|
|
usize,
|
|
|_| 1
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm"))]
|
|
fn return_wrapped_function_pointer_b() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
|
|
foo : { x: (I64 -> Str) }
|
|
foo = { x: (\_ -> "foobar") }
|
|
|
|
main : { x: (I64 -> Str) }
|
|
main = foo
|
|
"#
|
|
),
|
|
1,
|
|
usize,
|
|
|_| 1
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm"))]
|
|
fn return_wrapped_closure() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Effect a := {} -> a
|
|
|
|
foo : Effect {}
|
|
foo =
|
|
x = 5
|
|
|
|
@Effect (\{} -> if x > 3 then {} else {})
|
|
|
|
main : Effect {}
|
|
main = foo
|
|
"#
|
|
),
|
|
1,
|
|
usize,
|
|
|_| 1
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_is_singleton() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
ConsList a : [Cons a (ConsList a), Nil]
|
|
|
|
empty : ConsList a
|
|
empty = Nil
|
|
|
|
isSingleton : ConsList a -> Bool
|
|
isSingleton = \list ->
|
|
when list is
|
|
Cons _ Nil ->
|
|
True
|
|
|
|
_ ->
|
|
False
|
|
|
|
main : Bool
|
|
main =
|
|
myList : ConsList I64
|
|
myList = empty
|
|
|
|
isSingleton myList
|
|
"#
|
|
),
|
|
false,
|
|
bool
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_is_empty_1() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
ConsList a : [Cons a (ConsList a), Nil]
|
|
|
|
empty : ConsList a
|
|
empty = Nil
|
|
|
|
isEmpty : ConsList a -> Bool
|
|
isEmpty = \list ->
|
|
when list is
|
|
Cons _ _ ->
|
|
False
|
|
|
|
Nil ->
|
|
True
|
|
|
|
main : Bool
|
|
main =
|
|
myList : ConsList (Int *)
|
|
myList = empty
|
|
|
|
isEmpty myList
|
|
"#
|
|
),
|
|
true,
|
|
bool
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_is_empty_2() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
ConsList a : [Cons a (ConsList a), Nil]
|
|
|
|
isEmpty : ConsList a -> Bool
|
|
isEmpty = \list ->
|
|
when list is
|
|
Cons _ _ ->
|
|
False
|
|
|
|
Nil ->
|
|
True
|
|
|
|
main : Bool
|
|
main =
|
|
myList : ConsList I64
|
|
myList = Cons 0x1 Nil
|
|
|
|
isEmpty myList
|
|
"#
|
|
),
|
|
false,
|
|
bool
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_singleton() {
|
|
// verifies only that valid llvm is produced
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
ConsList a : [Cons a (ConsList a), Nil]
|
|
|
|
main : ConsList I64
|
|
main = Cons 0x1 Nil
|
|
"#
|
|
),
|
|
0,
|
|
i64,
|
|
|_| 0
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn recursive_function_with_rigid() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
State a : { count : I64, x : a }
|
|
|
|
foo : State a -> Int *
|
|
foo = \state ->
|
|
if state.count == 0 then
|
|
0
|
|
else
|
|
1 + foo { count: state.count - 1, x: state.x }
|
|
|
|
main : Int *
|
|
main =
|
|
foo { count: 3, x: {} }
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn rbtree_insert() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
NodeColor : [Red, Black]
|
|
|
|
RedBlackTree k v : [Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty]
|
|
|
|
Key k : Num k
|
|
|
|
insert : Key k, v, RedBlackTree (Key k) v -> RedBlackTree (Key k) v
|
|
insert = \key, value, dict ->
|
|
when insertHelp key value dict is
|
|
Node Red k v l r ->
|
|
Node Black k v l r
|
|
|
|
x ->
|
|
x
|
|
|
|
insertHelp : (Key k), v, RedBlackTree (Key k) v -> RedBlackTree (Key k) v
|
|
insertHelp = \key, value, dict ->
|
|
when dict is
|
|
Empty ->
|
|
# New nodes are always red. If it violates the rules, it will be fixed
|
|
# when balancing.
|
|
Node Red key value Empty Empty
|
|
|
|
Node nColor nKey nValue nLeft nRight ->
|
|
when Num.compare key nKey is
|
|
LT ->
|
|
balance nColor nKey nValue (insertHelp key value nLeft) nRight
|
|
|
|
EQ ->
|
|
Node nColor nKey value nLeft nRight
|
|
|
|
GT ->
|
|
balance nColor nKey nValue nLeft (insertHelp key value nRight)
|
|
|
|
balance : NodeColor, k, v, RedBlackTree k v, RedBlackTree k v -> RedBlackTree k v
|
|
balance = \color, key, value, left, right ->
|
|
when right is
|
|
Node Red rK rV rLeft rRight ->
|
|
when left is
|
|
Node Red lK lV lLeft lRight ->
|
|
Node
|
|
Red
|
|
key
|
|
value
|
|
(Node Black lK lV lLeft lRight)
|
|
(Node Black rK rV rLeft rRight)
|
|
|
|
_ ->
|
|
Node color rK rV (Node Red key value left rLeft) rRight
|
|
|
|
_ ->
|
|
when left is
|
|
Node Red lK lV (Node Red llK llV llLeft llRight) lRight ->
|
|
Node
|
|
Red
|
|
lK
|
|
lV
|
|
(Node Black llK llV llLeft llRight)
|
|
(Node Black key value lRight right)
|
|
|
|
_ ->
|
|
Node color key value left right
|
|
|
|
show : RedBlackTree I64 {} -> Str
|
|
show = \tree ->
|
|
when tree is
|
|
Empty -> "Empty"
|
|
Node _ _ _ _ _ -> "Node"
|
|
|
|
|
|
main : Str
|
|
main =
|
|
show (insert 0 {} Empty)
|
|
"#
|
|
),
|
|
RocStr::from("Node"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(all(
|
|
any(feature = "gen-llvm", feature = "gen-wasm"),
|
|
not(feature = "gen-llvm-wasm")
|
|
))]
|
|
fn rbtree_balance_3() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
RedBlackTree k : [Node k (RedBlackTree k) (RedBlackTree k), Empty]
|
|
|
|
balance : k, RedBlackTree k -> RedBlackTree k
|
|
balance = \key, left ->
|
|
Node key left Empty
|
|
|
|
main : RedBlackTree (Int *)
|
|
main =
|
|
balance 0 Empty
|
|
"#
|
|
),
|
|
false,
|
|
usize,
|
|
|x: usize| x == 0
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[ignore]
|
|
fn rbtree_layout_issue() {
|
|
// there is a flex var in here somewhere that blows up layout creation
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
NodeColor : [Red, Black]
|
|
|
|
RedBlackTree k v : [Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty]
|
|
|
|
# balance : NodeColor, k, v, RedBlackTree k v -> RedBlackTree k v
|
|
balance = \color, key, value, right ->
|
|
when right is
|
|
Node Red _ _ rLeft rRight ->
|
|
Node color key value rLeft rRight
|
|
|
|
|
|
_ ->
|
|
Empty
|
|
|
|
show : RedBlackTree * * -> Str
|
|
show = \tree ->
|
|
when tree is
|
|
Empty -> "Empty"
|
|
Node _ _ _ _ _ -> "Node"
|
|
|
|
zero : I64
|
|
zero = 0
|
|
|
|
main : Str
|
|
main = show (balance Red zero zero Empty)
|
|
"#
|
|
),
|
|
RocStr::from("Empty"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[ignore]
|
|
fn rbtree_balance_mono_problem() {
|
|
// because of how the function is written, only `Red` is used and so in the function's
|
|
// type, the first argument is a unit and dropped. Apparently something is weird with
|
|
// constraint generation where the specialization required by `main` does not fix the
|
|
// problem. As a result, the first argument is dropped and we run into issues down the line
|
|
//
|
|
// concretely, the `rRight` symbol will not be defined
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
NodeColor : [Red, Black]
|
|
|
|
RedBlackTree k v : [Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty]
|
|
|
|
# balance : NodeColor, k, v, RedBlackTree k v, RedBlackTree k v -> RedBlackTree k v
|
|
balance = \color, key, value, left, right ->
|
|
when right is
|
|
Node Red rK rV rLeft rRight ->
|
|
when left is
|
|
Node Red lK lV lLeft lRight ->
|
|
Node
|
|
Red
|
|
key
|
|
value
|
|
(Node Black lK lV lLeft lRight)
|
|
(Node Black rK rV rLeft rRight)
|
|
|
|
_ ->
|
|
Node color rK rV (Node Red key value left rLeft) rRight
|
|
|
|
_ ->
|
|
Empty
|
|
|
|
show : RedBlackTree * * -> Str
|
|
show = \tree ->
|
|
when tree is
|
|
Empty -> "Empty"
|
|
Node _ _ _ _ _ -> "Node"
|
|
|
|
|
|
main : Str
|
|
main = show (balance Red 0 0 Empty Empty)
|
|
"#
|
|
),
|
|
RocStr::from("Empty"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn rbtree_balance_full() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
NodeColor : [Red, Black]
|
|
|
|
RedBlackTree k v : [Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty]
|
|
|
|
balance : NodeColor, k, v, RedBlackTree k v, RedBlackTree k v -> RedBlackTree k v
|
|
balance = \color, key, value, left, right ->
|
|
when right is
|
|
Node Red rK rV rLeft rRight ->
|
|
when left is
|
|
Node Red lK lV lLeft lRight ->
|
|
Node
|
|
Red
|
|
key
|
|
value
|
|
(Node Black lK lV lLeft lRight)
|
|
(Node Black rK rV rLeft rRight)
|
|
|
|
_ ->
|
|
Node color rK rV (Node Red key value left rLeft) rRight
|
|
|
|
_ ->
|
|
when left is
|
|
Node Red lK lV (Node Red llK llV llLeft llRight) lRight ->
|
|
Node
|
|
Red
|
|
lK
|
|
lV
|
|
(Node Black llK llV llLeft llRight)
|
|
(Node Black key value lRight right)
|
|
|
|
_ ->
|
|
Node color key value left right
|
|
|
|
main : RedBlackTree F64 F64
|
|
main =
|
|
balance Red 0 0 Empty Empty
|
|
"#
|
|
),
|
|
true,
|
|
usize,
|
|
|x| x != 0
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn nested_pattern_match_two_ways() {
|
|
// exposed an issue in the ordering of pattern match checks when ran with `--release` mode
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
ConsList a : [Cons a (ConsList a), Nil]
|
|
|
|
balance : ConsList (Int *) -> Int *
|
|
balance = \right ->
|
|
when right is
|
|
Cons 1 foo ->
|
|
when foo is
|
|
Cons 1 _ -> 3
|
|
_ -> 3
|
|
_ -> 3
|
|
|
|
main : Int *
|
|
main =
|
|
when balance Nil is
|
|
_ -> 3
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
ConsList a : [Cons a (ConsList a), Nil]
|
|
|
|
balance : ConsList (Int *) -> Int *
|
|
balance = \right ->
|
|
when right is
|
|
Cons 1 (Cons 1 _) -> 3
|
|
_ -> 3
|
|
|
|
main : Int *
|
|
main =
|
|
when balance Nil is
|
|
_ -> 3
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_guarded_double_pattern_match() {
|
|
// the important part here is that the first case (with the nested Cons) does not match
|
|
// TODO this also has undefined behavior
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
ConsList a : [Cons a (ConsList a), Nil]
|
|
|
|
balance : ConsList (Int *) -> Int *
|
|
balance = \right ->
|
|
when right is
|
|
Cons 1 foo ->
|
|
when foo is
|
|
Cons 1 _ -> 3
|
|
_ -> 3
|
|
_ -> 3
|
|
|
|
main : Int *
|
|
main =
|
|
when balance Nil is
|
|
_ -> 3
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn linked_list_double_pattern_match() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
ConsList a : [Cons a (ConsList a), Nil]
|
|
|
|
foo : ConsList (Int a) -> Int a
|
|
foo = \list ->
|
|
when list is
|
|
Cons _ (Cons x _) -> x
|
|
_ -> 0
|
|
|
|
main : Int *
|
|
main =
|
|
foo (Cons 1 (Cons 32 Nil))
|
|
"#
|
|
),
|
|
32,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn binary_tree_double_pattern_match() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
BTree : [Node BTree BTree, Leaf I64]
|
|
|
|
foo : BTree -> I64
|
|
foo = \btree ->
|
|
when btree is
|
|
Node (Node (Leaf x) _) _ -> x
|
|
_ -> 1
|
|
|
|
main : I64
|
|
main =
|
|
foo (Node (Node (Leaf 32) (Leaf 2)) (Leaf 3))
|
|
"#
|
|
),
|
|
32,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn unified_empty_closure_bool() {
|
|
// none of the Closure tags will have a payload
|
|
// this was not handled correctly in the past
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
foo = \{} ->
|
|
when A is
|
|
A -> (\_ -> 1.23)
|
|
B -> (\_ -> 1.23)
|
|
|
|
main : Frac *
|
|
main =
|
|
(foo {}) 0
|
|
"#
|
|
),
|
|
1.23,
|
|
f64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn unified_empty_closure_byte() {
|
|
// none of the Closure tags will have a payload
|
|
// this was not handled correctly in the past
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
foo = \{} ->
|
|
when A is
|
|
A -> (\_ -> 1.23)
|
|
B -> (\_ -> 1.23)
|
|
C -> (\_ -> 1.23)
|
|
|
|
main : Frac *
|
|
main =
|
|
(foo {}) 0
|
|
"#
|
|
),
|
|
1.23,
|
|
f64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm"))]
|
|
fn task_always_twice() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Effect a := {} -> a
|
|
|
|
effectAlways : a -> Effect a
|
|
effectAlways = \x ->
|
|
inner = \{} -> x
|
|
|
|
@Effect inner
|
|
|
|
effectAfter : Effect a, (a -> Effect b) -> Effect b
|
|
effectAfter = \(@Effect thunk), transform -> transform (thunk {})
|
|
|
|
Task a err : Effect (Result a err)
|
|
|
|
always : a -> Task a *
|
|
always = \x -> effectAlways (Ok x)
|
|
|
|
fail : err -> Task * err
|
|
fail = \x -> effectAlways (Err x)
|
|
|
|
after : Task a err, (a -> Task b err) -> Task b err
|
|
after = \task, transform ->
|
|
effectAfter task \res ->
|
|
when res is
|
|
Ok x -> transform x
|
|
Err e -> fail e
|
|
|
|
main : Task {} (Frac *)
|
|
main = after (always "foo") (\_ -> always {})
|
|
|
|
"#
|
|
),
|
|
0,
|
|
usize,
|
|
|_| 0
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm"))]
|
|
fn wildcard_rigid() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Effect a := {} -> a
|
|
|
|
Task a err : Effect (Result a err)
|
|
|
|
# this failed because of the `*`, but worked with `err`
|
|
always : a -> Task a *
|
|
always = \x ->
|
|
inner = \{} -> (Ok x)
|
|
|
|
@Effect inner
|
|
|
|
|
|
main : Task {} (Frac *)
|
|
main = always {}
|
|
"#
|
|
),
|
|
0,
|
|
usize,
|
|
|_| 0
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm"))]
|
|
fn alias_of_alias_with_type_arguments() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Effect a := a
|
|
|
|
Task a err : Effect (Result a err)
|
|
|
|
always : a -> Task a *
|
|
always = \x ->
|
|
inner = (Ok x)
|
|
|
|
@Effect inner
|
|
|
|
|
|
main : Task {} (Frac *)
|
|
main = always {}
|
|
"#
|
|
),
|
|
0,
|
|
usize,
|
|
|_| 0
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[ignore]
|
|
fn todo_bad_error_message() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Effect a := {} -> a
|
|
|
|
effectAlways : a -> Effect a
|
|
effectAlways = \x ->
|
|
inner = \{} -> x
|
|
|
|
@Effect inner
|
|
|
|
effectAfter : Effect a, (a -> Effect b) -> Effect b
|
|
effectAfter = \(@Effect thunk), transform -> transform (thunk {})
|
|
|
|
Task a err : Effect (Result a err)
|
|
|
|
always : a -> Task a (Frac *)
|
|
always = \x -> effectAlways (Ok x)
|
|
|
|
# the problem is that this restricts to `Task {} *`
|
|
fail : err -> Task {} err
|
|
fail = \x -> effectAlways (Err x)
|
|
|
|
after : Task a err, (a -> Task b err) -> Task b err
|
|
after = \task, transform ->
|
|
effectAfter task \res ->
|
|
when res is
|
|
Ok x -> transform x
|
|
# but here it must be `forall b. Task b {}`
|
|
Err e -> fail e
|
|
|
|
main : Task {} (Frac *)
|
|
main =
|
|
after (always "foo") (\_ -> always {})
|
|
"#
|
|
),
|
|
0,
|
|
i64,
|
|
|_| 0
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn hof_conditional() {
|
|
// exposed issue with the if condition being just a symbol
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
passTrue = \f -> f True
|
|
|
|
passTrue (\trueVal -> if trueVal then False else True)
|
|
"#
|
|
),
|
|
0,
|
|
u8
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[should_panic(
|
|
expected = "Roc failed with message: \"Shadowing { original_region: @55-56, shadow: @88-89 Ident"
|
|
)]
|
|
fn pattern_shadowing() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
x = 4
|
|
|
|
when 4 is
|
|
x -> x
|
|
"#
|
|
),
|
|
0,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[ignore]
|
|
#[should_panic(expected = "")]
|
|
fn unsupported_pattern_str_interp() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
{ x: 4 } = { x : 4 }
|
|
|
|
x
|
|
"#
|
|
),
|
|
0,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[ignore]
|
|
fn fingertree_basic() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Some a : [One a, Two a a, Three a a a]
|
|
|
|
Tuple a : [Pair a a, Triple a a a]
|
|
|
|
# a FingerTree implementation
|
|
Seq a : [Nil, Unit a, More (Some a) (Seq (Tuple a)) (Some a)]
|
|
|
|
# cons : a, Seq a -> Seq a
|
|
cons = \x, s ->
|
|
when s is
|
|
Nil -> Unit x
|
|
Unit y -> More (One x) Nil (One y)
|
|
More some q u ->
|
|
when some is
|
|
One y -> More (Two x y) q u
|
|
Two y z -> More (Three x y z) q u
|
|
Three y z w -> More (Two x y) (consTuple (Pair z w) q) u
|
|
|
|
consTuple : Tuple a, Seq (Tuple a) -> Seq (Tuple a)
|
|
consTuple = \a, b -> cons a b
|
|
|
|
main : Bool
|
|
main =
|
|
when cons 0x1 Nil is
|
|
Unit 1 -> True
|
|
_ -> False
|
|
"#
|
|
),
|
|
true,
|
|
bool
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn case_or_pattern() {
|
|
// the `0` branch body should only be generated once in the future
|
|
// it is currently duplicated
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
x : [Red, Green, Blue]
|
|
x = Red
|
|
|
|
when x is
|
|
Red | Green -> 0
|
|
Blue -> 1
|
|
"#
|
|
),
|
|
0,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[ignore]
|
|
fn rosetree_basic() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Tree a : [Tree a (List (Tree a))]
|
|
|
|
singleton : a -> Tree a
|
|
singleton = \x -> Tree x []
|
|
|
|
main : Bool
|
|
main =
|
|
x : Tree F64
|
|
x = singleton 3
|
|
when x is
|
|
Tree 3.0 _ -> True
|
|
_ -> False
|
|
"#
|
|
),
|
|
true,
|
|
bool
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn case_jump() {
|
|
// the decision tree will generate a jump to the `1` branch here
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
ConsList a : [Cons a (ConsList a), Nil]
|
|
|
|
x : ConsList I64
|
|
x = Nil
|
|
|
|
main =
|
|
when Pair x x is
|
|
Pair Nil _ -> 1
|
|
Pair _ Nil -> 2
|
|
Pair (Cons a _) (Cons b _) -> a + b + 3
|
|
"#
|
|
),
|
|
1,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn nullable_eval_cfold() {
|
|
// the decision tree will generate a jump to the `1` branch here
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Expr : [Var, Val I64, Add Expr Expr, Mul Expr Expr]
|
|
|
|
mkExpr : I64, I64 -> Expr
|
|
mkExpr = \n , v ->
|
|
when n is
|
|
0 -> if v == 0 then Var else Val v
|
|
_ -> Add (mkExpr (n-1) (v+1)) (mkExpr (n-1) (max (v-1) 0))
|
|
|
|
max : I64, I64 -> I64
|
|
max = \a, b -> if a > b then a else b
|
|
|
|
eval : Expr -> I64
|
|
eval = \e ->
|
|
when e is
|
|
Var -> 0
|
|
Val v -> v
|
|
Add l r -> eval l + eval r
|
|
Mul l r -> eval l * eval r
|
|
|
|
main : I64
|
|
main = eval (mkExpr 3 1)
|
|
"#
|
|
),
|
|
11,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm"))]
|
|
fn nested_switch() {
|
|
// exposed bug with passing the right symbol/layout down into switch branch generation
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Expr : [ZAdd Expr Expr, Val I64, Var I64]
|
|
|
|
eval : Expr -> I64
|
|
eval = \e ->
|
|
when e is
|
|
Var _ -> 0
|
|
Val v -> v
|
|
ZAdd l r -> eval l + eval r
|
|
|
|
constFolding : Expr -> Expr
|
|
constFolding = \e ->
|
|
when e is
|
|
ZAdd e1 e2 ->
|
|
when Pair e1 e2 is
|
|
Pair (Val a) (Val b) -> Val (a+b)
|
|
Pair (Val a) (ZAdd x (Val b)) -> ZAdd (Val (a+b)) x
|
|
Pair _ _ -> ZAdd e1 e2
|
|
|
|
|
|
_ -> e
|
|
|
|
|
|
expr : Expr
|
|
expr = ZAdd (Val 3) (ZAdd (Val 4) (Val 5))
|
|
|
|
main : I64
|
|
main = eval (constFolding expr)
|
|
"#
|
|
),
|
|
12,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn count_deriv_x() {
|
|
// exposed bug with basing the block_of_memory on a specific (smaller) tag layout
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Expr : [Ln Expr, Pow Expr Expr, Var Str]
|
|
|
|
count : Expr -> I64
|
|
count = \expr ->
|
|
when expr is
|
|
(Var _) -> 1
|
|
(Pow f g) -> count f + count g
|
|
(Ln f) -> count f
|
|
|
|
main : I64
|
|
main = count (Var "x")
|
|
"#
|
|
),
|
|
1,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn deriv_pow() {
|
|
// exposed bug with ordering of variable declarations before switch
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Expr : [Ln Expr, Pow Expr Expr, Var Str, Val I64]
|
|
|
|
count : Expr -> I64
|
|
count = \expr ->
|
|
when expr is
|
|
(Var _) -> 1
|
|
(Val n) -> n
|
|
(Pow f g) -> count f + count g
|
|
(Ln f) -> count f
|
|
|
|
pow : Expr, Expr -> Expr
|
|
pow = \a,b ->
|
|
when Pair a b is
|
|
Pair (Val _) (Val _) -> Val -1
|
|
Pair _ (Val 0) -> Val 1
|
|
Pair f (Val 1) -> f
|
|
Pair (Val 0) _ -> Val 0
|
|
Pair f g -> Pow f g
|
|
|
|
main : I64
|
|
main = count (pow (Var "x") (Var "x"))
|
|
"#
|
|
),
|
|
2,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn multiple_increment() {
|
|
// the `leaf` value will be incremented multiple times at once
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
|
|
Color : [Red, Black]
|
|
|
|
Tree a b : [Leaf, Node Color (Tree a b) a b (Tree a b)]
|
|
|
|
Map : Tree I64 Bool
|
|
|
|
main : I64
|
|
main =
|
|
leaf : Map
|
|
leaf = Leaf
|
|
|
|
m : Map
|
|
m = Node Black (Node Black leaf 10 False leaf) 11 False (Node Black leaf 12 False (Node Red leaf 13 False leaf))
|
|
|
|
when m is
|
|
Leaf -> 0
|
|
Node _ _ _ _ _ -> 1
|
|
"#
|
|
),
|
|
1,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn switch_fuse_rc_non_exhaustive() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Foo : [A I64 Foo, B I64 Foo, C I64 Foo, Empty]
|
|
|
|
sum : Foo, I64 -> I64
|
|
sum = \foo, accum ->
|
|
when foo is
|
|
A x resta -> sum resta (x + accum)
|
|
B x restb -> sum restb (x + accum)
|
|
# Empty -> accum
|
|
# C x restc -> sum restc (x + accum)
|
|
_ -> accum
|
|
|
|
main : I64
|
|
main =
|
|
A 1 (B 2 (C 3 Empty))
|
|
|> sum 0
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn switch_fuse_rc_exhaustive() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Foo : [A I64 Foo, B I64 Foo, C I64 Foo, Empty]
|
|
|
|
sum : Foo, I64 -> I64
|
|
sum = \foo, accum ->
|
|
when foo is
|
|
A x resta -> sum resta (x + accum)
|
|
B x restb -> sum restb (x + accum)
|
|
C x restc -> sum restc (x + accum)
|
|
Empty -> accum
|
|
|
|
main : I64
|
|
main =
|
|
A 1 (B 2 (C 3 Empty))
|
|
|> sum 0
|
|
"#
|
|
),
|
|
6,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn build_then_apply_closure() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main : Str
|
|
main =
|
|
x = "long string that is malloced"
|
|
|
|
(\_ -> x) {}
|
|
"#
|
|
),
|
|
RocStr::from("long string that is malloced"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn expanded_result() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
a : Result I64 Str
|
|
a = Ok 4
|
|
|
|
after = \x, f ->
|
|
when x is
|
|
Ok v -> f v
|
|
Err e -> Err e
|
|
|
|
main : I64
|
|
main =
|
|
helper = after a (\x -> Ok x)
|
|
|
|
when helper is
|
|
Ok v -> v
|
|
Err _ -> 0
|
|
|
|
"#
|
|
),
|
|
4,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn backpassing_result() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
a : Result I64 Str
|
|
a = Ok 1
|
|
|
|
f = \x -> Ok (x + 1)
|
|
g = \y -> Ok (y * 2)
|
|
|
|
main : I64
|
|
main =
|
|
helper =
|
|
x <- Result.try a
|
|
y <- Result.try (f x)
|
|
z <- Result.try (g y)
|
|
|
|
Ok z
|
|
|
|
helper
|
|
|> Result.withDefault 0
|
|
|
|
"#
|
|
),
|
|
4,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[should_panic(expected = "Shadowing { original_region: @55-56, shadow: @72-73 Ident")]
|
|
fn function_malformed_pattern() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
x = 3
|
|
|
|
(\x -> x) 42
|
|
"#
|
|
),
|
|
3,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[should_panic(expected = "Hit an erroneous type when creating a layout for")]
|
|
fn call_invalid_layout() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
f : I64 -> I64
|
|
f = \x -> x
|
|
|
|
f {}
|
|
"#
|
|
),
|
|
3,
|
|
i64,
|
|
|x| x,
|
|
true
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn increment_or_double_closure() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
|
|
apply : (a -> a), a -> a
|
|
apply = \f, x -> f x
|
|
|
|
main =
|
|
one : I64
|
|
one = 1
|
|
|
|
two : I64
|
|
two = 2
|
|
|
|
b : Bool
|
|
b = True
|
|
|
|
increment : I64 -> I64
|
|
increment = \x -> x + one
|
|
|
|
double : I64 -> I64
|
|
double = \x -> if b then x * two else x
|
|
|
|
f = (if True then increment else double)
|
|
|
|
apply f 42
|
|
"#
|
|
),
|
|
43,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn module_thunk_is_function() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main = helper "foo" "bar"
|
|
helper = Str.concat
|
|
"#
|
|
),
|
|
RocStr::from("foobar"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn pass_through_unresolved_type_variable() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main : Str
|
|
main =
|
|
(accept Bool.isEq) "B"
|
|
|
|
|
|
accept : * -> (b -> b)
|
|
accept = \_ ->
|
|
\input -> input
|
|
"#
|
|
),
|
|
RocStr::from("B"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn pattern_match_empty_record() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main : I64
|
|
main =
|
|
when {} is
|
|
{} -> 0
|
|
|
|
"#
|
|
),
|
|
0,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn pattern_match_unit_tag() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
unit : [Unit]
|
|
unit = Unit
|
|
|
|
main : I64
|
|
main =
|
|
when unit is
|
|
Unit -> 0
|
|
|
|
"#
|
|
),
|
|
0,
|
|
i64
|
|
);
|
|
}
|
|
|
|
// see for why this is disabled on wasm32 https://github.com/rtfeldman/roc/issues/1687
|
|
#[cfg(not(feature = "gen-llvm-wasm"))]
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn mirror_llvm_alignment_padding() {
|
|
// see https://github.com/rtfeldman/roc/issues/1569
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main : Str
|
|
main =
|
|
p1 = {name : "test1", test: 1 == 1 }
|
|
|
|
List.map [p1, p1] (\{ test } -> if test then "pass" else "fail")
|
|
|> Str.joinWith "\n"
|
|
|
|
"#
|
|
),
|
|
RocStr::from("pass\npass"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn lambda_set_bool() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
p1 = (\u -> u == 97)
|
|
p2 = (\u -> u == 98)
|
|
|
|
main : I64
|
|
main =
|
|
oneOfResult = List.map [p1, p2] (\p -> p 42)
|
|
|
|
when oneOfResult is
|
|
_ -> 32
|
|
|
|
"#
|
|
),
|
|
32,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn lambda_set_byte() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
p1 = (\u -> u == 97)
|
|
p2 = (\u -> u == 98)
|
|
p3 = (\u -> u == 99)
|
|
|
|
main : I64
|
|
main =
|
|
oneOfResult = List.map [p1, p2, p3] (\p -> p 42)
|
|
|
|
when oneOfResult is
|
|
_ -> 32
|
|
|
|
"#
|
|
),
|
|
32,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn lambda_set_struct_byte() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
|
|
main : I64
|
|
main =
|
|
r : [Red, Green, Blue]
|
|
r = Red
|
|
|
|
p1 = (\u -> r == u)
|
|
foobarbaz = (\p -> p Green)
|
|
oneOfResult = List.map [p1, p1] foobarbaz
|
|
|
|
when oneOfResult is
|
|
_ -> 32
|
|
|
|
"#
|
|
),
|
|
32,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn lambda_set_enum_byte_byte() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
|
|
main : I64
|
|
main =
|
|
r : [Red, Green, Blue]
|
|
r = Red
|
|
|
|
g : [Red, Green, Blue]
|
|
g = Green
|
|
|
|
p1 = (\u -> r == u)
|
|
p2 = (\u -> g == u)
|
|
oneOfResult = List.map [p1, p2] (\p -> p Green)
|
|
|
|
when oneOfResult is
|
|
_ -> 32
|
|
|
|
"#
|
|
),
|
|
32,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn list_walk_until() {
|
|
// see https://github.com/rtfeldman/roc/issues/1576
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
|
|
satisfyA : {} -> List {}
|
|
satisfyA = \_ -> []
|
|
|
|
oneOfResult =
|
|
List.walkUntil [satisfyA] [] \_, _ -> Break []
|
|
|
|
main =
|
|
when oneOfResult is
|
|
_ -> 32
|
|
"#
|
|
),
|
|
32,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn int_literal_not_specialized_with_annotation() {
|
|
// see https://github.com/rtfeldman/roc/issues/1600
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main =
|
|
satisfy : (U8 -> Str) -> Str
|
|
satisfy = \_ -> "foo"
|
|
|
|
myEq : a, a -> Str
|
|
myEq = \_, _ -> "bar"
|
|
|
|
p1 : Num * -> Str
|
|
p1 = (\u -> myEq u 64)
|
|
|
|
when satisfy p1 is
|
|
_ -> 32
|
|
"#
|
|
),
|
|
32,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn int_literal_not_specialized_no_annotation() {
|
|
// see https://github.com/rtfeldman/roc/issues/1600
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main =
|
|
satisfy : (U8 -> Str) -> Str
|
|
satisfy = \_ -> "foo"
|
|
|
|
myEq : a, a -> Str
|
|
myEq = \_, _ -> "bar"
|
|
|
|
p1 = (\u -> myEq u 64)
|
|
|
|
when satisfy p1 is
|
|
_ -> 32
|
|
"#
|
|
),
|
|
32,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn unresolved_tvar_when_capture_is_unused() {
|
|
// see https://github.com/rtfeldman/roc/issues/1585
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main : I64
|
|
main =
|
|
r : Bool
|
|
r = False
|
|
|
|
p1 = (\_ -> r == (1 == 1))
|
|
oneOfResult = List.map [p1] (\p -> p Green)
|
|
|
|
when oneOfResult is
|
|
_ -> 32
|
|
|
|
"#
|
|
),
|
|
32,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[should_panic(expected = "Roc failed with message: ")]
|
|
fn value_not_exposed_hits_panic() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main : I64
|
|
main =
|
|
Str.toInt 32
|
|
"#
|
|
),
|
|
32,
|
|
i64
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn mix_function_and_closure() {
|
|
// see https://github.com/rtfeldman/roc/pull/1706
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
# foo does not capture any variables
|
|
# but through unification will get a lambda set that does store information
|
|
# we must handle that correctly
|
|
foo = \x -> x
|
|
|
|
bar = \y -> \_ -> y
|
|
|
|
main : Str
|
|
main =
|
|
(if 1 == 1 then foo else (bar "nope nope nope")) "hello world"
|
|
"#
|
|
),
|
|
RocStr::from("hello world"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn mix_function_and_closure_level_of_indirection() {
|
|
// see https://github.com/rtfeldman/roc/pull/1706
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
foo = \x -> x
|
|
|
|
bar = \y -> \_ -> y
|
|
|
|
f = (if 1 == 1 then foo else (bar "nope nope nope"))
|
|
|
|
main : Str
|
|
main =
|
|
f "hello world"
|
|
"#
|
|
),
|
|
RocStr::from("hello world"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[cfg_attr(debug_assertions, ignore)] // this test stack-overflows the compiler in debug mode
|
|
fn do_pass_bool_byte_closure_layout() {
|
|
// see https://github.com/rtfeldman/roc/pull/1706
|
|
// the distinction is actually important, dropping that info means some functions just get
|
|
// skipped
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
## PARSER
|
|
|
|
Parser a : List U8 -> List [Pair a (List U8)]
|
|
|
|
|
|
## ANY
|
|
|
|
# If successful, the any parser consumes one character
|
|
|
|
any: Parser U8
|
|
any = \inp ->
|
|
when List.first inp is
|
|
Ok u -> [Pair u (List.drop inp 1)]
|
|
_ -> []
|
|
|
|
|
|
|
|
## SATISFY
|
|
|
|
satisfy : (U8 -> Bool) -> Parser U8
|
|
satisfy = \predicate ->
|
|
\input ->
|
|
walker = \accum, (Pair u rest) ->
|
|
if predicate u then
|
|
Break [Pair u rest]
|
|
|
|
else
|
|
Break accum
|
|
|
|
List.walkUntil (any input) [] walker
|
|
|
|
|
|
|
|
oneOf : List (Parser a) -> Parser a
|
|
oneOf = \parserList ->
|
|
\input ->
|
|
walker = \accum, p ->
|
|
output = p input
|
|
if List.len output == 1 then
|
|
Break output
|
|
|
|
else
|
|
Continue accum
|
|
|
|
List.walkUntil parserList [] walker
|
|
|
|
|
|
satisfyA = satisfy (\u -> u == 97) # recognize 97
|
|
satisfyB = satisfy (\u -> u == 98) # recognize 98
|
|
|
|
test1 = if List.len ((oneOf [satisfyA, satisfyB]) [97, 98, 99, 100] ) == 1 then "PASS" else "FAIL"
|
|
test2 = if List.len ((oneOf [satisfyA, satisfyB]) [98, 99, 100, 97] ) == 1 then "PASS" else "FAIL"
|
|
test3 = if List.len ((oneOf [satisfyB , satisfyA]) [98, 99, 100, 97] ) == 1 then "PASS" else "FAIL"
|
|
test4 = if List.len ((oneOf [satisfyA, satisfyB]) [99, 100, 101] ) == 0 then "PASS" else "FAIL"
|
|
|
|
|
|
main : Str
|
|
main = [test1, test2, test3, test4] |> Str.joinWith ", "
|
|
"#
|
|
),
|
|
RocStr::from("PASS, PASS, PASS, PASS"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn nested_rigid_list() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
foo : List a -> List a
|
|
foo = \list ->
|
|
p2 : List a
|
|
p2 = list
|
|
|
|
p2
|
|
|
|
main =
|
|
when foo [] is
|
|
_ -> "hello world"
|
|
"#
|
|
),
|
|
RocStr::from("hello world"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
|
fn nested_rigid_alias() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
Identity a := a
|
|
|
|
foo : Identity a -> Identity a
|
|
foo = \list ->
|
|
p2 : Identity a
|
|
p2 = list
|
|
|
|
p2
|
|
|
|
main =
|
|
when foo (@Identity "foo") is
|
|
_ -> "hello world"
|
|
"#
|
|
),
|
|
RocStr::from("hello world"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
|
fn nested_rigid_tag_union() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
foo : [Identity a] -> [Identity a]
|
|
foo = \list ->
|
|
p2 : [Identity a]
|
|
p2 = list
|
|
|
|
p2
|
|
|
|
main =
|
|
when foo (Identity "foo") is
|
|
_ -> "hello world"
|
|
"#
|
|
),
|
|
RocStr::from("hello world"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn call_that_needs_closure_parameter() {
|
|
// here both p2 is lifted to the top-level, which means that `list` must be
|
|
// passed to it from `manyAux`.
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Step state a : [Loop state, Done a]
|
|
|
|
manyAux : List a -> [Pair (Step (List a) (List a))]
|
|
manyAux = \list ->
|
|
p2 = \_ -> Pair (Done list)
|
|
|
|
p2 "foo"
|
|
|
|
manyAuxTest = (manyAux []) == Pair (Loop [97])
|
|
|
|
runTest = \t -> if t then "PASS" else "FAIL"
|
|
|
|
runTest manyAuxTest
|
|
"#
|
|
),
|
|
RocStr::from("FAIL"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn alias_defined_out_of_order() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main : Foo
|
|
main = "foo"
|
|
|
|
Foo : Bar
|
|
Bar : Str
|
|
|
|
"#
|
|
),
|
|
RocStr::from("foo"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn recursively_build_effect() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
greeting =
|
|
hi = "Hello"
|
|
name = "World"
|
|
|
|
"\(hi), \(name)!"
|
|
|
|
main =
|
|
when nestHelp 4 is
|
|
_ -> greeting
|
|
|
|
nestHelp : I64 -> XEffect {}
|
|
nestHelp = \m ->
|
|
when m is
|
|
0 ->
|
|
always {}
|
|
|
|
_ ->
|
|
always {} |> after \_ -> nestHelp (m - 1)
|
|
|
|
|
|
XEffect a := {} -> a
|
|
|
|
always : a -> XEffect a
|
|
always = \x -> @XEffect (\{} -> x)
|
|
|
|
after : XEffect a, (a -> XEffect b) -> XEffect b
|
|
after = \(@XEffect e), toB ->
|
|
@XEffect \{} ->
|
|
when toB (e {}) is
|
|
@XEffect e2 ->
|
|
e2 {}
|
|
"#
|
|
),
|
|
RocStr::from("Hello, World!"),
|
|
RocStr
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "TODO; currently generates bad code because `a` isn't specialized inside the closure."]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn polymophic_expression_captured_inside_closure() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
asU8 : U8 -> U8
|
|
asU8 = \_ -> 30
|
|
|
|
main =
|
|
a = 15
|
|
f = \{} ->
|
|
asU8 a
|
|
|
|
f {}
|
|
"#
|
|
),
|
|
30,
|
|
u8
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn issue_2322() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
double = \x -> x * 2
|
|
doubleBind = \x -> (\_ -> double x)
|
|
doubleThree = doubleBind 3
|
|
doubleThree {}
|
|
"#
|
|
),
|
|
6,
|
|
i64
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn box_and_unbox_string() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Str.concat "Leverage " "agile frameworks to provide a robust synopsis for high level overviews"
|
|
|> Box.box
|
|
|> Box.unbox
|
|
"#
|
|
),
|
|
RocStr::from(
|
|
"Leverage agile frameworks to provide a robust synopsis for high level overviews"
|
|
),
|
|
RocStr
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn box_and_unbox_num() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Box.unbox (Box.box (123u8))
|
|
"#
|
|
),
|
|
123,
|
|
u8
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn box_and_unbox_record() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Box.unbox (Box.box { a: 15u8, b: 27u8 })
|
|
"#
|
|
),
|
|
(15, 27),
|
|
(u8, u8)
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn box_and_unbox_tag_union() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
v : [A U8, B U8] # usually stack allocated
|
|
v = B 27u8
|
|
|
|
Box.unbox (Box.box v)
|
|
"#
|
|
),
|
|
(27, 1),
|
|
(u8, u8)
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn closure_called_in_its_defining_scope() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main : Str
|
|
main =
|
|
g : Str
|
|
g = "hello world"
|
|
|
|
getG : {} -> Str
|
|
getG = \{} -> g
|
|
|
|
getG {}
|
|
"#
|
|
),
|
|
RocStr::from("hello world"),
|
|
RocStr
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn issue_2894() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [main] to "./platform"
|
|
|
|
main : U32
|
|
main =
|
|
g : { x : U32 }
|
|
g = { x: 1u32 }
|
|
|
|
getG : {} -> { x : U32 }
|
|
getG = \{} -> g
|
|
|
|
h : {} -> U32
|
|
h = \{} -> (getG {}).x
|
|
|
|
h {}
|
|
"#
|
|
),
|
|
1u32,
|
|
u32
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn polymorphic_def_used_in_closure() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
a : I64 -> _
|
|
a = \g ->
|
|
f = { r: g, h: 32 }
|
|
|
|
h1 : U64
|
|
h1 = (\{} -> f.h) {}
|
|
h1
|
|
a 1
|
|
"#
|
|
),
|
|
32,
|
|
u64
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn polymorphic_lambda_set_usage() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
id1 = \x -> x
|
|
id2 = \y -> y
|
|
id = if True then id1 else id2
|
|
|
|
id 9u8
|
|
"#
|
|
),
|
|
9,
|
|
u8
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn polymorphic_lambda_set_multiple_specializations() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
id1 = \x -> x
|
|
id2 = \y -> y
|
|
id = if True then id1 else id2
|
|
|
|
(id 9u8) + Num.toU8 (id 16u16)
|
|
"#
|
|
),
|
|
25,
|
|
u8
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm"))]
|
|
fn list_map2_conslist() {
|
|
// this had an RC problem, https://github.com/rtfeldman/roc/issues/2968
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
ConsList a : [Nil, Cons a (ConsList a)]
|
|
|
|
x : List (ConsList Str)
|
|
x = List.map2 [] [Nil] Cons
|
|
|
|
when List.first x is
|
|
_ -> ""
|
|
"#
|
|
),
|
|
RocStr::default(),
|
|
RocStr
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
|
fn mutual_recursion_top_level_defs() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
app "test" provides [ main ] to "./platform"
|
|
|
|
isEven = \n ->
|
|
when n is
|
|
0 -> True
|
|
1 -> False
|
|
_ -> isOdd (n - 1)
|
|
|
|
isOdd = \n ->
|
|
when n is
|
|
0 -> False
|
|
1 -> True
|
|
_ -> isEven (n - 1)
|
|
|
|
main = isOdd 11
|
|
"#
|
|
),
|
|
true,
|
|
bool
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn polymorphic_lambda_captures_polymorphic_value() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
x = 2
|
|
|
|
f1 = \_ -> x
|
|
|
|
f = if True then f1 else f1
|
|
f {}
|
|
"#
|
|
),
|
|
2,
|
|
u64
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn lambda_capture_niche_u64_vs_u8_capture() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
capture : _ -> ({} -> Str)
|
|
capture = \val ->
|
|
\{} ->
|
|
Num.toStr val
|
|
|
|
x : [True, False]
|
|
x = True
|
|
|
|
fun =
|
|
when x is
|
|
True -> capture 123u64
|
|
False -> capture 18u8
|
|
|
|
fun {}
|
|
"#
|
|
),
|
|
RocStr::from("123"),
|
|
RocStr
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn lambda_capture_niches_with_other_lambda_capture() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
capture : _ -> ({} -> Str)
|
|
capture = \val ->
|
|
\{} ->
|
|
Num.toStr val
|
|
|
|
capture2 = \val -> \{} -> val
|
|
|
|
f = \x ->
|
|
g =
|
|
when x is
|
|
A -> capture 11u8
|
|
B -> capture2 "lisa"
|
|
C -> capture 187128u64
|
|
g {}
|
|
|
|
{a: f A, b: f B, c: f C}
|
|
"#
|
|
),
|
|
(
|
|
RocStr::from("11"),
|
|
RocStr::from("lisa"),
|
|
RocStr::from("187128")
|
|
),
|
|
(RocStr, RocStr, RocStr)
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn lambda_capture_niches_with_non_capturing_function() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
capture : _ -> ({} -> Str)
|
|
capture = \val ->
|
|
\{} ->
|
|
Num.toStr val
|
|
|
|
triv = \{} -> "triv"
|
|
|
|
f = \x ->
|
|
g =
|
|
when x is
|
|
A -> capture 11u8
|
|
B -> triv
|
|
C -> capture 187128u64
|
|
g {}
|
|
|
|
{a: f A, b: f B, c: f C}
|
|
"#
|
|
),
|
|
(
|
|
RocStr::from("11"),
|
|
RocStr::from("triv"),
|
|
RocStr::from("187128")
|
|
),
|
|
(RocStr, RocStr, RocStr)
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn lambda_capture_niches_have_captured_function_in_closure() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
Lazy a : {} -> a
|
|
|
|
after : Lazy a, (a -> Lazy b) -> Lazy b
|
|
after = \effect, map ->
|
|
thunk = \{} ->
|
|
when map (effect {}) is
|
|
b -> b {}
|
|
thunk
|
|
|
|
f = \_ -> \_ -> "fun f"
|
|
g = \{ s1 } -> \_ -> s1
|
|
|
|
fun = \x ->
|
|
h =
|
|
when x is
|
|
True -> after (\{} -> "") f
|
|
False -> after (\{} -> {s1: "s1"}) g
|
|
h {}
|
|
|
|
{a: fun False, b: fun True}
|
|
"#
|
|
),
|
|
(RocStr::from("s1"), RocStr::from("fun f")),
|
|
(RocStr, RocStr)
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn recursive_call_capturing_function() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
a = \b ->
|
|
c = \d ->
|
|
if d == 7 then d else c (d + b)
|
|
c 1
|
|
|
|
a 6
|
|
"#
|
|
),
|
|
7,
|
|
i64
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn shared_pattern_variable_in_when_branches() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
f = \t ->
|
|
when t is
|
|
A x | B x -> x
|
|
|
|
{a: f (A 15u8), b: (B 31u8)}
|
|
"#
|
|
),
|
|
(15u8, 31u8),
|
|
(u8, u8)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm"))]
|
|
fn symbol_not_bound_in_all_patterns_runs_when_no_bound_symbol_used() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
f = \t -> when t is
|
|
A x | B y -> 31u8
|
|
|
|
{a: f (A 15u8), b: f (B 15u8)}
|
|
"#
|
|
),
|
|
31u8,
|
|
u8,
|
|
|x| x,
|
|
true // allow errors
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
fn symbol_not_bound_in_all_patterns_runs_when_bound_pattern_reached() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when A 15u8 is
|
|
A x | B y -> x
|
|
"#
|
|
),
|
|
15u8,
|
|
u8,
|
|
|x| x,
|
|
true // allow errors
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
|
#[should_panic(
|
|
expected = r#"Roc failed with message: "Hit a branch pattern that does not bind all symbols its body needs"#
|
|
)]
|
|
fn runtime_error_when_degenerate_pattern_reached() {
|
|
assert_evals_to!(
|
|
indoc!(
|
|
r#"
|
|
when B 15u8 is
|
|
A x | B y -> x + 5u8
|
|
"#
|
|
),
|
|
15u8,
|
|
u8,
|
|
|x| x,
|
|
true // allow errors
|
|
);
|
|
}
|