Add macro to expect runtime error panic through llvm backend, and a test

This commit is contained in:
ayazhafiz 2021-12-22 09:17:54 -06:00
parent 903fa7d363
commit 823e32961f
3 changed files with 104 additions and 16 deletions

View file

@ -1,6 +1,9 @@
#[cfg(feature = "gen-llvm")] #[cfg(feature = "gen-llvm")]
use crate::helpers::llvm::assert_evals_to; use crate::helpers::llvm::assert_evals_to;
#[cfg(feature = "gen-llvm")]
use crate::helpers::llvm::expect_runtime_error_panic;
#[cfg(feature = "gen-dev")] #[cfg(feature = "gen-dev")]
use crate::helpers::dev::assert_evals_to; use crate::helpers::dev::assert_evals_to;
@ -1007,3 +1010,22 @@ fn both_have_unique_fields() {
i64 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: ""}
"#
))
}

View file

@ -28,8 +28,6 @@ pub fn test_builtin_defs(symbol: Symbol, var_store: &mut VarStore) -> Option<Def
builtin_defs_map(symbol, var_store) builtin_defs_map(symbol, var_store)
} }
// this is not actually dead code, but only used by cfg_test modules
// so "normally" it is dead, only at testing time is it used
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn create_llvm_module<'a>( fn create_llvm_module<'a>(
arena: &'a bumpalo::Bump, arena: &'a bumpalo::Bump,
@ -511,16 +509,31 @@ where
#[allow(unused_macros)] #[allow(unused_macros)]
macro_rules! assert_wasm_evals_to { 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) { match $crate::helpers::llvm::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) {
Err(msg) => panic!("Wasm test failed: {:?}", msg), Err(msg) => panic!("Wasm test failed: {:?}", msg),
Ok(actual) => { Ok(actual) => {
#[allow(clippy::bool_assert_comparison)] if $expect_failure {
assert_eq!($transform(actual), $expected, "Wasm test failed") 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) => { ($src:expr, $expected:expr, $ty:ty) => {
$crate::helpers::llvm::assert_wasm_evals_to!( $crate::helpers::llvm::assert_wasm_evals_to!(
$src, $src,
@ -538,7 +551,7 @@ macro_rules! assert_wasm_evals_to {
#[allow(unused_macros)] #[allow(unused_macros)]
macro_rules! assert_llvm_evals_to { 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 bumpalo::Bump;
use inkwell::context::Context; use inkwell::context::Context;
use roc_gen_llvm::run_jit_function; use roc_gen_llvm::run_jit_function;
@ -560,26 +573,47 @@ macro_rules! assert_llvm_evals_to {
); );
let transform = |success| { let transform = |success| {
let expected = $expected; if $expect_rt_error {
#[allow(clippy::redundant_closure_call)] assert_eq!(
let given = $transform(success); true, false,
assert_eq!(&given, &expected, "LLVM test failed"); "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) 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) => { ($src:expr, $expected:expr, $ty:ty) => {
$crate::helpers::llvm::assert_llvm_evals_to!( $crate::helpers::llvm::assert_llvm_evals_to!(
$src, $src,
$expected, $expected,
$ty, $ty,
$crate::helpers::llvm::identity, $crate::helpers::llvm::identity,
false,
false false
); );
}; };
($src:expr, $expected:expr, $ty:ty, $transform:expr) => { ($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); assert_evals_to!($src, $expected, $ty, $crate::helpers::llvm::identity);
}}; }};
($src:expr, $expected:expr, $ty:ty, $transform:expr) => { ($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")] #[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)] #[allow(dead_code)]
pub fn identity<T>(value: T) -> T { pub fn identity<T>(value: T) -> T {
value value
@ -617,7 +678,7 @@ macro_rules! assert_non_opt_evals_to {
($src:expr, $expected:expr, $ty:ty, $transform:expr) => { ($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.
{ {
$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) => {{ ($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; pub(crate) use assert_non_opt_evals_to;
#[allow(unused_imports)] #[allow(unused_imports)]
pub(crate) use assert_wasm_evals_to; pub(crate) use assert_wasm_evals_to;
#[allow(unused_imports)]
pub(crate) use expect_runtime_error_panic;

View file

@ -3,4 +3,7 @@ app "hello-world"
imports [] imports []
provides [ main ] to pf provides [ main ] to pf
main = "Hello, World!\n" main =
get : {a: Bool} -> Bool
get = \{a} -> a
get {b: ""}