diff --git a/compiler/test_gen/src/gen_records.rs b/compiler/test_gen/src/gen_records.rs index c799d09a57..a6266b9a0c 100644 --- a/compiler/test_gen/src/gen_records.rs +++ b/compiler/test_gen/src/gen_records.rs @@ -1,6 +1,9 @@ #[cfg(feature = "gen-llvm")] use crate::helpers::llvm::assert_evals_to; +#[cfg(feature = "gen-llvm")] +use crate::helpers::llvm::expect_runtime_error_panic; + #[cfg(feature = "gen-dev")] use crate::helpers::dev::assert_evals_to; @@ -1007,3 +1010,22 @@ fn both_have_unique_fields() { i64 ); } + +#[test] +#[cfg(any(feature = "gen-llvm"))] +#[should_panic( + // TODO: something upstream is escaping the ' + expected = r#"Roc failed with message: "Can\'t create record with improper layout""# +)] +fn call_with_bad_record_runtime_error() { + expect_runtime_error_panic!(indoc!( + r#" + app "test" provides [ main ] to "./platform" + + main = + get : {a: Bool} -> Bool + get = \{a} -> a + get {b: ""} + "# + )) +} diff --git a/compiler/test_gen/src/helpers/llvm.rs b/compiler/test_gen/src/helpers/llvm.rs index a74f64eaba..5281eeda9d 100644 --- a/compiler/test_gen/src/helpers/llvm.rs +++ b/compiler/test_gen/src/helpers/llvm.rs @@ -28,8 +28,6 @@ pub fn test_builtin_defs(symbol: Symbol, var_store: &mut VarStore) -> Option( arena: &'a bumpalo::Bump, @@ -511,16 +509,31 @@ where #[allow(unused_macros)] macro_rules! assert_wasm_evals_to { - ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => { + ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr, $expect_failure:expr) => { match $crate::helpers::llvm::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) { Err(msg) => panic!("Wasm test failed: {:?}", msg), Ok(actual) => { - #[allow(clippy::bool_assert_comparison)] - assert_eq!($transform(actual), $expected, "Wasm test failed") + if $expect_failure { + assert!(false, "Expected failure during wasm execution!") + } else { + #[allow(clippy::bool_assert_comparison)] + assert_eq!($transform(actual), $expected, "Wasm test failed") + } } } }; + ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => { + $crate::helpers::llvm::assert_wasm_evals_to!( + $src, + $expected, + $ty, + $crate::helpers::llvm::identity, + $ignore_problems, + false + ); + }; + ($src:expr, $expected:expr, $ty:ty) => { $crate::helpers::llvm::assert_wasm_evals_to!( $src, @@ -538,7 +551,7 @@ macro_rules! assert_wasm_evals_to { #[allow(unused_macros)] macro_rules! assert_llvm_evals_to { - ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => { + ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr, $expect_rt_error:expr) => { use bumpalo::Bump; use inkwell::context::Context; use roc_gen_llvm::run_jit_function; @@ -560,26 +573,47 @@ macro_rules! assert_llvm_evals_to { ); let transform = |success| { - let expected = $expected; - #[allow(clippy::redundant_closure_call)] - let given = $transform(success); - assert_eq!(&given, &expected, "LLVM test failed"); + if $expect_rt_error { + assert_eq!( + true, false, + "Runtime error expected, but evaluation succeeded!" + ) + } else { + let expected = $expected; + #[allow(clippy::redundant_closure_call)] + let given = $transform(success); + assert_eq!(&given, &expected, "LLVM test failed"); + } }; run_jit_function!(lib, main_fn_name, $ty, transform, errors) }; + ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => { + $crate::helpers::llvm::assert_llvm_evals_to!( + $src, + $expected, + $ty, + $transform, + $ignore_problems, + false + ); + }; + ($src:expr, $expected:expr, $ty:ty) => { $crate::helpers::llvm::assert_llvm_evals_to!( $src, $expected, $ty, $crate::helpers::llvm::identity, + false, false ); }; ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { - $crate::helpers::llvm::assert_llvm_evals_to!($src, $expected, $ty, $transform, false); + $crate::helpers::llvm::assert_llvm_evals_to!( + $src, $expected, $ty, $transform, false, false + ); }; } @@ -589,16 +623,43 @@ macro_rules! assert_evals_to { assert_evals_to!($src, $expected, $ty, $crate::helpers::llvm::identity); }}; ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { - // Same as above, except with an additional transformation argument. + // same as above, except with an additional transformation argument. { #[cfg(feature = "wasm-cli-run")] - $crate::helpers::llvm::assert_wasm_evals_to!($src, $expected, $ty, $transform, false); + $crate::helpers::llvm::assert_wasm_evals_to!( + $src, $expected, $ty, $transform, false, false + ); - $crate::helpers::llvm::assert_llvm_evals_to!($src, $expected, $ty, $transform, false); + $crate::helpers::llvm::assert_llvm_evals_to!( + $src, $expected, $ty, $transform, false, false + ); } }; } +macro_rules! expect_runtime_error_panic { + ($src:expr) => {{ + #[cfg(feature = "wasm-cli-run")] + $crate::helpers::llvm::assert_wasm_evals_to!( + $src, + false, // fake value/type for eval + bool, + $crate::helpers::llvm::identity, + true, // ignore problems + true // expect runtime error + ); + + $crate::helpers::llvm::assert_llvm_evals_to!( + $src, + false, // fake value/type for eval + bool, + $crate::helpers::llvm::identity, + true, // ignore problems + true // expect runtime error + ); + }}; +} + #[allow(dead_code)] pub fn identity(value: T) -> T { value @@ -617,7 +678,7 @@ macro_rules! assert_non_opt_evals_to { ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { // Same as above, except with an additional transformation argument. { - $crate::helpers::llvm::assert_llvm_evals_to!($src, $expected, $ty, $transform, false); + $crate::helpers::llvm::assert_llvm_evals_to!($src, $expected, $ty, $transform); } }; ($src:expr, $expected:expr, $ty:ty, $transform:expr) => {{ @@ -633,3 +694,5 @@ pub(crate) use assert_llvm_evals_to; pub(crate) use assert_non_opt_evals_to; #[allow(unused_imports)] pub(crate) use assert_wasm_evals_to; +#[allow(unused_imports)] +pub(crate) use expect_runtime_error_panic; diff --git a/examples/hello-world/Hello.roc b/examples/hello-world/Hello.roc index de5250ff5f..68a25c73df 100644 --- a/examples/hello-world/Hello.roc +++ b/examples/hello-world/Hello.roc @@ -3,4 +3,7 @@ app "hello-world" imports [] provides [ main ] to pf -main = "Hello, World!\n" +main = + get : {a: Bool} -> Bool + get = \{a} -> a + get {b: ""}