diff --git a/compiler/gen/tests/gen_list.rs b/compiler/gen/tests/gen_list.rs new file mode 100644 index 0000000000..61eec1a9fa --- /dev/null +++ b/compiler/gen/tests/gen_list.rs @@ -0,0 +1,383 @@ +#[macro_use] +extern crate pretty_assertions; +#[macro_use] +extern crate indoc; + +extern crate bumpalo; +extern crate inkwell; +extern crate libc; +extern crate roc_gen; + +#[macro_use] +mod helpers; + +#[cfg(test)] +mod gen_builtins { + use crate::helpers::{can_expr, infer_expr, uniq_expr, CanExprOut}; + use bumpalo::Bump; + use inkwell::context::Context; + use inkwell::execution_engine::JitFunction; + use inkwell::passes::PassManager; + use inkwell::types::BasicType; + use inkwell::OptimizationLevel; + use roc_collections::all::ImMap; + use roc_gen::llvm::build::{build_proc, build_proc_header}; + use roc_gen::llvm::convert::basic_type_from_layout; + use roc_mono::expr::{Expr, Procs}; + use roc_mono::layout::Layout; + use roc_types::subs::Subs; + + #[test] + fn empty_list_literal() { + assert_evals_to!("[]", &[], &'static [i64]); + } + + #[test] + fn int_list_literal() { + assert_evals_to!("[ 12, 9, 6, 3 ]", &[12, 9, 6, 3], &'static [i64]); + } + + // #[test] + // fn list_push() { + // assert_evals_to!("List.push [] 1", &[1], &'static [i64]); + // } + + #[test] + fn list_single() { + assert_evals_to!("List.single 1", &[1], &'static [i64]); + assert_evals_to!("List.single 5.6", &[5.6], &'static [f64]); + } + + #[test] + fn empty_list_len() { + assert_evals_to!("List.len []", 0, usize); + } + + #[test] + fn basic_int_list_len() { + assert_evals_to!("List.len [ 12, 9, 6, 3 ]", 4, usize); + } + + #[test] + fn loaded_int_list_len() { + assert_evals_to!( + indoc!( + r#" + nums = [ 2, 4, 6 ] + + List.len nums + "# + ), + 3, + usize + ); + } + + #[test] + fn fn_int_list_len() { + assert_evals_to!( + indoc!( + r#" + getLen = \list -> List.len list + + nums = [ 2, 4, 6, 8 ] + + getLen nums + "# + ), + 4, + usize + ); + } + + #[test] + fn int_list_is_empty() { + assert_evals_to!("List.isEmpty [ 12, 9, 6, 3 ]", false, bool); + } + + #[test] + fn empty_list_is_empty() { + assert_evals_to!("List.isEmpty []", true, bool); + } + + #[test] + fn first_int_list() { + assert_evals_to!( + indoc!( + r#" + when List.first [ 12, 9, 6, 3 ] is + Ok val -> val + Err _ -> -1 + "# + ), + 12, + i64 + ); + } + + #[test] + fn first_wildcard_empty_list() { + assert_evals_to!( + indoc!( + r#" + when List.first [] is + Ok _ -> 5 + Err _ -> -1 + "# + ), + -1, + i64 + ); + } + + #[test] + fn first_empty_list() { + assert_evals_to!( + indoc!( + r#" + when List.first [] is + Ok val -> val + Err _ -> -1 + "# + ), + -1, + i64 + ); + } + + #[test] + fn get_empty_list() { + assert_evals_to!( + indoc!( + r#" + when List.get [] 0 is + Ok val -> val + Err _ -> -1 + "# + ), + -1, + i64 + ); + } + + #[test] + fn get_wildcard_empty_list() { + assert_evals_to!( + indoc!( + r#" + when List.get [] 0 is + Ok _ -> 5 + Err _ -> -1 + "# + ), + -1, + i64 + ); + } + + #[test] + fn get_int_list_ok() { + assert_evals_to!( + indoc!( + r#" + when List.get [ 12, 9, 6 ] 1 is + Ok val -> val + Err _ -> -1 + "# + ), + 9, + i64 + ); + } + + #[test] + fn get_int_list_oob() { + assert_evals_to!( + indoc!( + r#" + when List.get [ 12, 9, 6 ] 1000 is + Ok val -> val + Err _ -> -1 + "# + ), + -1, + i64 + ); + } + + #[test] + fn get_set_unique_int_list() { + assert_evals_to!( + indoc!( + r#" + when List.get (List.set [ 12, 9, 7, 3 ] 1 42) 1 is + Ok val -> val + Err _ -> -1 + "# + ), + 42, + i64 + ); + } + + #[test] + fn set_unique_int_list() { + assert_evals_to!( + "List.set [ 12, 9, 7, 1, 5 ] 2 33", + &[12, 9, 33, 1, 5], + &'static [i64] + ); + } + + #[test] + fn set_unique_list_oob() { + assert_evals_to!( + "List.set [ 3, 17, 4.1 ] 1337 9.25", + &[3.0, 17.0, 4.1], + &'static [f64] + ); + } + + #[test] + fn set_shared_int_list() { + assert_evals_to!( + indoc!( + r#" + shared = [ 2.1, 4.3 ] + + # This should not mutate the original + x = + when List.get (List.set shared 1 7.7) 1 is + Ok num -> num + Err _ -> 0 + + y = + when List.get shared 1 is + Ok num -> num + Err _ -> 0 + + { x, y } + "# + ), + (7.7, 4.3), + (f64, f64) + ); + } + + #[test] + fn set_shared_list_oob() { + assert_evals_to!( + indoc!( + r#" + shared = [ 2, 4 ] + + # This List.set is out of bounds, and should have no effect + x = + when List.get (List.set shared 422 0) 1 is + Ok num -> num + Err _ -> 0 + + y = + when List.get shared 1 is + Ok num -> num + Err _ -> 0 + + { x, y } + "# + ), + (4, 4), + (i64, i64) + ); + } + + #[test] + fn get_unique_int_list() { + assert_evals_to!( + indoc!( + r#" + unique = [ 2, 4 ] + + when List.get unique 1 is + Ok num -> num + Err _ -> -1 + "# + ), + 4, + i64 + ); + } + + #[test] + fn gen_quicksort() { + if true { + todo!("fix gen_quicksort stack overflow (note: TCO test passes, check to see if there's a stack overflow *before* the code begins to execute"); + } + + assert_evals_to!( + indoc!( + r#" + quicksort : List (Num a) -> List (Num a) + quicksort = \list -> + quicksortHelp list 0 (List.len list - 1) + + + quicksortHelp : List (Num a), Int, Int -> List (Num a) + quicksortHelp = \list, low, high -> + if low < high then + when partition low high list is + Pair partitionIndex partitioned -> + partitioned + |> quicksortHelp low (partitionIndex - 1) + |> quicksortHelp (partitionIndex + 1) high + else + list + + + swap : Int, Int, List a -> List a + swap = \i, j, list -> + when Pair (List.get list i) (List.get list j) is + Pair (Ok atI) (Ok atJ) -> + list + |> List.set i atJ + |> List.set j atI + + _ -> + [] + + partition : Int, Int, List (Num a) -> [ Pair Int (List (Num a)) ] + partition = \low, high, initialList -> + when List.get initialList high is + Ok pivot -> + when partitionHelp (low - 1) low initialList high pivot is + Pair newI newList -> + Pair (newI + 1) (swap (newI + 1) high newList) + + Err _ -> + Pair (low - 1) initialList + + + partitionHelp : Int, Int, List (Num a), Int, Int -> [ Pair Int (List (Num a)) ] + partitionHelp = \i, j, list, high, pivot -> + if j < high then + when List.get list j is + Ok value -> + if value <= pivot then + partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot + else + partitionHelp i (j + 1) list high pivot + + Err _ -> + Pair i list + else + Pair i list + + + + quicksort [ 7, 4, 21, 19 ] + "# + ), + &[4, 7, 19, 21], + &'static [i64] + ); + } +} diff --git a/compiler/gen/tests/gen_builtins.rs b/compiler/gen/tests/gen_num.rs similarity index 53% rename from compiler/gen/tests/gen_builtins.rs rename to compiler/gen/tests/gen_num.rs index a9b15d14ce..14130f8290 100644 --- a/compiler/gen/tests/gen_builtins.rs +++ b/compiler/gen/tests/gen_num.rs @@ -29,17 +29,18 @@ mod gen_builtins { #[test] fn f64_sqrt() { - assert_evals_to!( - indoc!( - r#" - when Num.sqrt 144 is - Ok val -> val - Err _ -> -1 - "# - ), - 12.0, - f64 - ); + todo!("if I change Num.sqrt 1000 to Num.sqrt 144 I get a BadPattern error?!"); + // assert_evals_to!( + // indoc!( + // r#" + // when Num.sqrt 100 is + // Ok val -> val + // Err _ -> -1 + // "# + // ), + // 12.0, + // f64 + // ); } #[test] @@ -59,16 +60,6 @@ mod gen_builtins { assert_evals_to!("Num.abs 7", 7, i64); } - #[test] - fn empty_list_literal() { - assert_evals_to!("[]", &[], &'static [i64]); - } - - #[test] - fn int_list_literal() { - assert_evals_to!("[ 12, 9, 6, 3 ]", &[12, 9, 6, 3], &'static [i64]); - } - #[test] fn gen_if_fn() { assert_evals_to!( @@ -118,15 +109,18 @@ mod gen_builtins { #[test] fn gen_div_f64() { - assert_evals_to!( - indoc!( - r#" - 48 / 2 - "# - ), - 24.0, - f64 - ); + todo!("if I change 1000 / 10 to 48 / 2 I get a BadPattern error?!"); + // assert_evals_to!( + // indoc!( + // r#" + // when 1000 / 10 is + // Ok val -> val + // Err _ -> -1 + // "# + // ), + // 24.0, + // f64 + // ); } #[test] @@ -421,10 +415,10 @@ mod gen_builtins { assert_evals_to!( indoc!( r#" - 48 / 2 + 3 + 3 - 48 * 2.0 "# ), - 27.0, + -93.0, f64 ); } @@ -455,6 +449,7 @@ mod gen_builtins { i64 ); } + #[test] fn tail_call_elimination() { assert_evals_to!( @@ -472,6 +467,7 @@ mod gen_builtins { i64 ); } + #[test] fn int_negate() { assert_evals_to!("Num.neg 123", -123, i64); @@ -493,276 +489,6 @@ mod gen_builtins { ); } - // #[test] - // fn list_push() { - // assert_evals_to!("List.push [] 1", &[1], &'static [i64]); - // } - - #[test] - fn list_single() { - assert_evals_to!("List.single 1", &[1], &'static [i64]); - assert_evals_to!("List.single 5.6", &[5.6], &'static [f64]); - } - - #[test] - fn empty_list_len() { - assert_evals_to!("List.len []", 0, usize); - } - - #[test] - fn basic_int_list_len() { - assert_evals_to!("List.len [ 12, 9, 6, 3 ]", 4, usize); - } - - #[test] - fn loaded_int_list_len() { - assert_evals_to!( - indoc!( - r#" - nums = [ 2, 4, 6 ] - - List.len nums - "# - ), - 3, - usize - ); - } - - #[test] - fn fn_int_list_len() { - assert_evals_to!( - indoc!( - r#" - getLen = \list -> List.len list - - nums = [ 2, 4, 6, 8 ] - - getLen nums - "# - ), - 4, - usize - ); - } - - #[test] - fn int_list_is_empty() { - assert_evals_to!("List.isEmpty [ 12, 9, 6, 3 ]", false, bool); - } - - #[test] - fn empty_list_is_empty() { - assert_evals_to!("List.isEmpty []", true, bool); - } - - #[test] - fn first_int_list() { - assert_evals_to!( - indoc!( - r#" - when List.first [ 12, 9, 6, 3 ] is - Ok val -> val - Err _ -> -1 - "# - ), - 12, - i64 - ); - } - - #[test] - fn first_wildcard_empty_list() { - assert_evals_to!( - indoc!( - r#" - when List.first [] is - Ok _ -> 5 - Err _ -> -1 - "# - ), - -1, - i64 - ); - } - - #[test] - fn first_empty_list() { - assert_evals_to!( - indoc!( - r#" - when List.first [] is - Ok val -> val - Err _ -> -1 - "# - ), - -1, - i64 - ); - } - - #[test] - fn get_empty_list() { - assert_evals_to!( - indoc!( - r#" - when List.get [] 0 is - Ok val -> val - Err _ -> -1 - "# - ), - -1, - i64 - ); - } - - #[test] - fn get_wildcard_empty_list() { - assert_evals_to!( - indoc!( - r#" - when List.get [] 0 is - Ok _ -> 5 - Err _ -> -1 - "# - ), - -1, - i64 - ); - } - - #[test] - fn get_int_list_ok() { - assert_evals_to!( - indoc!( - r#" - when List.get [ 12, 9, 6 ] 1 is - Ok val -> val - Err _ -> -1 - "# - ), - 9, - i64 - ); - } - - #[test] - fn get_int_list_oob() { - assert_evals_to!( - indoc!( - r#" - when List.get [ 12, 9, 6 ] 1000 is - Ok val -> val - Err _ -> -1 - "# - ), - -1, - i64 - ); - } - - #[test] - fn get_set_unique_int_list() { - assert_evals_to!( - indoc!( - r#" - when List.get (List.set [ 12, 9, 7, 3 ] 1 42) 1 is - Ok val -> val - Err _ -> -1 - "# - ), - 42, - i64 - ); - } - - #[test] - fn set_unique_int_list() { - assert_evals_to!( - "List.set [ 12, 9, 7, 1, 5 ] 2 33", - &[12, 9, 33, 1, 5], - &'static [i64] - ); - } - - #[test] - fn set_unique_list_oob() { - assert_evals_to!( - "List.set [ 3, 17, 4.1 ] 1337 9.25", - &[3.0, 17.0, 4.1], - &'static [f64] - ); - } - - #[test] - fn set_shared_int_list() { - assert_evals_to!( - indoc!( - r#" - shared = [ 2.1, 4.3 ] - - # This should not mutate the original - x = - when List.get (List.set shared 1 7.7) 1 is - Ok num -> num - Err _ -> 0 - - y = - when List.get shared 1 is - Ok num -> num - Err _ -> 0 - - { x, y } - "# - ), - (7.7, 4.3), - (f64, f64) - ); - } - - #[test] - fn set_shared_list_oob() { - assert_evals_to!( - indoc!( - r#" - shared = [ 2, 4 ] - - # This List.set is out of bounds, and should have no effect - x = - when List.get (List.set shared 422 0) 1 is - Ok num -> num - Err _ -> 0 - - y = - when List.get shared 1 is - Ok num -> num - Err _ -> 0 - - { x, y } - "# - ), - (4, 4), - (i64, i64) - ); - } - - #[test] - fn get_unique_int_list() { - assert_evals_to!( - indoc!( - r#" - unique = [ 2, 4 ] - - when List.get unique 1 is - Ok num -> num - Err _ -> -1 - "# - ), - 4, - i64 - ); - } - #[test] fn int_to_float() { assert_evals_to!("Num.toFloat 0x9", 9.0, f64); @@ -777,78 +503,4 @@ mod gen_builtins { fn float_to_float() { assert_evals_to!("Num.toFloat 0.5", 0.5, f64); } - - #[test] - fn gen_quicksort() { - if true { - todo!("fix gen_quicksort"); - } - - assert_evals_to!( - indoc!( - r#" - quicksort : List (Num a) -> List (Num a) - quicksort = \list -> - quicksortHelp list 0 (List.len list - 1) - - - quicksortHelp : List (Num a), Int, Int -> List (Num a) - quicksortHelp = \list, low, high -> - if low < high then - when partition low high list is - Pair partitionIndex partitioned -> - partitioned - |> quicksortHelp low (partitionIndex - 1) - |> quicksortHelp (partitionIndex + 1) high - else - list - - - swap : Int, Int, List a -> List a - swap = \i, j, list -> - when Pair (List.get list i) (List.get list j) is - Pair (Ok atI) (Ok atJ) -> - list - |> List.set i atJ - |> List.set j atI - - _ -> - [] - - partition : Int, Int, List (Num a) -> [ Pair Int (List (Num a)) ] - partition = \low, high, initialList -> - when List.get initialList high is - Ok pivot -> - when partitionHelp (low - 1) low initialList high pivot is - Pair newI newList -> - Pair (newI + 1) (swap (newI + 1) high newList) - - Err _ -> - Pair (low - 1) initialList - - - partitionHelp : Int, Int, List (Num a), Int, Int -> [ Pair Int (List (Num a)) ] - partitionHelp = \i, j, list, high, pivot -> - if j < high then - when List.get list j is - Ok value -> - if value <= pivot then - partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot - else - partitionHelp i (j + 1) list high pivot - - Err _ -> - Pair i list - else - Pair i list - - - - quicksort [ 7, 4, 21, 19 ] - "# - ), - &[4, 7, 19, 21], - &'static [i64] - ); - } }