Merge branch 'trunk' into str_trim_left

This commit is contained in:
Michael Downey 2021-11-09 19:43:26 -05:00 committed by GitHub
commit 07cd3850d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
62 changed files with 3288 additions and 7733 deletions

4
.cargo/config Normal file
View file

@ -0,0 +1,4 @@
[alias]
test-gen-llvm = "test -p test_gen"
test-gen-dev = "test -p test_gen --no-default-features --features gen-dev"
test-gen-wasm = "test -p test_gen --no-default-features --features gen-wasm"

57
Cargo.lock generated
View file

@ -3402,12 +3402,10 @@ version = "0.1.0"
dependencies = [
"bumpalo",
"roc_builtins",
"roc_can",
"roc_collections",
"roc_module",
"roc_mono",
"roc_std",
"roc_types",
]
[[package]]
@ -4070,29 +4068,6 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "test_dev"
version = "0.1.0"
dependencies = [
"bumpalo",
"indoc",
"libloading 0.7.1",
"roc_build",
"roc_builtins",
"roc_can",
"roc_collections",
"roc_constrain",
"roc_gen_dev",
"roc_load",
"roc_mono",
"roc_parse",
"roc_problem",
"roc_reporting",
"roc_std",
"target-lexicon",
"tempfile",
]
[[package]]
name = "test_gen"
version = "0.1.0"
@ -4110,7 +4085,9 @@ dependencies = [
"roc_can",
"roc_collections",
"roc_constrain",
"roc_gen_dev",
"roc_gen_llvm",
"roc_gen_wasm",
"roc_load",
"roc_module",
"roc_mono",
@ -4124,7 +4101,6 @@ dependencies = [
"roc_unify",
"target-lexicon",
"tempfile",
"test_wasm_util",
"wasmer",
"wasmer-wasi",
]
@ -4154,35 +4130,6 @@ dependencies = [
"syn",
]
[[package]]
name = "test_wasm"
version = "0.1.0"
dependencies = [
"bumpalo",
"indoc",
"libc",
"roc_builtins",
"roc_can",
"roc_collections",
"roc_gen_wasm",
"roc_load",
"roc_module",
"roc_std",
"roc_types",
"target-lexicon",
"test_wasm_util",
"wasmer",
"wasmer-wasi",
]
[[package]]
name = "test_wasm_util"
version = "0.1.0"
dependencies = [
"roc_std",
"wasmer",
]
[[package]]
name = "textwrap"
version = "0.11.0"

View file

@ -22,9 +22,7 @@ members = [
"compiler/gen_wasm",
"compiler/build",
"compiler/arena_pool",
"compiler/test_dev",
"compiler/test_gen",
"compiler/test_wasm",
"vendor/ena",
"vendor/inkwell",
"vendor/pathfinding",
@ -44,7 +42,6 @@ exclude = [
# The tests will still correctly build them.
"cli_utils",
"compiler/test_mono_macros",
"compiler/test_wasm_util",
]
# Needed to be able to run `cargo run -p roc_cli --no-default-features` -
# see www/build.sh for more.

View file

@ -79,10 +79,13 @@ test-rust:
# not pre-compiling the host can cause race conditions
RUN echo "4" | cargo run --release examples/benchmarks/NQueens.roc
RUN --mount=type=cache,target=$SCCACHE_DIR \
cargo test --release --features with_sound --workspace --exclude test_wasm && sccache --show-stats
# test_wasm has some multithreading problems to do with the wasmer runtime. Run it single-threaded as a separate job
cargo test --release --features with_sound --workspace && sccache --show-stats
# test the dev and wasm backend: they require an explicit feature flag.
RUN --mount=type=cache,target=$SCCACHE_DIR \
cargo test --release --package test_wasm -- --test-threads=1 && sccache --show-stats
cargo test --release --package test_gen --no-default-features --features gen-dev && sccache --show-stats
# gen-wasm has some multithreading problems to do with the wasmer runtime. Run it single-threaded as a separate job
RUN --mount=type=cache,target=$SCCACHE_DIR \
cargo test --release --package test_gen --no-default-features --features gen-wasm -- --test-threads=1 && sccache --show-stats
# run i386 (32-bit linux) cli tests
RUN echo "4" | cargo run --release --features="target-x86" -- --backend=x86_32 examples/benchmarks/NQueens.roc
RUN --mount=type=cache,target=$SCCACHE_DIR \

View file

@ -888,6 +888,34 @@ pub fn listTakeFirst(
}
}
pub fn listTakeLast(
list: RocList,
alignment: u32,
element_width: usize,
take_count: usize,
dec: Dec,
) callconv(.C) RocList {
if (take_count == 0) {
return RocList.empty();
}
if (list.bytes) |source_ptr| {
const size = list.len();
if (size <= take_count) {
return list;
}
const drop_count = size - take_count;
return listDrop(
list,
alignment,
element_width,
drop_count,
dec,
);
} else {
return RocList.empty();
}
}
pub fn listDrop(
list: RocList,
alignment: u32,
@ -1333,3 +1361,39 @@ inline fn listSetImmutable(
//return list;
return new_bytes;
}
pub fn listFindUnsafe(
list: RocList,
caller: Caller1,
data: Opaque,
inc_n_data: IncN,
data_is_owned: bool,
alignment: u32,
element_width: usize,
inc: Inc,
dec: Dec,
) callconv(.C) extern struct { value: Opaque, found: bool } {
if (list.bytes) |source_ptr| {
const size = list.len();
if (data_is_owned) {
inc_n_data(data, size);
}
var i: usize = 0;
while (i < size) : (i += 1) {
var theOne = false;
const element = source_ptr + (i * element_width);
inc(element);
caller(data, element, @ptrCast(?[*]u8, &theOne));
if (theOne) {
return .{ .value = element, .found = true };
} else {
dec(element);
}
}
return .{ .value = null, .found = false };
} else {
return .{ .value = null, .found = false };
}
}

View file

@ -46,12 +46,14 @@ comptime {
exportListFn(list.listSortWith, "sort_with");
exportListFn(list.listConcat, "concat");
exportListFn(list.listTakeFirst, "take_first");
exportListFn(list.listTakeLast, "take_last");
exportListFn(list.listDrop, "drop");
exportListFn(list.listDropAt, "drop_at");
exportListFn(list.listSet, "set");
exportListFn(list.listSetInPlace, "set_in_place");
exportListFn(list.listSwap, "swap");
exportListFn(list.listAny, "any");
exportListFn(list.listFindUnsafe, "find_unsafe");
}
// Dict Module

View file

@ -690,3 +690,7 @@ all : List elem, (elem -> Bool) -> Bool
## Run the given predicate on each element of the list, returning `True` if
## any of the elements satisfy it.
any : List elem, (elem -> Bool) -> Bool
## Returns the first element of the list satisfying a predicate function.
## If no satisfying element is found, an `Err NotFound` is returned.
find : List elem, (elem -> Bool) -> Result elem [ NotFound ]*

View file

@ -179,6 +179,7 @@ pub const LIST_REPEAT: &str = "roc_builtins.list.repeat";
pub const LIST_APPEND: &str = "roc_builtins.list.append";
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
pub const LIST_TAKE_FIRST: &str = "roc_builtins.list.take_first";
pub const LIST_TAKE_LAST: &str = "roc_builtins.list.take_last";
pub const LIST_DROP: &str = "roc_builtins.list.drop";
pub const LIST_DROP_AT: &str = "roc_builtins.list.drop_at";
pub const LIST_SWAP: &str = "roc_builtins.list.swap";
@ -191,6 +192,7 @@ pub const LIST_CONCAT: &str = "roc_builtins.list.concat";
pub const LIST_SET: &str = "roc_builtins.list.set";
pub const LIST_SET_IN_PLACE: &str = "roc_builtins.list.set_in_place";
pub const LIST_ANY: &str = "roc_builtins.list.any";
pub const LIST_FIND_UNSAFE: &str = "roc_builtins.list.find_unsafe";
pub const DEC_FROM_F64: &str = "roc_builtins.dec.from_f64";
pub const DEC_EQ: &str = "roc_builtins.dec.eq";

View file

@ -985,6 +985,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
Box::new(list_type(flex(TVAR1))),
);
// takeLast : List elem, Nat -> List elem
add_top_level_function_type!(
Symbol::LIST_TAKE_LAST,
vec![list_type(flex(TVAR1)), nat_type()],
Box::new(list_type(flex(TVAR1))),
);
// drop : List elem, Nat -> List elem
add_top_level_function_type!(
Symbol::LIST_DROP,
@ -1093,6 +1100,23 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
Box::new(list_type(flex(TVAR1))),
);
// find : List elem, (elem -> Bool) -> Result elem [ NotFound ]*
{
let not_found = SolvedType::TagUnion(
vec![(TagName::Global("NotFound".into()), vec![])],
Box::new(SolvedType::Wildcard),
);
let (elem, cvar) = (TVAR1, TVAR2);
add_top_level_function_type!(
Symbol::LIST_FIND,
vec![
list_type(flex(elem)),
closure(vec![flex(elem)], cvar, Box::new(bool_type())),
],
Box::new(result_type(flex(elem), not_found)),
)
}
// Dict module
// len : Dict * * -> Nat

View file

@ -93,6 +93,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
LIST_MAP3 => list_map3,
LIST_MAP4 => list_map4,
LIST_TAKE_FIRST => list_take_first,
LIST_TAKE_LAST => list_take_last,
LIST_DROP => list_drop,
LIST_DROP_AT => list_drop_at,
LIST_DROP_FIRST => list_drop_first,
@ -108,6 +109,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
LIST_WALK_UNTIL => list_walk_until,
LIST_SORT_WITH => list_sort_with,
LIST_ANY => list_any,
LIST_FIND => list_find,
DICT_LEN => dict_len,
DICT_EMPTY => dict_empty,
DICT_SINGLE => dict_single,
@ -2035,6 +2037,29 @@ fn list_take_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
)
}
/// List.takeLast : List elem, Nat -> List elem
fn list_take_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh();
let len_var = var_store.fresh();
let body = RunLowLevel {
op: LowLevel::ListTakeLast,
args: vec![
(list_var, Var(Symbol::ARG_1)),
(len_var, Var(Symbol::ARG_2)),
],
ret_var: list_var,
};
defn(
symbol,
vec![(list_var, Symbol::ARG_1), (len_var, Symbol::ARG_2)],
var_store,
body,
list_var,
)
}
/// List.drop : List elem, Nat -> List elem
fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh();
@ -2730,6 +2755,87 @@ fn list_any(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_2(symbol, LowLevel::ListAny, var_store)
}
/// List.find : List elem, (elem -> Bool) -> Result elem [ NotFound ]*
fn list_find(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list = Symbol::ARG_1;
let find_predicate = Symbol::ARG_2;
let find_result = Symbol::LIST_FIND_RESULT;
let t_list = var_store.fresh();
let t_pred_fn = var_store.fresh();
let t_bool = var_store.fresh();
let t_found = var_store.fresh();
let t_value = var_store.fresh();
let t_ret = var_store.fresh();
let t_find_result = var_store.fresh();
let t_ext_var1 = var_store.fresh();
let t_ext_var2 = var_store.fresh();
// ListFindUnsafe returns { value: elem, found: Bool }.
// When `found` is true, the value was found. Otherwise `List.find` should return `Err ...`
let find_result_def = Def {
annotation: None,
expr_var: t_find_result,
loc_expr: no_region(RunLowLevel {
op: LowLevel::ListFindUnsafe,
args: vec![(t_list, Var(list)), (t_pred_fn, Var(find_predicate))],
ret_var: t_find_result,
}),
loc_pattern: no_region(Pattern::Identifier(find_result)),
pattern_vars: Default::default(),
};
let get_value = Access {
record_var: t_find_result,
ext_var: t_ext_var1,
field_var: t_value,
loc_expr: Box::new(no_region(Var(find_result))),
field: "value".into(),
};
let get_found = Access {
record_var: t_find_result,
ext_var: t_ext_var2,
field_var: t_found,
loc_expr: Box::new(no_region(Var(find_result))),
field: "found".into(),
};
let make_ok = tag("Ok", vec![get_value], var_store);
let make_err = tag(
"Err",
vec![tag("NotFound", Vec::new(), var_store)],
var_store,
);
let inspect = If {
cond_var: t_bool,
branch_var: t_ret,
branches: vec![(
// if-condition
no_region(get_found),
no_region(make_ok),
)],
final_else: Box::new(no_region(make_err)),
};
let body = LetNonRec(
Box::new(find_result_def),
Box::new(no_region(inspect)),
t_ret,
);
defn(
symbol,
vec![(t_list, Symbol::ARG_1), (t_pred_fn, Symbol::ARG_2)],
var_store,
body,
t_ret,
)
}
/// Dict.len : Dict * * -> Nat
fn dict_len(symbol: Symbol, var_store: &mut VarStore) -> Def {
let arg1_var = var_store.fresh();

View file

@ -67,10 +67,9 @@ This is the general procedure I follow with some helpful links:
1. Find a feature that is just n+1.
For example, since we already have integers, adding a builtin that functions on them should be n+1.
On the other hand, since we don't yet have booleans/conditionals, adding if statements may not yet be n+1.
A good place to look for missing features is in the test files for both the [regular](https://github.com/rtfeldman/roc/tree/trunk/compiler/gen/tests) and [dev](https://github.com/rtfeldman/roc/tree/trunk/compiler/gen_dev/tests) backend.
Eventually these test files should be practically identical.
A good place to look for missing features is in the test files for generation in [test_gen](https://github.com/rtfeldman/roc/tree/trunk/compiler/test_gen). Any test that is not enabled for the `gen-dev` feature still needs to be added to the dev backend. Eventually all features should be enabled for the dev backend.
1. Pick/write the simplest test case you can find for the new feature.
Just uncomment/copy over the test if it already exists.
Just add `feature = "gen-dev"` to the `cfg` line for the test case.
1. Uncomment the code to print out procedures [from here](https://github.com/rtfeldman/roc/blob/trunk/compiler/gen_dev/tests/helpers/eval.rs) and run the test.
It should fail and print out the mono ir for this test case.
Seeing the actual mono ir tends to be very helpful for complex additions.

View file

@ -9,10 +9,11 @@ use crate::llvm::build_dict::{
use crate::llvm::build_hash::generic_hash;
use crate::llvm::build_list::{
self, allocate_list, empty_list, empty_polymorphic_list, list_any, list_append, list_concat,
list_contains, list_drop, list_drop_at, list_get_unsafe, list_join, list_keep_errs,
list_keep_if, list_keep_oks, list_len, list_map, list_map2, list_map3, list_map4,
list_map_with_index, list_prepend, list_range, list_repeat, list_reverse, list_set,
list_single, list_sort_with, list_swap, list_take_first,
list_contains, list_drop, list_drop_at, list_find_trivial_not_found, list_find_unsafe,
list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map,
list_map2, list_map3, list_map4, list_map_with_index, list_prepend, list_range, list_repeat,
list_reverse, list_set, list_single, list_sort_with, list_swap, list_take_first,
list_take_last,
};
use crate::llvm::build_str::{
empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int,
@ -4887,6 +4888,37 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
_ => unreachable!("invalid list layout"),
}
}
ListFindUnsafe { xs } => {
let (list, list_layout) = load_symbol_and_layout(scope, &xs);
let (function, closure, closure_layout) = function_details!();
match list_layout {
Layout::Builtin(Builtin::EmptyList) => {
// Returns { found: False, elem: \empty }, where the `elem` field is zero-sized.
// NB: currently we never hit this case, since the only caller of this
// lowlevel, namely List.find, will fail during monomorphization when there is no
// concrete list element type. This is because List.find returns a
// `Result elem [ NotFound ]*`, and we can't figure out the size of that if
// `elem` is not concrete.
list_find_trivial_not_found(env)
}
Layout::Builtin(Builtin::List(element_layout)) => {
let argument_layouts = &[**element_layout];
let roc_function_call = roc_function_call(
env,
layout_ids,
function,
closure,
closure_layout,
function_owns_closure_data,
argument_layouts,
);
list_find_unsafe(env, layout_ids, roc_function_call, list, element_layout)
}
_ => unreachable!("invalid list layout"),
}
}
DictWalk { xs, state } => {
let (dict, dict_layout) = load_symbol_and_layout(scope, &xs);
let (default, default_layout) = load_symbol_and_layout(scope, &state);
@ -5178,6 +5210,27 @@ fn run_low_level<'a, 'ctx, 'env>(
_ => unreachable!("Invalid layout {:?} in List.takeFirst", list_layout),
}
}
ListTakeLast => {
// List.takeLast : List elem, Nat -> List elem
debug_assert_eq!(args.len(), 2);
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let original_wrapper = list.into_struct_value();
let count = load_symbol(scope, &args[1]);
match list_layout {
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
Layout::Builtin(Builtin::List(element_layout)) => list_take_last(
env,
layout_ids,
original_wrapper,
count.into_int_value(),
element_layout,
),
_ => unreachable!("Invalid layout {:?} in List.takeLast", list_layout),
}
}
ListDrop => {
// List.drop : List elem, Nat -> List elem
debug_assert_eq!(args.len(), 2);
@ -5763,7 +5816,9 @@ fn run_low_level<'a, 'ctx, 'env>(
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk
| ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith
| ListAny | DictWalk => unreachable!("these are higher order, and are handled elsewhere"),
| ListAny | ListFindUnsafe | DictWalk => {
unreachable!("these are higher order, and are handled elsewhere")
}
}
}

View file

@ -316,6 +316,28 @@ pub fn list_take_first<'a, 'ctx, 'env>(
)
}
/// List.takeLast : List elem, Nat -> List elem
pub fn list_take_last<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
original_wrapper: StructValue<'ctx>,
count: IntValue<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
call_bitcode_fn_returns_list(
env,
&[
pass_list_cc(env, original_wrapper.into()),
env.alignment_intvalue(element_layout),
layout_width(env, element_layout),
count.into(),
dec_element_fn.as_global_value().as_pointer_value().into(),
],
bitcode::LIST_TAKE_LAST,
)
}
/// List.drop : List elem, Nat -> List elem
pub fn list_drop<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
@ -936,6 +958,123 @@ pub fn list_any<'a, 'ctx, 'env>(
)
}
/// List.findUnsafe : List elem, (elem -> Bool) -> { value: elem, found: bool }
pub fn list_find_unsafe<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
roc_function_call: RocFunctionCall<'ctx>,
list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_wrapper(env, layout_ids, element_layout);
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
// { value: *const u8, found: bool }
let result = call_bitcode_fn(
env,
&[
pass_list_cc(env, list),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
env.alignment_intvalue(element_layout),
layout_width(env, element_layout),
inc_element_fn.as_global_value().as_pointer_value().into(),
dec_element_fn.as_global_value().as_pointer_value().into(),
],
bitcode::LIST_FIND_UNSAFE,
)
.into_struct_value();
// We promised the caller we'd give them back a struct containing the element
// loaded on the stack, so we do that now. The element can't be loaded directly
// in the Zig definition called above, because we don't know the size of the
// element until user compile time, which is later than the compile time of bitcode defs.
let value_u8_ptr = env
.builder
.build_extract_value(result, 0, "get_value_ptr")
.unwrap()
.into_pointer_value();
let found = env
.builder
.build_extract_value(result, 1, "get_found")
.unwrap()
.into_int_value();
let start_block = env.builder.get_insert_block().unwrap();
let parent = start_block.get_parent().unwrap();
let if_not_null = env.context.append_basic_block(parent, "if_not_null");
let done_block = env.context.append_basic_block(parent, "done");
let value_bt = basic_type_from_layout(env, element_layout);
let default = value_bt.const_zero();
env.builder
.build_conditional_branch(found, if_not_null, done_block);
env.builder.position_at_end(if_not_null);
let value_ptr = env
.builder
.build_bitcast(
value_u8_ptr,
value_bt.ptr_type(AddressSpace::Generic),
"from_opaque",
)
.into_pointer_value();
let loaded = env.builder.build_load(value_ptr, "load_value");
env.builder.build_unconditional_branch(done_block);
env.builder.position_at_end(done_block);
let result_phi = env.builder.build_phi(value_bt, "result");
result_phi.add_incoming(&[(&default, start_block), (&loaded, if_not_null)]);
let value = result_phi.as_basic_value();
let result = env
.context
.struct_type(&[value_bt, env.context.bool_type().into()], false)
.const_zero();
let result = env
.builder
.build_insert_value(result, value, 0, "insert_value")
.unwrap();
env.builder
.build_insert_value(result, found, 1, "insert_found")
.unwrap()
.into_struct_value()
.into()
}
/// Returns { value: \empty, found: False }, representing that no element was found in a call
/// to List.find when the layout of the element is also unknown.
pub fn list_find_trivial_not_found<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
) -> BasicValueEnum<'ctx> {
let empty_type = env.context.custom_width_int_type(0);
let result = env
.context
.struct_type(&[empty_type.into(), env.context.bool_type().into()], false)
.const_zero();
env.builder
.build_insert_value(
result,
env.context.bool_type().const_zero(),
1,
"insert_found",
)
.unwrap()
.into_struct_value()
.into()
}
pub fn decrementing_elem_loop<'ctx, LoopFn>(
builder: &Builder<'ctx>,
ctx: &'ctx Context,

View file

@ -6,15 +6,9 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bumpalo = { version = "3.8.0", features = ["collections"] }
roc_builtins = { path = "../builtins" }
roc_collections = { path = "../collections" }
roc_module = { path = "../module" }
roc_mono = { path = "../mono" }
bumpalo = { version = "3.8.0", features = ["collections"] }
roc_std = { path = "../../roc_std" }
[dev-dependencies]
roc_can = { path = "../can" }
roc_builtins = { path = "../builtins" }
roc_types = { path = "../types" }
roc_module = { path = "../module" }

View file

@ -1,6 +1,7 @@
use bumpalo::{self, collections::Vec};
use code_builder::Align;
use roc_builtins::bitcode::{self, FloatWidth};
use roc_collections::all::MutMap;
use roc_module::low_level::LowLevel;
use roc_module::symbol::Symbol;
@ -9,10 +10,12 @@ use roc_mono::layout::{Layout, LayoutIds};
use crate::layout::WasmLayout;
use crate::storage::{Storage, StoredValue, StoredValueKind};
use crate::wasm_module::linking::{DataSymbol, LinkingSection, RelocationSection};
use crate::wasm_module::linking::{
DataSymbol, LinkingSection, RelocationSection, WasmObjectSymbol, WASM_SYM_UNDEFINED,
};
use crate::wasm_module::sections::{
CodeSection, DataMode, DataSection, DataSegment, ExportSection, FunctionSection, GlobalSection,
ImportSection, MemorySection, TypeSection, WasmModule,
Import, ImportDesc, ImportSection, MemorySection, TypeSection, WasmModule,
};
use crate::wasm_module::{
code_builder, BlockType, CodeBuilder, ConstExpr, Export, ExportType, Global, GlobalType,
@ -28,6 +31,8 @@ const CONST_SEGMENT_BASE_ADDR: u32 = 1024;
/// Index of the data segment where we store constants
const CONST_SEGMENT_INDEX: usize = 0;
const IMPORT_MODULE_BUILTINS: &str = "builtins";
pub struct WasmBackend<'a> {
env: &'a Env<'a>,
@ -35,6 +40,7 @@ pub struct WasmBackend<'a> {
pub module: WasmModule<'a>,
layout_ids: LayoutIds<'a>,
constant_sym_index_map: MutMap<&'a str, usize>,
builtin_sym_index_map: MutMap<&'a str, usize>,
proc_symbols: Vec<'a, Symbol>,
pub linker_symbols: Vec<'a, SymInfo>,
@ -52,7 +58,7 @@ impl<'a> WasmBackend<'a> {
env: &'a Env<'a>,
layout_ids: LayoutIds<'a>,
proc_symbols: Vec<'a, Symbol>,
linker_symbols: Vec<'a, SymInfo>,
mut linker_symbols: Vec<'a, SymInfo>,
mut exports: Vec<'a, Export>,
) -> Self {
const MEMORY_INIT_SIZE: u32 = 1024 * 1024;
@ -60,7 +66,7 @@ impl<'a> WasmBackend<'a> {
let num_procs = proc_symbols.len();
exports.push(Export {
name: "memory".to_string(),
name: "__linear_memory".to_string(),
ty: ExportType::Mem,
index: 0,
});
@ -72,6 +78,11 @@ impl<'a> WasmBackend<'a> {
},
init: ConstExpr::I32(MEMORY_INIT_SIZE as i32),
};
linker_symbols.push(SymInfo::Global(WasmObjectSymbol::Defined {
flags: 0,
index: 0,
name: "__stack_pointer".to_string(),
}));
let const_segment = DataSegment {
mode: DataMode::Active {
@ -92,7 +103,9 @@ impl<'a> WasmBackend<'a> {
export: ExportSection { entries: exports },
start: (),
element: (),
code: CodeSection::new(arena),
code: CodeSection {
code_builders: Vec::with_capacity_in(num_procs, arena),
},
data: DataSection {
segments: bumpalo::vec![in arena; const_segment],
},
@ -108,6 +121,7 @@ impl<'a> WasmBackend<'a> {
layout_ids,
constant_sym_index_map: MutMap::default(),
builtin_sym_index_map: MutMap::default(),
proc_symbols,
linker_symbols,
@ -181,7 +195,7 @@ impl<'a> WasmBackend<'a> {
self.end_block();
// Write local declarations and stack frame push/pop code
self.code_builder.finalize(
self.code_builder.build_fn_header(
&self.storage.local_types,
self.storage.stack_frame_size,
self.storage.stack_frame_pointer,
@ -650,42 +664,60 @@ impl<'a> WasmBackend<'a> {
) -> Result<(), String> {
self.storage.load_symbols(&mut self.code_builder, args);
let wasm_layout = WasmLayout::new(return_layout);
self.build_instructions_lowlevel(lowlevel, wasm_layout.value_type())?;
Ok(())
}
let ret_type = wasm_layout.value_type();
let panic_ret_type = || panic!("Invalid return type for {:?}: {:?}", lowlevel, ret_type);
fn build_instructions_lowlevel(
&mut self,
lowlevel: &LowLevel,
return_value_type: ValueType,
) -> Result<(), String> {
// TODO: Find a way to organise all the lowlevel ops and layouts! There's lots!
//
// Some Roc low-level ops care about wrapping, clipping, sign-extending...
// For those, we'll need to pre-process each argument before the main op,
// so simple arrays of instructions won't work. But there are common patterns.
match lowlevel {
LowLevel::NumAdd => match return_value_type {
LowLevel::NumAdd => match ret_type {
ValueType::I32 => self.code_builder.i32_add(),
ValueType::I64 => self.code_builder.i64_add(),
ValueType::F32 => self.code_builder.f32_add(),
ValueType::F64 => self.code_builder.f64_add(),
},
LowLevel::NumSub => match return_value_type {
LowLevel::NumSub => match ret_type {
ValueType::I32 => self.code_builder.i32_sub(),
ValueType::I64 => self.code_builder.i64_sub(),
ValueType::F32 => self.code_builder.f32_sub(),
ValueType::F64 => self.code_builder.f64_sub(),
},
LowLevel::NumMul => match return_value_type {
LowLevel::NumMul => match ret_type {
ValueType::I32 => self.code_builder.i32_mul(),
ValueType::I64 => self.code_builder.i64_mul(),
ValueType::F32 => self.code_builder.f32_mul(),
ValueType::F64 => self.code_builder.f64_mul(),
},
LowLevel::NumGt => {
// needs layout of the argument to be implemented fully
self.code_builder.i32_gt_s()
LowLevel::NumGt => match self.get_uniform_arg_type(args) {
ValueType::I32 => self.code_builder.i32_gt_s(),
ValueType::I64 => self.code_builder.i64_gt_s(),
ValueType::F32 => self.code_builder.f32_gt(),
ValueType::F64 => self.code_builder.f64_gt(),
},
LowLevel::Eq => match self.get_uniform_arg_type(args) {
ValueType::I32 => self.code_builder.i32_eq(),
ValueType::I64 => self.code_builder.i64_eq(),
ValueType::F32 => self.code_builder.f32_eq(),
ValueType::F64 => self.code_builder.f64_eq(),
},
LowLevel::NumNeg => match ret_type {
ValueType::I32 => {
self.code_builder.i32_const(-1);
self.code_builder.i32_mul();
}
ValueType::I64 => {
self.code_builder.i64_const(-1);
self.code_builder.i64_mul();
}
ValueType::F32 => self.code_builder.f32_neg(),
ValueType::F64 => self.code_builder.f64_neg(),
},
LowLevel::NumAtan => {
let name = match ret_type {
ValueType::F32 => &bitcode::NUM_ATAN[FloatWidth::F32],
ValueType::F64 => &bitcode::NUM_ATAN[FloatWidth::F64],
_ => panic_ret_type(),
};
self.call_imported_builtin(name, &[ret_type], Some(ret_type));
}
_ => {
return Err(format!("unsupported low-level op {:?}", lowlevel));
@ -693,4 +725,61 @@ impl<'a> WasmBackend<'a> {
};
Ok(())
}
/// Get the ValueType for a set of arguments that are required to have the same type
fn get_uniform_arg_type(&self, args: &'a [Symbol]) -> ValueType {
let value_type = self.storage.get(&args[0]).value_type();
for arg in args.iter().skip(1) {
debug_assert!(self.storage.get(arg).value_type() == value_type);
}
value_type
}
fn call_imported_builtin(
&mut self,
name: &'a str,
arg_types: &[ValueType],
ret_type: Option<ValueType>,
) {
let (fn_index, linker_symbol_index) = match self.builtin_sym_index_map.get(name) {
Some(sym_idx) => match &self.linker_symbols[*sym_idx] {
SymInfo::Function(WasmObjectSymbol::Imported { index, .. }) => {
(*index, *sym_idx as u32)
}
x => unreachable!("Invalid linker symbol for builtin {}: {:?}", name, x),
},
None => {
let mut param_types = Vec::with_capacity_in(arg_types.len(), self.env.arena);
param_types.extend_from_slice(arg_types);
let signature_index = self.module.types.insert(Signature {
param_types,
ret_type,
});
let import_index = self.module.import.entries.len() as u32;
let import = Import {
module: IMPORT_MODULE_BUILTINS,
name: name.to_string(),
description: ImportDesc::Func { signature_index },
};
self.module.import.entries.push(import);
let sym_idx = self.linker_symbols.len() as u32;
let sym_info = SymInfo::Function(WasmObjectSymbol::Imported {
flags: WASM_SYM_UNDEFINED,
index: import_index,
});
self.linker_symbols.push(sym_info);
(import_index, sym_idx)
}
};
self.code_builder.call(
fn_index,
linker_symbol_index,
arg_types.len(),
ret_type.is_some(),
);
}
}

View file

@ -34,7 +34,7 @@ pub fn build_module<'a>(
) -> Result<std::vec::Vec<u8>, String> {
let mut wasm_module = build_module_help(env, procedures)?;
let mut buffer = std::vec::Vec::with_capacity(4096);
wasm_module.serialize(&mut buffer);
wasm_module.serialize_mut(&mut buffer);
Ok(buffer)
}

View file

@ -51,7 +51,16 @@ pub enum StoredValue {
size: u32,
alignment_bytes: u32,
},
// TODO: const data storage (fixed address)
}
impl StoredValue {
pub fn value_type(&self) -> ValueType {
match self {
Self::VirtualMachineStack { value_type, .. } => *value_type,
Self::Local { value_type, .. } => *value_type,
Self::StackMemory { .. } => ValueType::I32,
}
}
}
/// Helper structure for WasmBackend, to keep track of how values are stored,

View file

@ -350,11 +350,9 @@ impl<'a> CodeBuilder<'a> {
self.set_global(STACK_POINTER_GLOBAL_ID);
}
/// Finalize the function
/// Generate all the "extra" bytes: local declarations, stack frame push/pop code, and function length
/// After this, bytes will have been _generated_, but not yet _serialized_ into a single stream.
/// Returns the final number of bytes the function will occupy in the target binary
pub fn finalize(
/// Build the function header: local declarations, stack frame push/pop code, and function length
/// After this, all bytes have been generated (but not yet serialized) and we know the final size.
pub fn build_fn_header(
&mut self,
local_types: &[ValueType],
frame_size: i32,

View file

@ -174,6 +174,7 @@ impl<'a> Serialize for RelocationSection<'a> {
*******************************************************************/
/// Linking metadata for data segments
#[derive(Debug)]
pub struct LinkingSegment {
pub name: String,
pub alignment: Align,
@ -187,6 +188,7 @@ impl Serialize for LinkingSegment {
}
/// Linking metadata for init (start) functions
#[derive(Debug)]
pub struct LinkingInitFunc {
pub priority: u32,
pub symbol_index: u32, // index in the symbol table, not the function index
@ -213,6 +215,7 @@ pub enum ComdatSymKind {
Section = 5,
}
#[derive(Debug)]
pub struct ComdatSym {
pub kind: ComdatSymKind,
pub index: u32,
@ -229,6 +232,7 @@ impl Serialize for ComdatSym {
/// The linker will include all of these elements with a given group name from one object file,
/// and will exclude any element with this group name from all other object files.
#[allow(dead_code)]
#[derive(Debug)]
pub struct LinkingComdat<'a> {
name: String,
flags: u32,
@ -413,6 +417,7 @@ impl Serialize for SymInfo {
// Linking subsections
//----------------------------------------------------------------
#[derive(Debug)]
pub enum LinkingSubSection<'a> {
/// Extra metadata about the data segments.
SegmentInfo(Vec<'a, LinkingSegment>),
@ -454,6 +459,7 @@ impl<'a> Serialize for LinkingSubSection<'a> {
const LINKING_VERSION: u8 = 2;
#[derive(Debug)]
pub struct LinkingSection<'a> {
pub subsections: Vec<'a, LinkingSubSection<'a>>,
}
@ -464,6 +470,15 @@ impl<'a> LinkingSection<'a> {
subsections: Vec::with_capacity_in(1, arena),
}
}
pub fn symbol_table_mut(&mut self) -> &mut Vec<'a, SymInfo> {
for sub in self.subsections.iter_mut() {
if let LinkingSubSection::SymbolTable(syminfos) = sub {
return syminfos;
}
}
panic!("Symbol table not found");
}
}
impl<'a> Serialize for LinkingSection<'a> {

View file

@ -1,7 +1,9 @@
use bumpalo::collections::vec::Vec;
use bumpalo::Bump;
use super::linking::{LinkingSection, RelocationEntry, RelocationSection};
use super::linking::{
IndexRelocType, LinkingSection, RelocationEntry, RelocationSection, SymInfo, WasmObjectSymbol,
};
use super::opcodes;
use super::serialize::{SerialBuffer, Serialize};
use super::{CodeBuilder, ValueType};
@ -87,7 +89,7 @@ fn serialize_vector_section<B: SerialBuffer, T: Serialize>(
*
*******************************************************************/
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Debug)]
pub struct Signature<'a> {
pub param_types: Vec<'a, ValueType>,
pub ret_type: Option<ValueType>,
@ -101,6 +103,7 @@ impl<'a> Serialize for Signature<'a> {
}
}
#[derive(Debug)]
pub struct TypeSection<'a> {
/// Private. See WasmModule::add_function_signature
signatures: Vec<'a, Signature<'a>>,
@ -114,7 +117,7 @@ impl<'a> TypeSection<'a> {
}
/// Find a matching signature or insert a new one. Return the index.
fn insert(&mut self, signature: Signature<'a>) -> u32 {
pub fn insert(&mut self, signature: Signature<'a>) -> u32 {
// Using linear search because we need to preserve indices stored in
// the Function section. (Also for practical sizes it's fast)
let maybe_index = self.signatures.iter().position(|s| *s == signature);
@ -148,6 +151,7 @@ pub enum RefType {
Extern = 0x6f,
}
#[derive(Debug)]
pub struct TableType {
pub ref_type: RefType,
pub limits: Limits,
@ -160,6 +164,7 @@ impl Serialize for TableType {
}
}
#[derive(Debug)]
pub enum ImportDesc {
Func { signature_index: u32 },
Table { ty: TableType },
@ -167,8 +172,9 @@ pub enum ImportDesc {
Global { ty: GlobalType },
}
#[derive(Debug)]
pub struct Import {
pub module: String,
pub module: &'static str,
pub name: String,
pub description: ImportDesc,
}
@ -198,8 +204,9 @@ impl Serialize for Import {
}
}
#[derive(Debug)]
pub struct ImportSection<'a> {
entries: Vec<'a, Import>,
pub entries: Vec<'a, Import>,
}
impl<'a> ImportSection<'a> {
@ -208,6 +215,13 @@ impl<'a> ImportSection<'a> {
entries: bumpalo::vec![in arena],
}
}
pub fn function_count(&self) -> usize {
self.entries
.iter()
.filter(|import| matches!(import.description, ImportDesc::Func { .. }))
.count()
}
}
impl<'a> Serialize for ImportSection<'a> {
@ -223,6 +237,7 @@ impl<'a> Serialize for ImportSection<'a> {
*
*******************************************************************/
#[derive(Debug)]
pub struct FunctionSection<'a> {
/// Private. See WasmModule::add_function_signature
signature_indices: Vec<'a, u32>,
@ -247,6 +262,7 @@ impl<'a> Serialize for FunctionSection<'a> {
*
*******************************************************************/
#[derive(Debug)]
pub enum Limits {
Min(u32),
MinMax(u32, u32),
@ -268,6 +284,7 @@ impl Serialize for Limits {
}
}
#[derive(Debug)]
pub struct MemorySection(Option<Limits>);
impl MemorySection {
@ -309,6 +326,7 @@ impl Serialize for MemorySection {
*
*******************************************************************/
#[derive(Debug)]
pub struct GlobalType {
pub value_type: ValueType,
pub is_mutable: bool,
@ -323,6 +341,7 @@ impl Serialize for GlobalType {
/// Constant expression for initialising globals or data segments
/// Note: This is restricted for simplicity, but the spec allows arbitrary constant expressions
#[derive(Debug)]
pub enum ConstExpr {
I32(i32),
I64(i64),
@ -354,6 +373,7 @@ impl Serialize for ConstExpr {
}
}
#[derive(Debug)]
pub struct Global {
/// Type and mutability of the global
pub ty: GlobalType,
@ -368,6 +388,7 @@ impl Serialize for Global {
}
}
#[derive(Debug)]
pub struct GlobalSection<'a> {
pub entries: Vec<'a, Global>,
}
@ -393,6 +414,7 @@ pub enum ExportType {
Global = 3,
}
#[derive(Debug)]
pub struct Export {
pub name: String,
pub ty: ExportType,
@ -406,18 +428,11 @@ impl Serialize for Export {
}
}
#[derive(Debug)]
pub struct ExportSection<'a> {
pub entries: Vec<'a, Export>,
}
impl<'a> ExportSection<'a> {
pub fn new(arena: &'a Bump) -> Self {
ExportSection {
entries: bumpalo::vec![in arena],
}
}
}
impl<'a> Serialize for ExportSection<'a> {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
serialize_vector_section(buffer, SectionId::Export, &self.entries);
@ -436,18 +451,12 @@ pub struct CodeSection<'a> {
}
impl<'a> CodeSection<'a> {
pub fn new(arena: &'a Bump) -> Self {
CodeSection {
code_builders: Vec::with_capacity_in(8, arena),
}
}
/// Serialize the code builders for all functions, and get code relocations with final offsets
pub fn serialize_with_relocs<T: SerialBuffer>(
&self,
buffer: &mut T,
relocations: &mut Vec<'a, RelocationEntry>,
) {
) -> usize {
let header_indices = write_section_header(buffer, SectionId::Code);
buffer.encode_u32(self.code_builders.len() as u32);
@ -455,7 +464,9 @@ impl<'a> CodeSection<'a> {
code_builder.serialize_with_relocs(buffer, relocations, header_indices.body_index);
}
let code_section_body_index = header_indices.body_index;
update_section_size(buffer, header_indices);
code_section_body_index
}
}
@ -465,6 +476,7 @@ impl<'a> CodeSection<'a> {
*
*******************************************************************/
#[derive(Debug)]
pub enum DataMode {
/// A data segment that auto-loads into memory on instantiation
Active { offset: ConstExpr },
@ -472,6 +484,7 @@ pub enum DataMode {
Passive,
}
#[derive(Debug)]
pub struct DataSegment<'a> {
pub mode: DataMode,
pub init: Vec<'a, u8>,
@ -493,6 +506,7 @@ impl Serialize for DataSegment<'_> {
}
}
#[derive(Debug)]
pub struct DataSection<'a> {
pub segments: Vec<'a, DataSegment<'a>>,
}
@ -521,6 +535,7 @@ impl Serialize for DataSection<'_> {
*
*******************************************************************/
#[derive(Debug)]
struct DataCountSection {
count: u32,
}
@ -583,6 +598,7 @@ impl SectionCounter {
}
}
#[derive(Debug)]
pub struct WasmModule<'a> {
pub types: TypeSection<'a>,
pub import: ImportSection<'a>,
@ -611,8 +627,10 @@ impl<'a> WasmModule<'a> {
self.function.signature_indices.push(index);
}
/// Serialize the module to bytes
/// (Mutates some data related to linking)
#[allow(clippy::unit_arg)]
pub fn serialize<T: SerialBuffer>(&mut self, buffer: &mut T) {
pub fn serialize_mut<T: SerialBuffer>(&mut self, buffer: &mut T) {
buffer.append_u8(0);
buffer.append_slice("asm".as_bytes());
buffer.write_unencoded_u32(Self::WASM_VERSION);
@ -623,6 +641,13 @@ impl<'a> WasmModule<'a> {
section_index: 0,
};
// If we have imports, then references to other functions need to be re-indexed.
// Modify exports before serializing them, since we don't have linker data for them
let n_imported_fns = self.import.function_count() as u32;
if n_imported_fns > 0 {
self.finalize_exported_fn_indices(n_imported_fns);
}
counter.serialize_and_count(buffer, &self.types);
counter.serialize_and_count(buffer, &self.import);
counter.serialize_and_count(buffer, &self.function);
@ -640,9 +665,16 @@ impl<'a> WasmModule<'a> {
// Code section is the only one with relocations so we can stop counting
let code_section_index = counter.section_index;
self.code
let code_section_body_index = self
.code
.serialize_with_relocs(buffer, &mut self.relocations.entries);
// If we have imports, references to other functions need to be re-indexed.
// Simplest to do after serialization, using linker data
if n_imported_fns > 0 {
self.finalize_code_fn_indices(buffer, code_section_body_index, n_imported_fns);
}
self.data.serialize(buffer);
self.linking.serialize(buffer);
@ -650,4 +682,52 @@ impl<'a> WasmModule<'a> {
self.relocations.target_section_index = Some(code_section_index);
self.relocations.serialize(buffer);
}
/// Shift indices of exported functions to make room for imported functions,
/// which come first in the function index space.
/// Must be called after traversing the full IR, but before export section is serialized.
fn finalize_exported_fn_indices(&mut self, n_imported_fns: u32) {
for export in self.export.entries.iter_mut() {
if export.ty == ExportType::Func {
export.index += n_imported_fns;
}
}
}
/// Re-index internally-defined functions to make room for imported functions.
/// We do this after serialization, when all buffers in all CodeBuilders have been combined.
/// That makes the code simpler and avoids spreading it across multiple impl's and files.
fn finalize_code_fn_indices<T: SerialBuffer>(
&mut self,
buffer: &mut T,
code_section_body_index: usize,
n_imported_fns: u32,
) {
// Modify symbol table entries
let symbol_table = self.linking.symbol_table_mut();
let mut target_symbol_indices = std::vec::Vec::with_capacity(symbol_table.len());
for (i, sym_info) in symbol_table.iter_mut().enumerate() {
if let SymInfo::Function(WasmObjectSymbol::Defined { index, .. }) = sym_info {
target_symbol_indices.push(i as u32);
*index += n_imported_fns;
}
}
// Modify call instructions, using linker data
for reloc in &self.relocations.entries {
if let RelocationEntry::Index {
type_id: IndexRelocType::FunctionIndexLeb,
offset,
symbol_index,
} = reloc
{
if target_symbol_indices.contains(symbol_index) {
let orig_fn_index = *symbol_index; // trick: we know these were the first symbols we created
let new_fn_index = orig_fn_index + n_imported_fns;
let buffer_index = code_section_body_index + (*offset as usize);
buffer.overwrite_padded_u32(buffer_index, new_fn_index);
}
}
}
}
}

View file

@ -44,10 +44,12 @@ pub enum LowLevel {
ListKeepErrs,
ListSortWith,
ListTakeFirst,
ListTakeLast,
ListDrop,
ListDropAt,
ListSwap,
ListAny,
ListFindUnsafe,
DictSize,
DictEmpty,
DictInsert,
@ -135,6 +137,7 @@ macro_rules! first_order {
| ListGetUnsafe
| ListSet
| ListTakeFirst
| ListTakeLast
| ListDrop
| ListDropAt
| ListSingle
@ -227,6 +230,7 @@ macro_rules! higher_order {
| ListKeepErrs
| ListSortWith
| ListAny
| ListFindUnsafe
| DictWalk
};
}
@ -261,6 +265,7 @@ impl LowLevel {
ListKeepErrs => 1,
ListSortWith => 1,
ListAny => 1,
ListFindUnsafe => 1,
DictWalk => 2,
}
}

View file

@ -1067,6 +1067,9 @@ define_builtins! {
43 LIST_JOIN_MAP_CONCAT: "#joinMapConcat"
44 LIST_ANY: "any"
45 LIST_TAKE_FIRST: "takeFirst"
46 LIST_TAKE_LAST: "takeLast"
47 LIST_FIND: "find"
48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find
}
5 RESULT: "Result" => {
0 RESULT_RESULT: "Result" imported // the Result.Result type alias

View file

@ -1093,6 +1093,41 @@ fn call_spec(
add_loop(builder, block, state_type, init_state, loop_body)
}
ListFindUnsafe { xs } => {
let list = env.symbols[xs];
// ListFindUnsafe returns { value: v, found: Bool=Int1 }
let output_layouts = vec![arg_layouts[0], Layout::Builtin(Builtin::Int1)];
let output_layout = Layout::Struct(&output_layouts);
let output_type = layout_spec(builder, &output_layout)?;
let loop_body = |builder: &mut FuncDefBuilder, block, output| {
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
let element = builder.add_bag_get(block, bag)?;
let _is_found = call_function!(builder, block, [element]);
// We may or may not use the element we got from the list in the output struct,
// depending on whether we found the element to satisfy the "find" predicate.
// If we did find the element, our output "changes" to be a record including that element.
let found_branch = builder.add_block();
let new_output =
builder.add_unknown_with(block, &[element], output_type)?;
let not_found_branch = builder.add_block();
builder.add_choice(
block,
&[
BlockExpr(found_branch, new_output),
BlockExpr(not_found_branch, output),
],
)
};
// Assume the output is initially { found: False, value: \empty }
let output_state = builder.add_unknown_with(block, &[], output_type)?;
add_loop(builder, block, output_type, output_state, loop_body)
}
}
}
}

View file

@ -618,7 +618,8 @@ impl<'a> BorrowInfState<'a> {
| ListKeepIf { xs }
| ListKeepOks { xs }
| ListKeepErrs { xs }
| ListAny { xs } => {
| ListAny { xs }
| ListFindUnsafe { xs } => {
// own the list if the function wants to own the element
if !function_ps[0].borrow {
self.own_var(*xs);
@ -960,11 +961,13 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
arena.alloc_slice_copy(&[owned, owned, function, closure_data])
}
ListSortWith => arena.alloc_slice_copy(&[owned, function, closure_data]),
ListFindUnsafe => arena.alloc_slice_copy(&[owned, function, closure_data]),
// TODO when we have lists with capacity (if ever)
// List.append should own its first argument
ListAppend => arena.alloc_slice_copy(&[owned, owned]),
ListTakeFirst => arena.alloc_slice_copy(&[owned, irrelevant]),
ListTakeLast => arena.alloc_slice_copy(&[owned, irrelevant]),
ListDrop => arena.alloc_slice_copy(&[owned, irrelevant]),
ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]),
ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),

View file

@ -531,7 +531,8 @@ impl<'a> Context<'a> {
| ListKeepIf { xs }
| ListKeepOks { xs }
| ListKeepErrs { xs }
| ListAny { xs } => {
| ListAny { xs }
| ListFindUnsafe { xs } => {
let borrows = [function_ps[0].borrow, FUNCTION, CLOSURE_DATA];
let b = self.add_dec_after_lowlevel(arguments, &borrows, b, b_live_vars);

View file

@ -4164,6 +4164,11 @@ pub fn with_hole<'a>(
match_on_closure_argument!(ListMap4, [xs, ys, zs, ws])
}
ListFindUnsafe => {
debug_assert_eq!(arg_symbols.len(), 2);
let xs = arg_symbols[0];
match_on_closure_argument!(ListFindUnsafe, [xs])
}
_ => {
let call = self::Call {
call_type: CallType::LowLevel {

View file

@ -50,6 +50,9 @@ pub enum HigherOrder {
ListAny {
xs: Symbol,
},
ListFindUnsafe {
xs: Symbol,
},
DictWalk {
xs: Symbol,
state: Symbol,
@ -71,6 +74,7 @@ impl HigherOrder {
HigherOrder::ListKeepOks { .. } => 1,
HigherOrder::ListKeepErrs { .. } => 1,
HigherOrder::ListSortWith { .. } => 2,
HigherOrder::ListFindUnsafe { .. } => 1,
HigherOrder::DictWalk { .. } => 2,
HigherOrder::ListAny { .. } => 1,
}
@ -97,6 +101,7 @@ enum FirstOrder {
ListGetUnsafe,
ListSet,
ListTakeFirst,
ListTakeLast,
ListDrop,
ListDropAt,
ListSingle,

View file

@ -3769,6 +3769,18 @@ mod solve_expr {
);
}
#[test]
fn list_take_last() {
infer_eq_without_problem(
indoc!(
r#"
List.takeLast
"#
),
"List a, Nat -> List a",
);
}
#[test]
fn list_drop_last() {
infer_eq_without_problem(

View file

@ -1,28 +0,0 @@
[package]
name = "test_dev"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[test]]
name = "test_dev"
path = "src/tests.rs"
[dev-dependencies]
roc_collections = { path = "../collections" }
roc_can = { path = "../can" }
roc_build = { path = "../build" }
roc_parse = { path = "../parse" }
roc_reporting = { path = "../reporting" }
roc_load = { path = "../load" }
roc_constrain = { path = "../constrain" }
roc_std = { path = "../../roc_std" }
roc_gen_dev = { path = "../gen_dev" }
roc_mono = { path = "../mono" }
roc_problem = { path = "../problem" }
roc_builtins = { path = "../builtins" }
indoc = "1.0.3"
bumpalo = { version = "3.8.0", features = ["collections"] }
tempfile = "3.2.0"
libloading = "0.7.1"
target-lexicon = "0.12.2"

View file

@ -1,871 +0,0 @@
#![cfg(all(test, any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
use crate::assert_evals_to;
use indoc::indoc;
#[test]
fn i64_values() {
assert_evals_to!("0", 0, i64);
assert_evals_to!("-0", 0, i64);
assert_evals_to!("-1", -1, i64);
assert_evals_to!("1", 1, i64);
assert_evals_to!("9_000_000_000_000", 9_000_000_000_000, i64);
assert_evals_to!("-9_000_000_000_000", -9_000_000_000_000, i64);
assert_evals_to!("0b1010", 0b1010, i64);
assert_evals_to!("0o17", 0o17, i64);
assert_evals_to!("0x1000_0000_0000_0000", 0x1000_0000_0000_0000, i64);
}
#[test]
fn f64_values() {
assert_evals_to!("0.0", 0.0, f64);
assert_evals_to!("-0.0", 0.0, f64);
assert_evals_to!("1.0", 1.0, f64);
assert_evals_to!("-1.0", -1.0, f64);
assert_evals_to!("3.1415926535897932", 3.141_592_653_589_793, f64);
assert_evals_to!(&format!("{:0.1}", f64::MIN), f64::MIN, f64);
assert_evals_to!(&format!("{:0.1}", f64::MAX), f64::MAX, f64);
}
#[test]
fn gen_add_i64() {
assert_evals_to!(
indoc!(
r#"
1 + 2 + 3
"#
),
6,
i64
);
}
#[test]
fn gen_add_f64() {
assert_evals_to!(
indoc!(
r#"
1.1 + 2.4 + 3
"#
),
6.5,
f64
);
}
#[test]
fn gen_sub_i64() {
assert_evals_to!(
indoc!(
r#"
1 - 2 - 3
"#
),
-4,
i64
);
}
#[test]
fn gen_mul_i64() {
assert_evals_to!(
indoc!(
r#"
2 * 4 * 6
"#
),
48,
i64
);
}
#[test]
fn i64_force_stack() {
// This claims 33 registers. One more than Arm and RISC-V, and many more than x86-64.
assert_evals_to!(
indoc!(
r#"
a = 0
b = 1
c = 2
d = 3
e = 4
f = 5
g = 6
h = 7
i = 8
j = 9
k = 10
l = 11
m = 12
n = 13
o = 14
p = 15
q = 16
r = 17
s = 18
t = 19
u = 20
v = 21
w = 22
x = 23
y = 24
z = 25
aa = 26
ab = 27
ac = 28
ad = 29
ae = 30
af = 31
ag = 32
a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r + s + t + u + v + w + x + y + z + aa + ab + ac + ad + ae + af + ag
"#
),
528,
i64
);
}
#[test]
fn i64_abs() {
assert_evals_to!("Num.abs -6", 6, i64);
assert_evals_to!("Num.abs 7", 7, i64);
assert_evals_to!("Num.abs 0", 0, i64);
assert_evals_to!("Num.abs -0", 0, i64);
assert_evals_to!("Num.abs -1", 1, i64);
assert_evals_to!("Num.abs 1", 1, i64);
assert_evals_to!("Num.abs 9_000_000_000_000", 9_000_000_000_000, i64);
assert_evals_to!("Num.abs -9_000_000_000_000", 9_000_000_000_000, i64);
}
#[test]
fn gen_int_eq() {
assert_evals_to!(
indoc!(
r#"
4 == 4
"#
),
true,
bool
);
assert_evals_to!(
indoc!(
r#"
3 == 4
"#
),
false,
bool
);
}
#[test]
fn gen_basic_fn() {
assert_evals_to!(
indoc!(
r#"
always42 : Num.Num (Num.Integer Num.Signed64) -> Num.Num (Num.Integer Num.Signed64)
always42 = \_ -> 42
always42 5
"#
),
42,
i64
);
}
#[test]
fn gen_wrap_add_nums() {
assert_evals_to!(
indoc!(
r#"
add2 = \num1, num2 -> num1 + num2
add2 4 5
"#
),
9,
i64
);
}
#[test]
fn gen_wrap_add_nums_force_stack() {
assert_evals_to!(
indoc!(
r#"
add9 = \num1, num2, num3, num4, num5, num6, num7, num8, num9 -> num1 + num2 + num3 + num4 + num5 + num6 + num7 + num8 + num9
add9 1 2 3 4 5 6 7 8 9
"#
),
45,
i64
);
}
#[test]
fn pow_int() {
assert_evals_to!("Num.powInt 2 3", 8, i64);
}
#[test]
fn acos() {
assert_evals_to!("Num.acos 0.5", 1.0471975511965979, f64);
}
#[test]
fn asin() {
assert_evals_to!("Num.asin 0.5", 0.5235987755982989, f64);
}
#[test]
fn atan() {
assert_evals_to!("Num.atan 10", 1.4711276743037347, f64);
}
#[test]
fn gen_if_fn() {
assert_evals_to!(
indoc!(
r#"
limitedNegate = \num ->
x =
if num == 1 then
-1
else if num == -1 then
1
else
num
x
limitedNegate 1
"#
),
-1,
i64
);
}
#[test]
fn gen_fib_fn() {
assert_evals_to!(
indoc!(
r#"
fib = \n ->
if n == 0 then
0
else if n == 1 then
1
else
(fib (n - 1)) + (fib (n - 2))
fib 10
"#
),
55,
i64
);
}
#[test]
fn gen_fast_fib_fn() {
assert_evals_to!(
indoc!(
r#"
fib = \n, a, b ->
if n == 0 then
a
else
fib (n - 1) b (a + b)
fib 10 0 1
"#
),
55,
i64
);
}
#[test]
fn f64_abs() {
assert_evals_to!("Num.abs -4.7", 4.7, f64);
assert_evals_to!("Num.abs 5.8", 5.8, f64);
}
#[test]
fn f64_round() {
assert_evals_to!("Num.round 3.6", 4, i64);
assert_evals_to!("Num.round 3.4", 3, i64);
assert_evals_to!("Num.round 2.5", 3, i64);
assert_evals_to!("Num.round -2.3", -2, i64);
assert_evals_to!("Num.round -2.5", -3, i64);
}
// #[test]
// fn f64_sqrt() {
// // FIXME this works with normal types, but fails when checking uniqueness types
// assert_evals_to!(
// indoc!(
// r#"
// when Num.sqrt 100 is
// Ok val -> val
// Err _ -> -1
// "#
// ),
// 10.0,
// f64
// );
// }
// #[test]
// fn gen_float_eq() {
// assert_evals_to!(
// indoc!(
// r#"
// 1.0 == 1.0
// "#
// ),
// true,
// bool
// );
// }
// #[test]
// fn gen_div_f64() {
// // FIXME this works with normal types, but fails when checking uniqueness types
// assert_evals_to!(
// indoc!(
// r#"
// when 48 / 2 is
// Ok val -> val
// Err _ -> -1
// "#
// ),
// 24.0,
// f64
// );
// }
// #[test]
// fn gen_int_neq() {
// assert_evals_to!(
// indoc!(
// r#"
// 4 != 5
// "#
// ),
// true,
// bool
// );
// }
// #[test]
// fn gen_wrap_int_neq() {
// assert_evals_to!(
// indoc!(
// r#"
// wrappedNotEq : a, a -> Bool
// wrappedNotEq = \num1, num2 ->
// num1 != num2
// wrappedNotEq 2 3
// "#
// ),
// true,
// bool
// );
// }
// #[test]
// fn gen_sub_f64() {
// assert_evals_to!(
// indoc!(
// r#"
// 1.5 - 2.4 - 3
// "#
// ),
// -3.9,
// f64
// );
// }
// #[test]
// fn gen_div_i64() {
// assert_evals_to!(
// indoc!(
// r#"
// when 1000 // 10 is
// Ok val -> val
// Err _ -> -1
// "#
// ),
// 100,
// i64
// );
// }
// #[test]
// fn gen_div_by_zero_i64() {
// assert_evals_to!(
// indoc!(
// r#"
// when 1000 // 0 is
// Err DivByZero -> 99
// _ -> -24
// "#
// ),
// 99,
// i64
// );
// }
// #[test]
// fn gen_rem_i64() {
// assert_evals_to!(
// indoc!(
// r#"
// when Num.rem 8 3 is
// Ok val -> val
// Err _ -> -1
// "#
// ),
// 2,
// i64
// );
// }
// #[test]
// fn gen_rem_div_by_zero_i64() {
// assert_evals_to!(
// indoc!(
// r#"
// when Num.rem 8 0 is
// Err DivByZero -> 4
// Ok _ -> -23
// "#
// ),
// 4,
// i64
// );
// }
// #[test]
// fn gen_is_zero_i64() {
// assert_evals_to!("Num.isZero 0", true, bool);
// assert_evals_to!("Num.isZero 1", false, bool);
// }
// #[test]
// fn gen_is_positive_i64() {
// assert_evals_to!("Num.isPositive 0", false, bool);
// assert_evals_to!("Num.isPositive 1", true, bool);
// assert_evals_to!("Num.isPositive -5", false, bool);
// }
// #[test]
// fn gen_is_negative_i64() {
// assert_evals_to!("Num.isNegative 0", false, bool);
// assert_evals_to!("Num.isNegative 3", false, bool);
// assert_evals_to!("Num.isNegative -2", true, bool);
// }
// #[test]
// fn gen_is_positive_f64() {
// assert_evals_to!("Num.isPositive 0.0", false, bool);
// assert_evals_to!("Num.isPositive 4.7", true, bool);
// assert_evals_to!("Num.isPositive -8.5", false, bool);
// }
// #[test]
// fn gen_is_negative_f64() {
// assert_evals_to!("Num.isNegative 0.0", false, bool);
// assert_evals_to!("Num.isNegative 9.9", false, bool);
// assert_evals_to!("Num.isNegative -4.4", true, bool);
// }
// #[test]
// fn gen_is_zero_f64() {
// assert_evals_to!("Num.isZero 0", true, bool);
// assert_evals_to!("Num.isZero 0_0", true, bool);
// assert_evals_to!("Num.isZero 0.0", true, bool);
// assert_evals_to!("Num.isZero 1", false, bool);
// }
// #[test]
// fn gen_is_odd() {
// assert_evals_to!("Num.isOdd 4", false, bool);
// assert_evals_to!("Num.isOdd 5", true, bool);
// }
// #[test]
// fn gen_is_even() {
// assert_evals_to!("Num.isEven 6", true, bool);
// assert_evals_to!("Num.isEven 7", false, bool);
// }
// #[test]
// fn sin() {
// assert_evals_to!("Num.sin 0", 0.0, f64);
// assert_evals_to!("Num.sin 1.41421356237", 0.9877659459922529, f64);
// }
// #[test]
// fn cos() {
// assert_evals_to!("Num.cos 0", 1.0, f64);
// assert_evals_to!("Num.cos 3.14159265359", -1.0, f64);
// }
// #[test]
// fn tan() {
// assert_evals_to!("Num.tan 0", 0.0, f64);
// assert_evals_to!("Num.tan 1", 1.557407724654902, f64);
// }
// #[test]
// fn lt_i64() {
// assert_evals_to!("1 < 2", true, bool);
// assert_evals_to!("1 < 1", false, bool);
// assert_evals_to!("2 < 1", false, bool);
// assert_evals_to!("0 < 0", false, bool);
// }
// #[test]
// fn lte_i64() {
// assert_evals_to!("1 <= 1", true, bool);
// assert_evals_to!("2 <= 1", false, bool);
// assert_evals_to!("1 <= 2", true, bool);
// assert_evals_to!("0 <= 0", true, bool);
// }
// #[test]
// fn gt_i64() {
// assert_evals_to!("2 > 1", true, bool);
// assert_evals_to!("2 > 2", false, bool);
// assert_evals_to!("1 > 1", false, bool);
// assert_evals_to!("0 > 0", false, bool);
// }
// #[test]
// fn gte_i64() {
// assert_evals_to!("1 >= 1", true, bool);
// assert_evals_to!("1 >= 2", false, bool);
// assert_evals_to!("2 >= 1", true, bool);
// assert_evals_to!("0 >= 0", true, bool);
// }
// #[test]
// fn lt_f64() {
// assert_evals_to!("1.1 < 1.2", true, bool);
// assert_evals_to!("1.1 < 1.1", false, bool);
// assert_evals_to!("1.2 < 1.1", false, bool);
// assert_evals_to!("0.0 < 0.0", false, bool);
// }
// #[test]
// fn lte_f64() {
// assert_evals_to!("1.1 <= 1.1", true, bool);
// assert_evals_to!("1.2 <= 1.1", false, bool);
// assert_evals_to!("1.1 <= 1.2", true, bool);
// assert_evals_to!("0.0 <= 0.0", true, bool);
// }
// #[test]
// fn gt_f64() {
// assert_evals_to!("2.2 > 1.1", true, bool);
// assert_evals_to!("2.2 > 2.2", false, bool);
// assert_evals_to!("1.1 > 2.2", false, bool);
// assert_evals_to!("0.0 > 0.0", false, bool);
// }
// #[test]
// fn gte_f64() {
// assert_evals_to!("1.1 >= 1.1", true, bool);
// assert_evals_to!("1.1 >= 1.2", false, bool);
// assert_evals_to!("1.2 >= 1.1", true, bool);
// assert_evals_to!("0.0 >= 0.0", true, bool);
// }
#[test]
fn gen_order_of_arithmetic_ops() {
assert_evals_to!(
indoc!(
r#"
1 + 3 * 7 - 2
"#
),
20,
i64
);
}
// #[test]
// fn gen_order_of_arithmetic_ops_complex_float() {
// assert_evals_to!(
// indoc!(
// r#"
// 3 - 48 * 2.0
// "#
// ),
// -93.0,
// f64
// );
// }
#[test]
fn if_guard_bind_variable_false() {
assert_evals_to!(
indoc!(
r#"
wrapper = \{} ->
when 10 is
x if x == 5 -> 0
_ -> 42
wrapper {}
"#
),
42,
i64
);
}
#[test]
fn if_guard_bind_variable_true() {
assert_evals_to!(
indoc!(
r#"
wrapper = \{} ->
when 10 is
x if x == 10 -> 42
_ -> 0
wrapper {}
"#
),
42,
i64
);
}
#[test]
fn tail_call_elimination() {
assert_evals_to!(
indoc!(
r#"
sum = \n, accum ->
when n is
0 -> accum
_ -> sum (n - 1) (n + accum)
sum 1_000_000 0
"#
),
500000500000,
i64
);
}
// #[test]
// fn int_negate() {
// assert_evals_to!("Num.neg 123", -123, i64);
// }
// #[test]
// fn gen_wrap_int_neg() {
// assert_evals_to!(
// indoc!(
// r#"
// wrappedNeg = \num -> -num
// wrappedNeg 3
// "#
// ),
// -3,
// i64
// );
// }
// #[test]
// fn int_to_float() {
// assert_evals_to!("Num.toFloat 0x9", 9.0, f64);
// }
// #[test]
// fn num_to_float() {
// assert_evals_to!("Num.toFloat 9", 9.0, f64);
// }
// #[test]
// fn float_to_float() {
// assert_evals_to!("Num.toFloat 0.5", 0.5, f64);
// }
// #[test]
// fn int_compare() {
// assert_evals_to!("Num.compare 0 1", RocOrder::Lt, RocOrder);
// assert_evals_to!("Num.compare 1 1", RocOrder::Eq, RocOrder);
// assert_evals_to!("Num.compare 1 0", RocOrder::Gt, RocOrder);
// }
// #[test]
// fn float_compare() {
// assert_evals_to!("Num.compare 0.01 3.14", RocOrder::Lt, RocOrder);
// assert_evals_to!("Num.compare 3.14 3.14", RocOrder::Eq, RocOrder);
// assert_evals_to!("Num.compare 3.14 0.01", RocOrder::Gt, RocOrder);
// }
// #[test]
// fn pow() {
// assert_evals_to!("Num.pow 2.0 2.0", 4.0, f64);
// }
// #[test]
// fn ceiling() {
// assert_evals_to!("Num.ceiling 1.1", 2, i64);
// }
// #[test]
// fn floor() {
// assert_evals_to!("Num.floor 1.9", 1, i64);
// }
// // #[test]
// // #[should_panic(expected = r#"Roc failed with message: "integer addition overflowed!"#)]
// // fn int_overflow() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // 9_223_372_036_854_775_807 + 1
// // "#
// // ),
// // 0,
// // i64
// // );
// // }
// #[test]
// fn int_add_checked() {
// assert_evals_to!(
// indoc!(
// r#"
// when Num.addChecked 1 2 is
// Ok v -> v
// _ -> -1
// "#
// ),
// 3,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// when Num.addChecked 9_223_372_036_854_775_807 1 is
// Err Overflow -> -1
// Ok v -> v
// "#
// ),
// -1,
// i64
// );
// }
// #[test]
// fn int_add_wrap() {
// assert_evals_to!(
// indoc!(
// r#"
// Num.addWrap 9_223_372_036_854_775_807 1
// "#
// ),
// std::i64::MIN,
// i64
// );
// }
// #[test]
// fn float_add_checked_pass() {
// assert_evals_to!(
// indoc!(
// r#"
// when Num.addChecked 1.0 0.0 is
// Ok v -> v
// Err Overflow -> -1.0
// "#
// ),
// 1.0,
// f64
// );
// }
// #[test]
// fn float_add_checked_fail() {
// assert_evals_to!(
// indoc!(
// r#"
// when Num.addChecked 1.7976931348623157e308 1.7976931348623157e308 is
// Err Overflow -> -1
// Ok v -> v
// "#
// ),
// -1.0,
// f64
// );
// }
// // #[test]
// // #[should_panic(expected = r#"Roc failed with message: "float addition overflowed!"#)]
// // fn float_overflow() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // 1.7976931348623157e308 + 1.7976931348623157e308
// // "#
// // ),
// // 0.0,
// // f64
// // );
// // }
// #[test]
// fn max_i128() {
// assert_evals_to!(
// indoc!(
// r#"
// Num.maxI128
// "#
// ),
// i128::MAX,
// i128
// );
// }
// #[test]
// fn num_max_int() {
// assert_evals_to!(
// indoc!(
// r#"
// Num.maxInt
// "#
// ),
// i64::MAX,
// i64
// );
// }
// #[test]
// fn num_min_int() {
// assert_evals_to!(
// indoc!(
// r#"
// Num.minInt
// "#
// ),
// i64::MIN,
// i64
// );
// }

View file

@ -1,933 +0,0 @@
#![cfg(all(test, any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
use crate::assert_evals_to;
use indoc::indoc;
#[test]
fn basic_record() {
assert_evals_to!(
indoc!(
r#"
{ y: 17, x: 15, z: 19 }.x
"#
),
15,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: 17, z: 19 }.y
"#
),
17,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: 17, z: 19 }.z
"#
),
19,
i64
);
}
#[test]
fn nested_record() {
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.x
"#
),
15,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.a
"#
),
12,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.b
"#
),
15,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.c
"#
),
2,
i64
);
assert_evals_to!(
indoc!(
r#"
{ x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.z
"#
),
19,
i64
);
}
#[test]
fn f64_record() {
assert_evals_to!(
indoc!(
r#"
rec = { y: 17.2, x: 15.1, z: 19.3 }
rec.x
"#
),
15.1,
f64
);
assert_evals_to!(
indoc!(
r#"
rec = { y: 17.2, x: 15.1, z: 19.3 }
rec.y
"#
),
17.2,
f64
);
assert_evals_to!(
indoc!(
r#"
rec = { y: 17.2, x: 15.1, z: 19.3 }
rec.z
"#
),
19.3,
f64
);
}
// #[test]
// fn fn_record() {
// assert_evals_to!(
// indoc!(
// r#"
// getRec = \x -> { y: 17, x, z: 19 }
// (getRec 15).x
// "#
// ),
// 15,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// rec = { x: 15, y: 17, z: 19 }
// rec.y
// "#
// ),
// 17,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// rec = { x: 15, y: 17, z: 19 }
// rec.z
// "#
// ),
// 19,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// rec = { x: 15, y: 17, z: 19 }
// rec.z + rec.x
// "#
// ),
// 34,
// i64
// );
// }
#[test]
fn def_record() {
assert_evals_to!(
indoc!(
r#"
rec = { y: 17, x: 15, z: 19 }
rec.x
"#
),
15,
i64
);
assert_evals_to!(
indoc!(
r#"
rec = { x: 15, y: 17, z: 19 }
rec.y
"#
),
17,
i64
);
assert_evals_to!(
indoc!(
r#"
rec = { x: 15, y: 17, z: 19 }
rec.z
"#
),
19,
i64
);
}
#[test]
fn when_on_record() {
assert_evals_to!(
indoc!(
r#"
when { x: 0x2 } is
{ x } -> x + 3
"#
),
5,
i64
);
}
#[test]
fn when_record_with_guard_pattern() {
assert_evals_to!(
indoc!(
r#"
when { x: 0x2, y: 3.14 } is
{ x: var } -> var + 3
"#
),
5,
i64
);
}
#[test]
fn let_with_record_pattern() {
assert_evals_to!(
indoc!(
r#"
{ x } = { x: 0x2, y: 3.14 }
x
"#
),
2,
i64
);
}
#[test]
fn record_guard_pattern() {
assert_evals_to!(
indoc!(
r#"
when { x: 0x2, y: 3.14 } is
{ x: 0x4 } -> 5
{ x } -> x + 3
"#
),
5,
i64
);
}
#[test]
fn twice_record_access() {
assert_evals_to!(
indoc!(
r#"
x = {a: 0x2, b: 0x3 }
x.a + x.b
"#
),
5,
i64
);
}
#[test]
fn empty_record() {
assert_evals_to!(
indoc!(
r#"
v = {}
v
"#
),
(),
()
);
}
#[test]
fn i64_record1_literal() {
assert_evals_to!(
indoc!(
r#"
{ x: 3 }
"#
),
3,
i64
);
}
// #[test]
// fn i64_record2_literal() {
// assert_evals_to!(
// indoc!(
// r#"
// { x: 3, y: 5 }
// "#
// ),
// (3, 5),
// (i64, i64)
// );
// }
// // #[test]
// // fn i64_record3_literal() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // { x: 3, y: 5, z: 17 }
// // "#
// // ),
// // (3, 5, 17),
// // (i64, i64, i64)
// // );
// // }
// #[test]
// fn f64_record2_literal() {
// assert_evals_to!(
// indoc!(
// r#"
// { x: 3.1, y: 5.1 }
// "#
// ),
// (3.1, 5.1),
// (f64, f64)
// );
// }
// // #[test]
// // fn f64_record3_literal() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // { x: 3.1, y: 5.1, z: 17.1 }
// // "#
// // ),
// // (3.1, 5.1, 17.1),
// // (f64, f64, f64)
// // );
// // }
// // #[test]
// // fn bool_record4_literal() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // record : { a : Bool, b : Bool, c : Bool, d : Bool }
// // record = { a: True, b: True, c : True, d : Bool }
// // record
// // "#
// // ),
// // (true, false, false, true),
// // (bool, bool, bool, bool)
// // );
// // }
// #[test]
// fn i64_record1_literal() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3 }
// "#
// ),
// 3,
// i64
// );
// }
// // #[test]
// // fn i64_record9_literal() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // { a: 3, b: 5, c: 17, d: 1, e: 9, f: 12, g: 13, h: 14, i: 15 }
// // "#
// // ),
// // (3, 5, 17, 1, 9, 12, 13, 14, 15),
// // (i64, i64, i64, i64, i64, i64, i64, i64, i64)
// // );
// // }
// // #[test]
// // fn f64_record3_literal() {
// // assert_evals_to!(
// // indoc!(
// // r#"
// // { x: 3.1, y: 5.1, z: 17.1 }
// // "#
// // ),
// // (3.1, 5.1, 17.1),
// // (f64, f64, f64)
// // );
// // }
// #[test]
// fn bool_literal() {
// assert_evals_to!(
// indoc!(
// r#"
// x : Bool
// x = True
// x
// "#
// ),
// true,
// bool
// );
// }
// #[test]
// fn optional_field_when_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// main =
// a = f { x: Blue, y: 7 }
// b = f { x: Blue }
// c = f { x: Red, y: 11 }
// d = f { x: Red }
// a * b * c * d
// "#
// ),
// 3 * 5 * 7 * 11,
// i64
// );
// }
// #[test]
// fn optional_field_when_use_default_nested() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// a = f { x: Blue, y: 7 }
// b = f { x: Blue }
// c = f { x: Red, y: 11 }
// d = f { x: Red }
// a * b * c * d
// "#
// ),
// 3 * 5 * 7 * 11,
// i64
// );
// }
// #[test]
// fn optional_field_when_no_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// { x ? 10, y } = r
// x + y
// main =
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_when_no_use_default_nested() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// { x ? 10, y } = r
// x + y
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_let_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// { x ? 10, y } = r
// x + y
// main =
// f { y: 9 }
// "#
// ),
// 19,
// i64
// );
// }
// #[test]
// fn optional_field_let_no_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// { x ? 10, y } = r
// x + y
// main =
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_let_no_use_default_nested() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// { x ? 10, y } = r
// x + y
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_function_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \{ x ? 10, y } -> x + y
// f { y: 9 }
// "#
// ),
// 19,
// i64
// );
// }
// #[test]
// #[ignore]
// fn optional_field_function_no_use_default() {
// // blocked on https://github.com/rtfeldman/roc/issues/786
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \{ x ? 10, y } -> x + y
// main =
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// #[ignore]
// fn optional_field_function_no_use_default_nested() {
// // blocked on https://github.com/rtfeldman/roc/issues/786
// assert_evals_to!(
// indoc!(
// r#"
// f = \{ x ? 10, y } -> x + y
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_singleton_record() {
// assert_evals_to!(
// indoc!(
// r#"
// when { x : 4 } is
// { x ? 3 } -> x
// "#
// ),
// 4,
// i64
// );
// }
// #[test]
// fn optional_field_empty_record() {
// assert_evals_to!(
// indoc!(
// r#"
// when { } is
// { x ? 3 } -> x
// "#
// ),
// 3,
// i64
// );
// }
// #[test]
// fn return_record_2() {
// assert_evals_to!(
// indoc!(
// r#"
// { x: 3, y: 5 }
// "#
// ),
// [3, 5],
// [i64; 2]
// );
// }
// #[test]
// fn return_record_3() {
// assert_evals_to!(
// indoc!(
// r#"
// { x: 3, y: 5, z: 4 }
// "#
// ),
// (3, 5, 4),
// (i64, i64, i64)
// );
// }
// #[test]
// fn return_record_4() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3, b: 5, c: 4, d: 2 }
// "#
// ),
// [3, 5, 4, 2],
// [i64; 4]
// );
// }
// #[test]
// fn return_record_5() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3, b: 5, c: 4, d: 2, e: 1 }
// "#
// ),
// [3, 5, 4, 2, 1],
// [i64; 5]
// );
// }
// #[test]
// fn return_record_6() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3, b: 5, c: 4, d: 2, e: 1, f: 7 }
// "#
// ),
// [3, 5, 4, 2, 1, 7],
// [i64; 6]
// );
// }
// #[test]
// fn return_record_7() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3, b: 5, c: 4, d: 2, e: 1, f: 7, g: 8 }
// "#
// ),
// [3, 5, 4, 2, 1, 7, 8],
// [i64; 7]
// );
// }
// #[test]
// fn return_record_float_int() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 3.14, b: 0x1 }
// "#
// ),
// (3.14, 0x1),
// (f64, i64)
// );
// }
// #[test]
// fn return_record_int_float() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 0x1, b: 3.14 }
// "#
// ),
// (0x1, 3.14),
// (i64, f64)
// );
// }
// #[test]
// fn return_record_float_float() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 6.28, b: 3.14 }
// "#
// ),
// (6.28, 3.14),
// (f64, f64)
// );
// }
// #[test]
// fn return_record_float_float_float() {
// assert_evals_to!(
// indoc!(
// r#"
// { a: 6.28, b: 3.14, c: 0.1 }
// "#
// ),
// (6.28, 3.14, 0.1),
// (f64, f64, f64)
// );
// }
// #[test]
// fn return_nested_record() {
// assert_evals_to!(
// indoc!(
// r#"
// { flag: 0x0, payload: { a: 6.28, b: 3.14, c: 0.1 } }
// "#
// ),
// (0x0, (6.28, 3.14, 0.1)),
// (i64, (f64, f64, f64))
// );
// }
// #[test]
// fn accessor() {
// assert_evals_to!(
// indoc!(
// r#"
// .foo { foo: 4 } + .foo { bar: 6.28, foo: 3 }
// "#
// ),
// 7,
// i64
// );
// }
// #[test]
// fn accessor_single_element_record() {
// assert_evals_to!(
// indoc!(
// r#"
// .foo { foo: 4 }
// "#
// ),
// 4,
// i64
// );
// }
// #[test]
// fn update_record() {
// assert_evals_to!(
// indoc!(
// r#"
// rec = { foo: 42, bar: 6 }
// { rec & foo: rec.foo + 1 }
// "#
// ),
// (6, 43),
// (i64, i64)
// );
// }
#[test]
fn update_single_element_record() {
assert_evals_to!(
indoc!(
r#"
rec = { foo: 42}
{ rec & foo: rec.foo + 1 }
"#
),
43,
i64
);
}
// #[test]
// fn booleans_in_record() {
// assert_evals_to!(
// indoc!("{ x: 1 == 1, y: 1 == 1 }"),
// (true, true),
// (bool, bool)
// );
// assert_evals_to!(
// indoc!("{ x: 1 != 1, y: 1 == 1 }"),
// (false, true),
// (bool, bool)
// );
// assert_evals_to!(
// indoc!("{ x: 1 == 1, y: 1 != 1 }"),
// (true, false),
// (bool, bool)
// );
// assert_evals_to!(
// indoc!("{ x: 1 != 1, y: 1 != 1 }"),
// (false, false),
// (bool, bool)
// );
// }
// #[test]
// fn alignment_in_record() {
// assert_evals_to!(
// indoc!("{ c: 32, b: if True then Red else if True then Green else Blue, a: 1 == 1 }"),
// (32i64, true, 2u8),
// (i64, bool, u8)
// );
// }
// #[test]
// fn blue_and_present() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// f { x: Blue, y: 7 }
// "#
// ),
// 7,
// i64
// );
// }
// #[test]
// fn blue_and_absent() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// f { x: Blue }
// "#
// ),
// 3,
// i64
// );
// }

View file

@ -1,950 +0,0 @@
#![cfg(all(test, any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
//use indoc::indoc;
use crate::assert_evals_to;
// use roc_std::{RocList, RocStr};
// #[test]
// fn str_split_bigger_delimiter_small_str() {
// assert_evals_to!(
// indoc!(
// r#"
// List.len (Str.split "hello" "JJJJ there")
// "#
// ),
// 1,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// when List.first (Str.split "JJJ" "JJJJ there") is
// Ok str ->
// Str.countGraphemes str
// _ ->
// -1
// "#
// ),
// 3,
// i64
// );
// }
// #[test]
// fn str_split_str_concat_repeated() {
// assert_evals_to!(
// indoc!(
// r#"
// when List.first (Str.split "JJJJJ" "JJJJ there") is
// Ok str ->
// str
// |> Str.concat str
// |> Str.concat str
// |> Str.concat str
// |> Str.concat str
// _ ->
// "Not Str!"
// "#
// ),
// RocStr::from_slice(b"JJJJJJJJJJJJJJJJJJJJJJJJJ"),
// RocStr
// );
// }
// #[test]
// fn str_split_small_str_bigger_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// when
// List.first
// (Str.split "JJJ" "0123456789abcdefghi")
// is
// Ok str -> str
// _ -> ""
// "#
// ),
// RocStr::from_slice(b"JJJ"),
// RocStr
// );
// }
// #[test]
// fn str_split_big_str_small_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "01234567789abcdefghi?01234567789abcdefghi" "?"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"01234567789abcdefghi"),
// RocStr::from_slice(b"01234567789abcdefghi")
// ]),
// RocList<RocStr>
// );
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "01234567789abcdefghi 3ch 01234567789abcdefghi" "3ch"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"01234567789abcdefghi "),
// RocStr::from_slice(b" 01234567789abcdefghi")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_small_str_small_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "J!J!J" "!"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"J"),
// RocStr::from_slice(b"J"),
// RocStr::from_slice(b"J")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_bigger_delimiter_big_strs() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "string to split is shorter"
// "than the delimiter which happens to be very very long"
// "#
// ),
// RocList::from_slice(&[RocStr::from_slice(b"string to split is shorter")]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_empty_strs() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "" ""
// "#
// ),
// RocList::from_slice(&[RocStr::from_slice(b"")]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_minimal_example() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "a," ","
// "#
// ),
// RocList::from_slice(&[RocStr::from_slice(b"a"), RocStr::from_slice(b"")]),
// RocList<RocStr>
// )
// }
// #[test]
// fn str_split_small_str_big_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "1---- ---- ---- ---- ----2---- ---- ---- ---- ----"
// "---- ---- ---- ---- ----"
// |> List.len
// "#
// ),
// 3,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "1---- ---- ---- ---- ----2---- ---- ---- ---- ----"
// "---- ---- ---- ---- ----"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"1"),
// RocStr::from_slice(b"2"),
// RocStr::from_slice(b"")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_small_str_20_char_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "3|-- -- -- -- -- -- |4|-- -- -- -- -- -- |"
// "|-- -- -- -- -- -- |"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"3"),
// RocStr::from_slice(b"4"),
// RocStr::from_slice(b"")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_concat_big_to_big() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.concat
// "First string that is fairly long. Longer strings make for different errors. "
// "Second string that is also fairly long. Two long strings test things that might not appear with short strings."
// "#
// ),
// RocStr::from_slice(b"First string that is fairly long. Longer strings make for different errors. Second string that is also fairly long. Two long strings test things that might not appear with short strings."),
// RocStr
// );
// }
#[test]
fn small_str_literal() {
assert_evals_to!(
"\"JJJJJJJJJJJJJJJ\"",
[
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0b1000_1111
],
[u8; 16]
);
}
// #[test]
// fn small_str_zeroed_literal() {
// // Verifies that we zero out unused bytes in the string.
// // This is important so that string equality tests don't randomly
// // fail due to unused memory being there!
// assert_evals_to!(
// "\"J\"",
// [
// 0x4a,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0b1000_0001
// ],
// [u8; 16]
// );
// }
#[test]
fn small_str_concat_empty_first_arg() {
assert_evals_to!(
r#"Str.concat "" "JJJJJJJJJJJJJJJ""#,
[
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0b1000_1111
],
[u8; 16]
);
}
#[test]
fn small_str_concat_empty_second_arg() {
assert_evals_to!(
r#"Str.concat "JJJJJJJJJJJJJJJ" """#,
[
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0b1000_1111
],
[u8; 16]
);
}
// #[test]
// fn small_str_concat_small_to_big() {
// assert_evals_to!(
// r#"Str.concat "abc" " this is longer than 15 chars""#,
// RocStr::from_slice(b"abc this is longer than 15 chars"),
// RocStr
// );
// }
#[test]
fn small_str_concat_small_to_small_staying_small() {
assert_evals_to!(
r#"Str.concat "J" "JJJJJJJJJJJJJJ""#,
[
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0b1000_1111
],
[u8; 16]
);
}
// #[test]
// fn small_str_concat_small_to_small_overflow_to_big() {
// assert_evals_to!(
// r#"Str.concat "abcdefghijklm" "nopqrstuvwxyz""#,
// RocStr::from_slice(b"abcdefghijklmnopqrstuvwxyz"),
// RocStr
// );
// }
// #[test]
// fn str_concat_empty() {
// assert_evals_to!(r#"Str.concat "" """#, RocStr::default(), RocStr);
// }
// #[test]
// fn small_str_is_empty() {
// assert_evals_to!(r#"Str.isEmpty "abc""#, false, bool);
// }
// #[test]
// fn big_str_is_empty() {
// assert_evals_to!(
// r#"Str.isEmpty "this is more than 15 chars long""#,
// false,
// bool
// );
// }
// #[test]
// fn empty_str_is_empty() {
// assert_evals_to!(r#"Str.isEmpty """#, true, bool);
// }
// #[test]
// fn str_starts_with() {
// assert_evals_to!(r#"Str.startsWith "hello world" "hell""#, true, bool);
// assert_evals_to!(r#"Str.startsWith "hello world" """#, true, bool);
// assert_evals_to!(r#"Str.startsWith "nope" "hello world""#, false, bool);
// assert_evals_to!(r#"Str.startsWith "hell" "hello world""#, false, bool);
// assert_evals_to!(r#"Str.startsWith "" "hello world""#, false, bool);
// }
// #[test]
// fn str_starts_with_code_point() {
// assert_evals_to!(
// &format!(r#"Str.startsWithCodePt "foobar" {}"#, 'f' as u32),
// true,
// bool
// );
// assert_evals_to!(
// &format!(r#"Str.startsWithCodePt "zoobar" {}"#, 'f' as u32),
// false,
// bool
// );
// }
// #[test]
// fn str_ends_with() {
// assert_evals_to!(r#"Str.endsWith "hello world" "world""#, true, bool);
// assert_evals_to!(r#"Str.endsWith "nope" "hello world""#, false, bool);
// assert_evals_to!(r#"Str.endsWith "" "hello world""#, false, bool);
// }
// #[test]
// fn str_count_graphemes_small_str() {
// assert_evals_to!(r#"Str.countGraphemes "å🤔""#, 2, usize);
// }
// #[test]
// fn str_count_graphemes_three_js() {
// assert_evals_to!(r#"Str.countGraphemes "JJJ""#, 3, usize);
// }
// #[test]
// fn str_count_graphemes_big_str() {
// assert_evals_to!(
// r#"Str.countGraphemes "6🤔å🤔e¥🤔çppkd🙃1jdal🦯asdfa∆ltråø˚waia8918.,🏅jjc""#,
// 45,
// usize
// );
// }
// #[test]
// fn str_starts_with_same_big_str() {
// assert_evals_to!(
// r#"Str.startsWith "123456789123456789" "123456789123456789""#,
// true,
// bool
// );
// }
// #[test]
// fn str_starts_with_different_big_str() {
// assert_evals_to!(
// r#"Str.startsWith "12345678912345678910" "123456789123456789""#,
// true,
// bool
// );
// }
// #[test]
// fn str_starts_with_same_small_str() {
// assert_evals_to!(r#"Str.startsWith "1234" "1234""#, true, bool);
// }
// #[test]
// fn str_starts_with_different_small_str() {
// assert_evals_to!(r#"Str.startsWith "1234" "12""#, true, bool);
// }
// #[test]
// fn str_starts_with_false_small_str() {
// assert_evals_to!(r#"Str.startsWith "1234" "23""#, false, bool);
// }
// #[test]
// fn str_from_int() {
// assert_evals_to!(
// r#"Str.fromInt 1234"#,
// roc_std::RocStr::from_slice("1234".as_bytes()),
// roc_std::RocStr
// );
// assert_evals_to!(
// r#"Str.fromInt 0"#,
// roc_std::RocStr::from_slice("0".as_bytes()),
// roc_std::RocStr
// );
// assert_evals_to!(
// r#"Str.fromInt -1"#,
// roc_std::RocStr::from_slice("-1".as_bytes()),
// roc_std::RocStr
// );
// let max = format!("{}", i64::MAX);
// assert_evals_to!(
// r#"Str.fromInt Num.maxInt"#,
// RocStr::from_slice(max.as_bytes()),
// RocStr
// );
// let min = format!("{}", i64::MIN);
// assert_evals_to!(
// r#"Str.fromInt Num.minInt"#,
// RocStr::from_slice(min.as_bytes()),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_single_ascii() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_many_ascii() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 99, 0x7E ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("abc~".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_single_unicode() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xE2, 0x88, 0x86 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("∆".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_many_unicode() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xE2, 0x88, 0x86, 0xC5, 0x93, 0xC2, 0xAC ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("∆œ¬".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_single_grapheme() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("💖".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_many_grapheme() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96, 0xF0, 0x9F, 0xA4, 0xA0, 0xF0, 0x9F, 0x9A, 0x80 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("💖🤠🚀".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_all() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96, 98, 0xE2, 0x88, 0x86 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("💖b∆".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_invalid_start_byte() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 0x80, 99 ] is
// Err (BadUtf8 InvalidStartByte byteIndex) ->
// if byteIndex == 2 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_unexpected_end_of_sequence() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 99, 0xC2 ] is
// Err (BadUtf8 UnexpectedEndOfSequence byteIndex) ->
// if byteIndex == 3 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_expected_continuation() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 99, 0xC2, 0x00 ] is
// Err (BadUtf8 ExpectedContinuation byteIndex) ->
// if byteIndex == 3 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_overlong_encoding() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 0xF0, 0x80, 0x80, 0x80 ] is
// Err (BadUtf8 OverlongEncoding byteIndex) ->
// if byteIndex == 1 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_codepoint_too_large() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 0xF4, 0x90, 0x80, 0x80 ] is
// Err (BadUtf8 CodepointTooLarge byteIndex) ->
// if byteIndex == 1 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_surrogate_half() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 0xED, 0xA0, 0x80 ] is
// Err (BadUtf8 EncodesSurrogateHalf byteIndex) ->
// if byteIndex == 2 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_equality() {
// assert_evals_to!(r#""a" == "a""#, true, bool);
// assert_evals_to!(
// r#""loremipsumdolarsitamet" == "loremipsumdolarsitamet""#,
// true,
// bool
// );
// assert_evals_to!(r#""a" != "b""#, true, bool);
// assert_evals_to!(r#""a" == "b""#, false, bool);
// }
// #[test]
// fn str_clone() {
// use roc_std::RocStr;
// let long = RocStr::from_slice("loremipsumdolarsitamet".as_bytes());
// let short = RocStr::from_slice("x".as_bytes());
// let empty = RocStr::from_slice("".as_bytes());
// debug_assert_eq!(long.clone(), long);
// debug_assert_eq!(short.clone(), short);
// debug_assert_eq!(empty.clone(), empty);
// }
// #[test]
// fn nested_recursive_literal() {
// assert_evals_to!(
// indoc!(
// r#"
// Expr : [ Add Expr Expr, Val I64, Var I64 ]
// expr : Expr
// expr = Add (Add (Val 3) (Val 1)) (Add (Val 1) (Var 1))
// printExpr : Expr -> Str
// printExpr = \e ->
// when e is
// Add a b ->
// "Add ("
// |> Str.concat (printExpr a)
// |> Str.concat ") ("
// |> Str.concat (printExpr b)
// |> Str.concat ")"
// Val v -> "Val " |> Str.concat (Str.fromInt v)
// Var v -> "Var " |> Str.concat (Str.fromInt v)
// printExpr expr
// "#
// ),
// RocStr::from_slice(b"Add (Add (Val 3) (Val 1)) (Add (Val 1) (Var 1))"),
// RocStr
// );
// }
// #[test]
// fn str_join_comma_small() {
// assert_evals_to!(
// r#"Str.joinWith ["1", "2"] ", " "#,
// RocStr::from("1, 2"),
// RocStr
// );
// }
// #[test]
// fn str_join_comma_big() {
// assert_evals_to!(
// r#"Str.joinWith ["10000000", "2000000", "30000000"] ", " "#,
// RocStr::from("10000000, 2000000, 30000000"),
// RocStr
// );
// }
// #[test]
// fn str_join_comma_single() {
// assert_evals_to!(r#"Str.joinWith ["1"] ", " "#, RocStr::from("1"), RocStr);
// }
// #[test]
// fn str_from_float() {
// assert_evals_to!(r#"Str.fromFloat 3.14"#, RocStr::from("3.14"), RocStr);
// }
// #[test]
// fn str_to_utf8() {
// assert_evals_to!(
// r#"Str.toUtf8 "hello""#,
// RocList::from_slice(&[104, 101, 108, 108, 111]),
// RocList<u8>
// );
// assert_evals_to!(
// r#"Str.toUtf8 "this is a long string""#,
// RocList::from_slice(&[
// 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 108, 111, 110, 103, 32, 115, 116,
// 114, 105, 110, 103
// ]),
// RocList<u8>
// );
// }
// #[test]
// fn str_from_utf8_range() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { count: 5, start: 0 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("hello"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_slice() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { count: 4, start: 1 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("ello"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_slice_not_end() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { count: 3, start: 1 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("ell"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_order_does_not_matter() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 1, count: 3 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("ell"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_out_of_bounds_start_value() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 7, count: 3 } is
// Ok _ -> ""
// Err (BadUtf8 _ _) -> ""
// Err OutOfBounds -> "out of bounds"
// "#
// ),
// RocStr::from("out of bounds"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_count_too_high() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 0, count: 6 } is
// Ok _ -> ""
// Err (BadUtf8 _ _) -> ""
// Err OutOfBounds -> "out of bounds"
// "#
// ),
// RocStr::from("out of bounds"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_count_too_high_for_start() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 4, count: 3 } is
// Ok _ -> ""
// Err (BadUtf8 _ _) -> ""
// Err OutOfBounds -> "out of bounds"
// "#
// ),
// RocStr::from("out of bounds"),
// RocStr
// );
// }

View file

@ -1,44 +0,0 @@
extern crate bumpalo;
#[macro_use]
pub mod eval;
/// Used in the with_larger_debug_stack() function, for tests that otherwise
/// run out of stack space in debug builds (but don't in --release builds)
#[allow(dead_code)]
const EXPANDED_STACK_SIZE: usize = 8 * 1024 * 1024;
/// Without this, some tests pass in `cargo test --release` but fail without
/// the --release flag because they run out of stack space. This increases
/// stack size for debug builds only, while leaving the stack space at the default
/// amount for release builds.
#[allow(dead_code)]
#[cfg(debug_assertions)]
pub fn with_larger_debug_stack<F>(run_test: F)
where
F: FnOnce(),
F: Send,
F: 'static,
{
std::thread::Builder::new()
.stack_size(EXPANDED_STACK_SIZE)
.spawn(run_test)
.expect("Error while spawning expanded dev stack size thread")
.join()
.expect("Error while joining expanded dev stack size thread")
}
/// In --release builds, don't increase the stack size. Run the test normally.
/// This way, we find out if any of our tests are blowing the stack even after
/// optimizations in release builds.
#[allow(dead_code)]
#[cfg(not(debug_assertions))]
#[inline(always)]
pub fn with_larger_debug_stack<F>(run_test: F)
where
F: FnOnce() -> (),
F: Send,
F: 'static,
{
run_test()
}

View file

@ -1,4 +0,0 @@
pub mod dev_num;
pub mod dev_records;
pub mod dev_str;
mod helpers;

View file

@ -11,6 +11,8 @@ path = "src/tests.rs"
[dev-dependencies]
roc_gen_llvm = { path = "../gen_llvm" }
roc_gen_dev = { path = "../gen_dev" }
roc_gen_wasm = { path = "../gen_wasm" }
roc_collections = { path = "../collections" }
roc_region = { path = "../region" }
roc_module = { path = "../module" }
@ -27,7 +29,6 @@ roc_can = { path = "../can" }
roc_parse = { path = "../parse" }
roc_build = { path = "../build" }
roc_std = { path = "../../roc_std" }
test_wasm_util = { path = "../test_wasm_util" }
im = "15.0.0"
im-rc = "15.0.0"
bumpalo = { version = "3.8.0", features = ["collections"] }
@ -42,5 +43,8 @@ tempfile = "3.2.0"
indoc = "1.0.3"
[features]
default = []
default = ["gen-llvm"]
gen-llvm = []
gen-dev = []
gen-wasm = []
wasm-cli-run = []

View file

@ -0,0 +1,28 @@
# Running our CodeGen tests
Our code generation tests are all in this crate. Feature flags are used to run the tests with a specific backend. For convenience, some aliases are added in `.cargo/config`:
```toml
[alias]
test-gen-llvm = "test -p test_gen"
test-gen-dev = "test -p test_gen --no-default-features --features gen-dev"
test-gen-wasm = "test -p test_gen --no-default-features --features gen-wasm"
```
So we can run:
```
cargo test-gen-llvm
```
To run the gen tests with the LLVM backend. To filter tests, append a filter like so:
```
> cargo test-gen-wasm wasm_str::small
Finished test [unoptimized + debuginfo] target(s) in 0.13s
Running src/tests.rs (target/debug/deps/test_gen-b4ad63a9dd50f050)
running 2 tests
test wasm_str::small_str_literal ... ok
test wasm_str::small_str_zeroed_literal ... ok
```

View file

@ -1,196 +1,218 @@
#[cfg(test)]
mod gen_compare {
use crate::assert_evals_to;
// use crate::assert_wasm_evals_to as assert_evals_to;
use indoc::indoc;
#![cfg(not(feature = "gen-wasm"))]
#[test]
fn eq_i64() {
assert_evals_to!(
indoc!(
r#"
#[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 crate::assert_wasm_evals_to as assert_evals_to;
use indoc::indoc;
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn eq_i64() {
assert_evals_to!(
indoc!(
r#"
i : I64
i = 1
i == i
"#
),
true,
bool
);
}
),
true,
bool
);
}
#[test]
fn neq_i64() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn neq_i64() {
assert_evals_to!(
indoc!(
r#"
i : I64
i = 1
i != i
"#
),
false,
bool
);
}
),
false,
bool
);
}
#[test]
fn eq_u64() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn eq_u64() {
assert_evals_to!(
indoc!(
r#"
i : U64
i = 1
i == i
"#
),
true,
bool
);
}
),
true,
bool
);
}
#[test]
fn neq_u64() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn neq_u64() {
assert_evals_to!(
indoc!(
r#"
i : U64
i = 1
i != i
"#
),
false,
bool
);
}
),
false,
bool
);
}
#[test]
fn eq_f64() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn eq_f64() {
assert_evals_to!(
indoc!(
r#"
i : F64
i = 1
i == i
"#
),
true,
bool
);
}
),
true,
bool
);
}
#[test]
fn neq_f64() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn neq_f64() {
assert_evals_to!(
indoc!(
r#"
i : F64
i = 1
i != i
"#
),
false,
bool
);
}
),
false,
bool
);
}
#[test]
fn eq_bool_tag() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn eq_bool_tag() {
assert_evals_to!(
indoc!(
r#"
true : Bool
true = True
true == True
"#
),
true,
bool
);
}
),
true,
bool
);
}
#[test]
fn neq_bool_tag() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn neq_bool_tag() {
assert_evals_to!(
indoc!(
r#"
true : Bool
true = True
true == False
"#
),
false,
bool
);
}
),
false,
bool
);
}
#[test]
fn empty_record() {
assert_evals_to!("{} == {}", true, bool);
assert_evals_to!("{} != {}", false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn empty_record() {
assert_evals_to!("{} == {}", true, bool);
assert_evals_to!("{} != {}", false, bool);
}
#[test]
fn unit() {
assert_evals_to!("Unit == Unit", true, bool);
assert_evals_to!("Unit != Unit", false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn unit() {
assert_evals_to!("Unit == Unit", true, bool);
assert_evals_to!("Unit != Unit", false, bool);
}
#[test]
fn newtype() {
assert_evals_to!("Identity 42 == Identity 42", true, bool);
assert_evals_to!("Identity 42 != Identity 42", false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn newtype() {
assert_evals_to!("Identity 42 == Identity 42", true, bool);
assert_evals_to!("Identity 42 != Identity 42", false, bool);
}
#[test]
fn small_str() {
assert_evals_to!("\"aaa\" == \"aaa\"", true, bool);
assert_evals_to!("\"aaa\" == \"bbb\"", false, bool);
assert_evals_to!("\"aaa\" != \"aaa\"", false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn small_str() {
assert_evals_to!("\"aaa\" == \"aaa\"", true, bool);
assert_evals_to!("\"aaa\" == \"bbb\"", false, bool);
assert_evals_to!("\"aaa\" != \"aaa\"", false, bool);
}
#[test]
fn large_str() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn large_str() {
assert_evals_to!(
indoc!(
r#"
x = "Unicode can represent text values which span multiple languages"
y = "Unicode can represent text values which span multiple languages"
x == y
"#
),
true,
bool
);
),
true,
bool
);
assert_evals_to!(
indoc!(
r#"
assert_evals_to!(
indoc!(
r#"
x = "Unicode can represent text values which span multiple languages"
y = "Here are some valid Roc strings"
x != y
"#
),
true,
bool
);
}
),
true,
bool
);
}
#[test]
fn eq_result_tag_true() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn eq_result_tag_true() {
assert_evals_to!(
indoc!(
r#"
x : Result I64 I64
x = Ok 1
@ -199,17 +221,18 @@ mod gen_compare {
x == y
"#
),
true,
bool
);
}
),
true,
bool
);
}
#[test]
fn eq_result_tag_false() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn eq_result_tag_false() {
assert_evals_to!(
indoc!(
r#"
x : Result I64 I64
x = Ok 1
@ -218,17 +241,18 @@ mod gen_compare {
x == y
"#
),
false,
bool
);
}
),
false,
bool
);
}
#[test]
fn eq_expr() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn eq_expr() {
assert_evals_to!(
indoc!(
r#"
Expr : [ Add Expr Expr, Mul Expr Expr, Val I64, Var I64 ]
x : Expr
@ -239,17 +263,18 @@ mod gen_compare {
x == y
"#
),
true,
bool
);
}
),
true,
bool
);
}
#[test]
fn eq_linked_list() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn eq_linked_list() {
assert_evals_to!(
indoc!(
r#"
LinkedList a : [ Nil, Cons a (LinkedList a) ]
x : LinkedList I64
@ -260,14 +285,14 @@ mod gen_compare {
x == y
"#
),
true,
bool
);
),
true,
bool
);
assert_evals_to!(
indoc!(
r#"
assert_evals_to!(
indoc!(
r#"
LinkedList a : [ Nil, Cons a (LinkedList a) ]
x : LinkedList I64
@ -278,14 +303,14 @@ mod gen_compare {
x == y
"#
),
true,
bool
);
),
true,
bool
);
assert_evals_to!(
indoc!(
r#"
assert_evals_to!(
indoc!(
r#"
LinkedList a : [ Nil, Cons a (LinkedList a) ]
x : LinkedList I64
@ -296,17 +321,18 @@ mod gen_compare {
x == y
"#
),
true,
bool
);
}
),
true,
bool
);
}
#[test]
fn eq_linked_list_false() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn eq_linked_list_false() {
assert_evals_to!(
indoc!(
r#"
LinkedList a : [ Nil, Cons a (LinkedList a) ]
x : LinkedList I64
@ -317,17 +343,18 @@ mod gen_compare {
y == x
"#
),
false,
bool
);
}
),
false,
bool
);
}
#[test]
fn eq_nullable_expr() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn eq_nullable_expr() {
assert_evals_to!(
indoc!(
r#"
Expr : [ Add Expr Expr, Mul Expr Expr, Val I64, Empty ]
x : Expr
@ -338,17 +365,18 @@ mod gen_compare {
x != y
"#
),
true,
bool
);
}
),
true,
bool
);
}
#[test]
fn eq_rosetree() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn eq_rosetree() {
assert_evals_to!(
indoc!(
r#"
Rose a : [ Rose (List (Rose a)) ]
x : Rose I64
@ -359,14 +387,14 @@ mod gen_compare {
x == y
"#
),
true,
bool
);
),
true,
bool
);
assert_evals_to!(
indoc!(
r#"
assert_evals_to!(
indoc!(
r#"
Rose a : [ Rose (List (Rose a)) ]
x : Rose I64
@ -377,20 +405,21 @@ mod gen_compare {
x != y
"#
),
false,
bool
);
}
),
false,
bool
);
}
#[test]
#[ignore]
fn rosetree_with_tag() {
// currently stack overflows in type checking
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn rosetree_with_tag() {
// currently stack overflows in type checking
assert_evals_to!(
indoc!(
r#"
assert_evals_to!(
indoc!(
r#"
Rose a : [ Rose (Result (List (Rose a)) I64) ]
x : Rose I64
@ -401,53 +430,60 @@ mod gen_compare {
x == y
"#
),
true,
bool
);
}
),
true,
bool
);
}
#[test]
fn list_eq_empty() {
assert_evals_to!("[] == []", true, bool);
assert_evals_to!("[] != []", false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn list_eq_empty() {
assert_evals_to!("[] == []", true, bool);
assert_evals_to!("[] != []", false, bool);
}
#[test]
fn list_eq_by_length() {
assert_evals_to!("[1] == []", false, bool);
assert_evals_to!("[] == [1]", false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn list_eq_by_length() {
assert_evals_to!("[1] == []", false, bool);
assert_evals_to!("[] == [1]", false, bool);
}
#[test]
fn list_eq_compare_pointwise() {
assert_evals_to!("[1] == [1]", true, bool);
assert_evals_to!("[2] == [1]", false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn list_eq_compare_pointwise() {
assert_evals_to!("[1] == [1]", true, bool);
assert_evals_to!("[2] == [1]", false, bool);
}
#[test]
fn list_eq_nested() {
assert_evals_to!("[[1]] == [[1]]", true, bool);
assert_evals_to!("[[2]] == [[1]]", false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn list_eq_nested() {
assert_evals_to!("[[1]] == [[1]]", true, bool);
assert_evals_to!("[[2]] == [[1]]", false, bool);
}
#[test]
fn list_neq_compare_pointwise() {
assert_evals_to!("[1] != [1]", false, bool);
assert_evals_to!("[2] != [1]", true, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn list_neq_compare_pointwise() {
assert_evals_to!("[1] != [1]", false, bool);
assert_evals_to!("[2] != [1]", true, bool);
}
#[test]
fn list_neq_nested() {
assert_evals_to!("[[1]] != [[1]]", false, bool);
assert_evals_to!("[[2]] != [[1]]", true, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn list_neq_nested() {
assert_evals_to!("[[1]] != [[1]]", false, bool);
assert_evals_to!("[[2]] != [[1]]", true, bool);
}
#[test]
fn compare_union_same_content() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn compare_union_same_content() {
assert_evals_to!(
indoc!(
r#"
Foo : [ A I64, B I64 ]
a : Foo
@ -458,17 +494,18 @@ mod gen_compare {
a == b
"#
),
false,
bool
);
}
),
false,
bool
);
}
#[test]
fn compare_recursive_union_same_content() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn compare_recursive_union_same_content() {
assert_evals_to!(
indoc!(
r#"
Expr : [ Add Expr Expr, Mul Expr Expr, Val1 I64, Val2 I64 ]
v1 : Expr
@ -479,17 +516,18 @@ mod gen_compare {
v1 == v2
"#
),
false,
bool
);
}
),
false,
bool
);
}
#[test]
fn compare_nullable_recursive_union_same_content() {
assert_evals_to!(
indoc!(
r#"
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn compare_nullable_recursive_union_same_content() {
assert_evals_to!(
indoc!(
r#"
Expr : [ Add Expr Expr, Mul Expr Expr, Val1 I64, Val2 I64, Empty ]
v1 : Expr
@ -500,9 +538,8 @@ mod gen_compare {
v1 == v2
"#
),
false,
bool
);
}
),
false,
bool
);
}

View file

@ -1,10 +1,19 @@
#![cfg(test)]
#![cfg(feature = "gen-llvm")]
#[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 crate::assert_evals_to;
use indoc::indoc;
use roc_std::{RocList, RocStr};
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn dict_empty_len() {
assert_evals_to!(
indoc!(
@ -18,6 +27,7 @@ fn dict_empty_len() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn dict_insert_empty() {
assert_evals_to!(
indoc!(
@ -32,6 +42,7 @@ fn dict_insert_empty() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn dict_empty_contains() {
assert_evals_to!(
indoc!(
@ -48,6 +59,7 @@ fn dict_empty_contains() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn dict_nonempty_contains() {
assert_evals_to!(
indoc!(
@ -64,6 +76,7 @@ fn dict_nonempty_contains() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn dict_empty_remove() {
assert_evals_to!(
indoc!(
@ -82,6 +95,7 @@ fn dict_empty_remove() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn dict_nonempty_remove() {
assert_evals_to!(
indoc!(
@ -100,6 +114,7 @@ fn dict_nonempty_remove() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn dict_nonempty_get() {
assert_evals_to!(
indoc!(
@ -142,6 +157,7 @@ fn dict_nonempty_get() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn keys() {
assert_evals_to!(
indoc!(
@ -163,6 +179,7 @@ fn keys() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn values() {
assert_evals_to!(
indoc!(
@ -184,6 +201,7 @@ fn values() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn from_list_with_fold() {
assert_evals_to!(
indoc!(
@ -226,6 +244,7 @@ fn from_list_with_fold() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn small_str_keys() {
assert_evals_to!(
indoc!(
@ -247,6 +266,7 @@ fn small_str_keys() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn big_str_keys() {
assert_evals_to!(
indoc!(
@ -272,6 +292,7 @@ fn big_str_keys() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn big_str_values() {
assert_evals_to!(
indoc!(
@ -296,6 +317,7 @@ fn big_str_values() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn unit_values() {
assert_evals_to!(
indoc!(
@ -317,6 +339,7 @@ fn unit_values() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn single() {
assert_evals_to!(
indoc!(
@ -334,6 +357,7 @@ fn single() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn union() {
assert_evals_to!(
indoc!(
@ -351,6 +375,7 @@ fn union() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn union_prefer_first() {
assert_evals_to!(
indoc!(
@ -368,6 +393,7 @@ fn union_prefer_first() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn intersection() {
assert_evals_to!(
indoc!(
@ -398,6 +424,7 @@ fn intersection() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn intersection_prefer_first() {
assert_evals_to!(
indoc!(
@ -428,6 +455,7 @@ fn intersection_prefer_first() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn difference() {
assert_evals_to!(
indoc!(
@ -458,6 +486,7 @@ fn difference() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn difference_prefer_first() {
assert_evals_to!(
indoc!(
@ -488,6 +517,7 @@ fn difference_prefer_first() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn walk_sum_keys() {
assert_evals_to!(
indoc!(

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,42 @@
#![cfg(test)]
#[cfg(feature = "gen-llvm")]
use crate::helpers::llvm::assert_evals_to;
#[cfg(feature = "gen-llvm")]
use crate::helpers::llvm::assert_llvm_evals_to;
#[cfg(feature = "gen-llvm")]
use crate::helpers::llvm::assert_non_opt_evals_to;
#[cfg(feature = "gen-dev")]
use crate::helpers::dev::assert_evals_to;
// #[cfg(feature = "gen-dev")]
// use crate::helpers::dev::assert_evals_to as assert_llvm_evals_to;
// #[cfg(feature = "gen-dev")]
// use crate::helpers::dev::assert_evals_to as assert_non_opt_evals_to;
#[cfg(feature = "gen-wasm")]
use crate::helpers::wasm::assert_evals_to;
// #[cfg(feature = "gen-wasm")]
// use crate::helpers::wasm::assert_evals_to as assert_llvm_evals_to;
// #[cfg(feature = "gen-wasm")]
// use crate::helpers::wasm::assert_evals_to as assert_non_opt_evals_to;
use crate::assert_evals_to;
use crate::assert_llvm_evals_to;
use crate::assert_non_opt_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"))]
fn branch_first_float() {
assert_evals_to!(
indoc!(
@ -32,6 +52,7 @@ fn branch_first_float() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn branch_second_float() {
assert_evals_to!(
indoc!(
@ -47,6 +68,7 @@ fn branch_second_float() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn branch_third_float() {
assert_evals_to!(
indoc!(
@ -63,6 +85,7 @@ fn branch_third_float() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn branch_first_int() {
assert_evals_to!(
indoc!(
@ -78,6 +101,7 @@ fn branch_first_int() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn branch_second_int() {
assert_evals_to!(
indoc!(
@ -93,6 +117,7 @@ fn branch_second_int() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn branch_third_int() {
assert_evals_to!(
indoc!(
@ -109,6 +134,7 @@ fn branch_third_int() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn branch_store_variable() {
assert_evals_to!(
indoc!(
@ -124,6 +150,7 @@ fn branch_store_variable() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn when_one_element_tag() {
assert_evals_to!(
indoc!(
@ -141,6 +168,7 @@ fn when_one_element_tag() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn when_two_element_tag_first() {
assert_evals_to!(
indoc!(
@ -159,6 +187,7 @@ fn when_two_element_tag_first() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn when_two_element_tag_second() {
assert_evals_to!(
indoc!(
@ -177,6 +206,7 @@ fn when_two_element_tag_second() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn gen_when_one_branch() {
assert_evals_to!(
indoc!(
@ -191,6 +221,7 @@ fn gen_when_one_branch() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn gen_large_when_int() {
assert_evals_to!(
indoc!(
@ -213,6 +244,7 @@ fn gen_large_when_int() {
}
// #[test]
// #[cfg(any(feature = "gen-llvm"))]
// fn gen_large_when_float() {
// assert_evals_to!(
// indoc!(
@ -235,6 +267,7 @@ fn gen_large_when_int() {
// }
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn or_pattern() {
assert_evals_to!(
indoc!(
@ -250,6 +283,7 @@ fn or_pattern() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn apply_identity() {
assert_evals_to!(
indoc!(
@ -265,6 +299,7 @@ fn apply_identity() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn apply_unnamed_identity() {
assert_evals_to!(
indoc!(
@ -281,6 +316,7 @@ fn apply_unnamed_identity() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn return_unnamed_fn() {
assert_evals_to!(
indoc!(
@ -301,6 +337,7 @@ fn return_unnamed_fn() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn gen_when_fn() {
assert_evals_to!(
indoc!(
@ -320,6 +357,7 @@ fn gen_when_fn() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn gen_basic_def() {
assert_evals_to!(
indoc!(
@ -347,6 +385,7 @@ fn gen_basic_def() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn gen_multiple_defs() {
assert_evals_to!(
indoc!(
@ -380,6 +419,7 @@ fn gen_multiple_defs() {
// 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"))]
// fn gen_chained_defs() {
// assert_evals_to!(
// indoc!(
@ -399,6 +439,7 @@ fn gen_multiple_defs() {
// }
//
// #[test]
// #[cfg(any(feature = "gen-llvm"))]
// fn gen_nested_defs_old() {
// assert_evals_to!(
// indoc!(
@ -440,6 +481,7 @@ fn gen_multiple_defs() {
// }
//
// #[test]
// #[cfg(any(feature = "gen-llvm"))]
// fn let_x_in_x() {
// assert_evals_to!(
// indoc!(
@ -462,6 +504,7 @@ fn gen_multiple_defs() {
// }
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn factorial() {
assert_evals_to!(
indoc!(
@ -483,6 +526,7 @@ fn factorial() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn peano1() {
assert_non_opt_evals_to!(
indoc!(
@ -503,6 +547,7 @@ fn peano1() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn peano2() {
assert_non_opt_evals_to!(
indoc!(
@ -524,6 +569,7 @@ fn peano2() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn top_level_constant() {
assert_evals_to!(
indoc!(
@ -542,6 +588,7 @@ fn top_level_constant() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_len_0() {
assert_non_opt_evals_to!(
indoc!(
@ -569,6 +616,7 @@ fn linked_list_len_0() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_len_twice_0() {
assert_non_opt_evals_to!(
indoc!(
@ -596,6 +644,7 @@ fn linked_list_len_twice_0() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_len_1() {
assert_non_opt_evals_to!(
indoc!(
@ -623,6 +672,7 @@ fn linked_list_len_1() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_len_twice_1() {
assert_non_opt_evals_to!(
indoc!(
@ -650,6 +700,7 @@ fn linked_list_len_twice_1() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_len_3() {
assert_non_opt_evals_to!(
indoc!(
@ -678,6 +729,7 @@ fn linked_list_len_3() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_sum_num_a() {
assert_non_opt_evals_to!(
indoc!(
@ -706,6 +758,7 @@ fn linked_list_sum_num_a() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_sum_int() {
assert_non_opt_evals_to!(
indoc!(
@ -733,6 +786,7 @@ fn linked_list_sum_int() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_map() {
assert_non_opt_evals_to!(
indoc!(
@ -766,6 +820,7 @@ fn linked_list_map() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn when_nested_maybe() {
assert_evals_to!(
indoc!(
@ -822,6 +877,7 @@ fn when_nested_maybe() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn when_peano() {
assert_non_opt_evals_to!(
indoc!(
@ -879,6 +935,7 @@ fn when_peano() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[should_panic(expected = "Roc failed with message: ")]
fn overflow_frees_list() {
assert_evals_to!(
@ -903,6 +960,7 @@ fn overflow_frees_list() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[should_panic(expected = "Roc failed with message: ")]
fn undefined_variable() {
assert_evals_to!(
@ -920,6 +978,7 @@ fn undefined_variable() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[should_panic(expected = "Roc failed with message: ")]
fn annotation_without_body() {
assert_evals_to!(
@ -937,6 +996,7 @@ fn annotation_without_body() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn simple_closure() {
assert_evals_to!(
indoc!(
@ -958,6 +1018,7 @@ fn simple_closure() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn nested_closure() {
assert_evals_to!(
indoc!(
@ -981,6 +1042,7 @@ fn nested_closure() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn closure_in_list() {
assert_evals_to!(
indoc!(
@ -1006,6 +1068,7 @@ fn closure_in_list() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn specialize_closure() {
use roc_std::RocList;
@ -1037,6 +1100,7 @@ fn specialize_closure() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn io_poc_effect() {
assert_non_opt_evals_to!(
indoc!(
@ -1067,6 +1131,7 @@ fn io_poc_effect() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn io_poc_desugared() {
assert_evals_to!(
indoc!(
@ -1094,6 +1159,7 @@ fn io_poc_desugared() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn return_wrapped_function_pointer() {
assert_non_opt_evals_to!(
indoc!(
@ -1116,6 +1182,7 @@ fn return_wrapped_function_pointer() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn return_wrapped_function_pointer_b() {
assert_non_opt_evals_to!(
indoc!(
@ -1137,6 +1204,7 @@ fn return_wrapped_function_pointer_b() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn return_wrapped_closure() {
assert_non_opt_evals_to!(
indoc!(
@ -1162,6 +1230,7 @@ fn return_wrapped_closure() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_is_singleton() {
assert_non_opt_evals_to!(
indoc!(
@ -1196,6 +1265,7 @@ fn linked_list_is_singleton() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_is_empty_1() {
assert_non_opt_evals_to!(
indoc!(
@ -1230,6 +1300,7 @@ fn linked_list_is_empty_1() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_is_empty_2() {
assert_non_opt_evals_to!(
indoc!(
@ -1261,6 +1332,7 @@ fn linked_list_is_empty_2() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_singleton() {
// verifies only that valid llvm is produced
assert_non_opt_evals_to!(
@ -1281,6 +1353,7 @@ fn linked_list_singleton() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn recursive_function_with_rigid() {
assert_non_opt_evals_to!(
indoc!(
@ -1307,6 +1380,7 @@ fn recursive_function_with_rigid() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn rbtree_insert() {
assert_non_opt_evals_to!(
indoc!(
@ -1394,6 +1468,7 @@ fn rbtree_insert() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn rbtree_balance_3() {
assert_non_opt_evals_to!(
indoc!(
@ -1418,6 +1493,7 @@ fn rbtree_balance_3() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn rbtree_layout_issue() {
// there is a flex var in here somewhere that blows up layout creation
@ -1459,6 +1535,7 @@ fn rbtree_layout_issue() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn rbtree_balance_mono_problem() {
// because of how the function is written, only `Red` is used and so in the function's
@ -1512,6 +1589,7 @@ fn rbtree_balance_mono_problem() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn rbtree_balance_full() {
assert_non_opt_evals_to!(
indoc!(
@ -1563,6 +1641,7 @@ fn rbtree_balance_full() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn nested_pattern_match_two_ways() {
// exposed an issue in the ordering of pattern match checks when ran with `--release` mode
assert_non_opt_evals_to!(
@ -1616,6 +1695,7 @@ fn nested_pattern_match_two_ways() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
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
@ -1647,6 +1727,7 @@ fn linked_list_guarded_double_pattern_match() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn linked_list_double_pattern_match() {
assert_non_opt_evals_to!(
indoc!(
@ -1672,6 +1753,7 @@ fn linked_list_double_pattern_match() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn binary_tree_double_pattern_match() {
assert_non_opt_evals_to!(
indoc!(
@ -1697,6 +1779,7 @@ fn binary_tree_double_pattern_match() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn unified_empty_closure_bool() {
// none of the Closure tags will have a payload
// this was not handled correctly in the past
@ -1721,6 +1804,7 @@ fn unified_empty_closure_bool() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn unified_empty_closure_byte() {
// none of the Closure tags will have a payload
// this was not handled correctly in the past
@ -1746,6 +1830,7 @@ fn unified_empty_closure_byte() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn task_always_twice() {
assert_non_opt_evals_to!(
indoc!(
@ -1790,6 +1875,7 @@ fn task_always_twice() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn wildcard_rigid() {
assert_non_opt_evals_to!(
indoc!(
@ -1819,6 +1905,7 @@ fn wildcard_rigid() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn todo_bad_error_message() {
assert_non_opt_evals_to!(
@ -1866,6 +1953,7 @@ fn todo_bad_error_message() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn hof_conditional() {
// exposed issue with the if condition being just a symbol
assert_evals_to!(
@ -1882,6 +1970,7 @@ fn hof_conditional() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[should_panic(
expected = "Roc failed with message: \"Shadowing { original_region: |L 3-3, C 4-5|, shadow: |L 6-6, C 8-9| Ident"
)]
@ -1901,6 +1990,7 @@ fn pattern_shadowing() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[should_panic(expected = "TODO non-exhaustive pattern")]
fn non_exhaustive_pattern_let() {
assert_evals_to!(
@ -1920,6 +2010,7 @@ fn non_exhaustive_pattern_let() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
#[should_panic(expected = "")]
fn unsupported_pattern_str_interp() {
@ -1937,6 +2028,7 @@ fn unsupported_pattern_str_interp() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn fingertree_basic() {
assert_non_opt_evals_to!(
@ -1978,6 +2070,7 @@ fn fingertree_basic() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn case_or_pattern() {
// the `0` branch body should only be generated once in the future
// it is currently duplicated
@ -1998,6 +2091,7 @@ fn case_or_pattern() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn rosetree_basic() {
assert_non_opt_evals_to!(
@ -2025,6 +2119,7 @@ fn rosetree_basic() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn case_jump() {
// the decision tree will generate a jump to the `1` branch here
assert_evals_to!(
@ -2050,6 +2145,7 @@ fn case_jump() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn nullable_eval_cfold() {
// the decision tree will generate a jump to the `1` branch here
assert_evals_to!(
@ -2086,6 +2182,7 @@ fn nullable_eval_cfold() {
}
#[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!(
@ -2128,6 +2225,7 @@ fn nested_switch() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn count_deriv_x() {
// exposed bug with basing the block_of_memory on a specific (smaller) tag layout
assert_evals_to!(
@ -2154,6 +2252,7 @@ fn count_deriv_x() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn deriv_pow() {
// exposed bug with ordering of variable declarations before switch
assert_evals_to!(
@ -2190,6 +2289,7 @@ fn deriv_pow() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn multiple_increment() {
// the `leaf` value will be incremented multiple times at once
assert_evals_to!(
@ -2223,6 +2323,7 @@ fn multiple_increment() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn switch_fuse_rc_non_exhaustive() {
assert_evals_to!(
indoc!(
@ -2252,6 +2353,7 @@ fn switch_fuse_rc_non_exhaustive() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn switch_fuse_rc_exhaustive() {
assert_evals_to!(
indoc!(
@ -2280,6 +2382,7 @@ fn switch_fuse_rc_exhaustive() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn build_then_apply_closure() {
assert_evals_to!(
indoc!(
@ -2299,6 +2402,7 @@ fn build_then_apply_closure() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn expanded_result() {
assert_evals_to!(
indoc!(
@ -2329,6 +2433,7 @@ fn expanded_result() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn backpassing_result() {
assert_evals_to!(
@ -2362,6 +2467,7 @@ fn backpassing_result() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
#[should_panic(
expected = "Shadowing { original_region: |L 3-3, C 4-5|, shadow: |L 5-5, C 6-7| Ident"
)]
@ -2380,6 +2486,7 @@ fn function_malformed_pattern() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[should_panic(expected = "Hit an erroneous type when creating a layout for")]
fn call_invalid_layout() {
assert_llvm_evals_to!(
@ -2399,6 +2506,7 @@ fn call_invalid_layout() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[should_panic(expected = "An expectation failed!")]
fn expect_fail() {
assert_evals_to!(
@ -2415,6 +2523,7 @@ fn expect_fail() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn increment_or_double_closure() {
assert_evals_to!(
indoc!(
@ -2452,6 +2561,7 @@ fn increment_or_double_closure() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn module_thunk_is_function() {
assert_evals_to!(
indoc!(
@ -2468,6 +2578,7 @@ fn module_thunk_is_function() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[should_panic(expected = "Roc failed with message: ")]
fn hit_unresolved_type_variable() {
assert_evals_to!(
@ -2491,6 +2602,7 @@ fn hit_unresolved_type_variable() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn pattern_match_empty_record() {
assert_evals_to!(
indoc!(
@ -2510,6 +2622,7 @@ fn pattern_match_empty_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn pattern_match_unit_tag() {
assert_evals_to!(
indoc!(
@ -2534,6 +2647,7 @@ fn pattern_match_unit_tag() {
// see for why this is disabled on wasm32 https://github.com/rtfeldman/roc/issues/1687
#[cfg(not(feature = "wasm-cli-run"))]
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn mirror_llvm_alignment_padding() {
// see https://github.com/rtfeldman/roc/issues/1569
assert_evals_to!(
@ -2556,6 +2670,7 @@ fn mirror_llvm_alignment_padding() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn lambda_set_bool() {
assert_evals_to!(
indoc!(
@ -2580,6 +2695,7 @@ fn lambda_set_bool() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn lambda_set_byte() {
assert_evals_to!(
indoc!(
@ -2605,6 +2721,7 @@ fn lambda_set_byte() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn lambda_set_struct_byte() {
assert_evals_to!(
indoc!(
@ -2632,6 +2749,7 @@ fn lambda_set_struct_byte() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn lambda_set_enum_byte_byte() {
assert_evals_to!(
indoc!(
@ -2662,6 +2780,7 @@ fn lambda_set_enum_byte_byte() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn list_walk_until() {
// see https://github.com/rtfeldman/roc/issues/1576
assert_evals_to!(
@ -2687,6 +2806,7 @@ fn list_walk_until() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn int_literal_not_specialized_with_annotation() {
// see https://github.com/rtfeldman/roc/issues/1600
assert_evals_to!(
@ -2714,6 +2834,7 @@ fn int_literal_not_specialized_with_annotation() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn int_literal_not_specialized_no_annotation() {
// see https://github.com/rtfeldman/roc/issues/1600
assert_evals_to!(
@ -2740,6 +2861,7 @@ fn int_literal_not_specialized_no_annotation() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn unresolved_tvar_when_capture_is_unused() {
// see https://github.com/rtfeldman/roc/issues/1585
assert_evals_to!(
@ -2766,6 +2888,7 @@ fn unresolved_tvar_when_capture_is_unused() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[should_panic(expected = "Roc failed with message: ")]
fn value_not_exposed_hits_panic() {
assert_evals_to!(
@ -2784,6 +2907,7 @@ fn value_not_exposed_hits_panic() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn mix_function_and_closure() {
// see https://github.com/rtfeldman/roc/pull/1706
assert_evals_to!(
@ -2809,6 +2933,7 @@ fn mix_function_and_closure() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn mix_function_and_closure_level_of_indirection() {
// see https://github.com/rtfeldman/roc/pull/1706
assert_evals_to!(
@ -2833,6 +2958,7 @@ fn mix_function_and_closure_level_of_indirection() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
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
@ -2908,6 +3034,7 @@ fn do_pass_bool_byte_closure_layout() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn nested_rigid_list() {
assert_evals_to!(
indoc!(
@ -2932,6 +3059,7 @@ fn nested_rigid_list() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn nested_rigid_alias() {
assert_evals_to!(
indoc!(
@ -2958,6 +3086,7 @@ fn nested_rigid_alias() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn nested_rigid_tag_union() {
assert_evals_to!(
indoc!(
@ -2982,6 +3111,7 @@ fn nested_rigid_tag_union() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
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`.

View file

@ -1,10 +1,17 @@
#![cfg(test)]
#[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 crate::assert_evals_to;
// use crate::assert_wasm_evals_to as assert_evals_to;
use indoc::indoc;
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn basic_record() {
assert_evals_to!(
indoc!(
@ -38,6 +45,7 @@ fn basic_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn f64_record() {
assert_evals_to!(
indoc!(
@ -77,6 +85,7 @@ fn f64_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn fn_record() {
assert_evals_to!(
indoc!(
@ -128,6 +137,7 @@ fn fn_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn def_record() {
assert_evals_to!(
indoc!(
@ -167,6 +177,7 @@ fn def_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn when_on_record() {
assert_evals_to!(
indoc!(
@ -181,6 +192,7 @@ fn when_on_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn when_record_with_guard_pattern() {
assert_evals_to!(
indoc!(
@ -195,6 +207,7 @@ fn when_record_with_guard_pattern() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn let_with_record_pattern() {
assert_evals_to!(
indoc!(
@ -210,6 +223,7 @@ fn let_with_record_pattern() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn record_guard_pattern() {
assert_evals_to!(
indoc!(
@ -225,6 +239,7 @@ fn record_guard_pattern() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn twice_record_access() {
assert_evals_to!(
indoc!(
@ -239,6 +254,7 @@ fn twice_record_access() {
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-dev"))]
fn empty_record() {
assert_evals_to!(
indoc!(
@ -253,6 +269,7 @@ fn empty_record() {
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn i64_record2_literal() {
assert_evals_to!(
indoc!(
@ -266,6 +283,7 @@ fn i64_record2_literal() {
}
// #[test]
// #[cfg(any(feature = "gen-llvm"))]
// fn i64_record3_literal() {
// assert_evals_to!(
// indoc!(
@ -277,8 +295,8 @@ fn i64_record2_literal() {
// (i64, i64, i64)
// );
// }
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn f64_record2_literal() {
assert_evals_to!(
indoc!(
@ -292,6 +310,7 @@ fn f64_record2_literal() {
}
// #[test]
// #[cfg(any(feature = "gen-llvm"))]
// fn f64_record3_literal() {
// assert_evals_to!(
// indoc!(
@ -305,6 +324,7 @@ fn f64_record2_literal() {
// }
// #[test]
// #[cfg(any(feature = "gen-llvm"))]
// fn bool_record4_literal() {
// assert_evals_to!(
// indoc!(
@ -319,8 +339,8 @@ fn f64_record2_literal() {
// (bool, bool, bool, bool)
// );
// }
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn i64_record1_literal() {
assert_evals_to!(
indoc!(
@ -334,6 +354,7 @@ fn i64_record1_literal() {
}
// #[test]
// #[cfg(any(feature = "gen-llvm"))]
// fn i64_record9_literal() {
// assert_evals_to!(
// indoc!(
@ -347,6 +368,7 @@ fn i64_record1_literal() {
// }
// #[test]
// #[cfg(any(feature = "gen-llvm"))]
// fn f64_record3_literal() {
// assert_evals_to!(
// indoc!(
@ -358,8 +380,8 @@ fn i64_record1_literal() {
// (f64, f64, f64)
// );
// }
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn bool_literal() {
assert_evals_to!(
indoc!(
@ -376,6 +398,7 @@ fn bool_literal() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_record() {
assert_evals_to!(
indoc!(
@ -392,6 +415,7 @@ fn return_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn optional_field_when_use_default() {
assert_evals_to!(
indoc!(
@ -419,6 +443,7 @@ fn optional_field_when_use_default() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn optional_field_when_use_default_nested() {
assert_evals_to!(
indoc!(
@ -442,6 +467,7 @@ fn optional_field_when_use_default_nested() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn optional_field_when_no_use_default() {
assert_evals_to!(
indoc!(
@ -462,6 +488,7 @@ fn optional_field_when_no_use_default() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn optional_field_when_no_use_default_nested() {
assert_evals_to!(
indoc!(
@ -479,6 +506,7 @@ fn optional_field_when_no_use_default_nested() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn optional_field_let_use_default() {
assert_evals_to!(
indoc!(
@ -499,6 +527,7 @@ fn optional_field_let_use_default() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn optional_field_let_no_use_default() {
assert_evals_to!(
indoc!(
@ -519,6 +548,7 @@ fn optional_field_let_no_use_default() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn optional_field_let_no_use_default_nested() {
assert_evals_to!(
indoc!(
@ -536,6 +566,7 @@ fn optional_field_let_no_use_default_nested() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn optional_field_function_use_default() {
assert_evals_to!(
indoc!(
@ -552,6 +583,7 @@ fn optional_field_function_use_default() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn optional_field_function_no_use_default() {
// blocked on https://github.com/rtfeldman/roc/issues/786
@ -572,6 +604,7 @@ fn optional_field_function_no_use_default() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn optional_field_function_no_use_default_nested() {
// blocked on https://github.com/rtfeldman/roc/issues/786
@ -590,6 +623,7 @@ fn optional_field_function_no_use_default_nested() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn optional_field_singleton_record() {
assert_evals_to!(
indoc!(
@ -604,6 +638,7 @@ fn optional_field_singleton_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn optional_field_empty_record() {
assert_evals_to!(
indoc!(
@ -618,6 +653,7 @@ fn optional_field_empty_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_record_2() {
assert_evals_to!(
indoc!(
@ -631,6 +667,7 @@ fn return_record_2() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_record_3() {
assert_evals_to!(
indoc!(
@ -644,6 +681,7 @@ fn return_record_3() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_record_4() {
assert_evals_to!(
indoc!(
@ -657,6 +695,7 @@ fn return_record_4() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_record_5() {
assert_evals_to!(
indoc!(
@ -670,6 +709,7 @@ fn return_record_5() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_record_6() {
assert_evals_to!(
indoc!(
@ -683,6 +723,7 @@ fn return_record_6() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_record_7() {
assert_evals_to!(
indoc!(
@ -696,6 +737,7 @@ fn return_record_7() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_record_float_int() {
assert_evals_to!(
indoc!(
@ -709,6 +751,7 @@ fn return_record_float_int() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_record_int_float() {
assert_evals_to!(
indoc!(
@ -722,6 +765,7 @@ fn return_record_int_float() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_record_float_float() {
assert_evals_to!(
indoc!(
@ -735,6 +779,7 @@ fn return_record_float_float() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_record_float_float_float() {
assert_evals_to!(
indoc!(
@ -748,6 +793,7 @@ fn return_record_float_float_float() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn return_nested_record() {
assert_evals_to!(
indoc!(
@ -761,11 +807,13 @@ fn return_nested_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn accessor_twice() {
assert_evals_to!(".foo { foo: 4 } + .foo { bar: 6.28, foo: 3 } ", 7, i64);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn accessor_multi_element_record() {
assert_evals_to!(
indoc!(
@ -779,6 +827,7 @@ fn accessor_multi_element_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn accessor_single_element_record() {
assert_evals_to!(
indoc!(
@ -792,6 +841,7 @@ fn accessor_single_element_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn update_record() {
assert_evals_to!(
indoc!(
@ -807,6 +857,7 @@ fn update_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn update_single_element_record() {
assert_evals_to!(
indoc!(
@ -822,6 +873,7 @@ fn update_single_element_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn booleans_in_record() {
assert_evals_to!(
indoc!("{ x: 1 == 1, y: 1 == 1 }"),
@ -846,6 +898,7 @@ fn booleans_in_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn alignment_in_record() {
assert_evals_to!(
indoc!("{ c: 32, b: if True then Red else if True then Green else Blue, a: 1 == 1 }"),
@ -855,6 +908,7 @@ fn alignment_in_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn blue_and_present() {
assert_evals_to!(
indoc!(
@ -873,6 +927,7 @@ fn blue_and_present() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn blue_and_absent() {
assert_evals_to!(
indoc!(
@ -891,6 +946,7 @@ fn blue_and_absent() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn update_the_only_field() {
assert_evals_to!(
indoc!(

View file

@ -1,9 +1,18 @@
#![cfg(test)]
#![cfg(feature = "gen-llvm")]
#[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 crate::assert_evals_to;
use indoc::indoc;
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn with_default() {
assert_evals_to!(
indoc!(
@ -33,6 +42,7 @@ fn with_default() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn result_map() {
assert_evals_to!(
indoc!(
@ -66,6 +76,7 @@ fn result_map() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn result_map_err() {
assert_evals_to!(
indoc!(
@ -99,6 +110,7 @@ fn result_map_err() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn err_type_var() {
assert_evals_to!(
indoc!(
@ -113,6 +125,7 @@ fn err_type_var() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn err_type_var_annotation() {
assert_evals_to!(
indoc!(
@ -130,6 +143,7 @@ fn err_type_var_annotation() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn err_empty_tag_union() {
assert_evals_to!(
indoc!(

View file

@ -1,10 +1,19 @@
#![cfg(test)]
#![cfg(feature = "gen-llvm")]
#[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 crate::assert_evals_to;
use indoc::indoc;
use roc_std::RocList;
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn empty_len() {
assert_evals_to!(
indoc!(
@ -18,6 +27,7 @@ fn empty_len() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn single_len() {
assert_evals_to!(
indoc!(
@ -31,6 +41,7 @@ fn single_len() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn single_to_list() {
assert_evals_to!(
indoc!(
@ -64,6 +75,7 @@ fn single_to_list() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn insert() {
assert_evals_to!(
indoc!(
@ -81,6 +93,7 @@ fn insert() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn remove() {
assert_evals_to!(
indoc!(
@ -99,6 +112,7 @@ fn remove() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn union() {
assert_evals_to!(
indoc!(
@ -119,6 +133,7 @@ fn union() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn difference() {
assert_evals_to!(
indoc!(
@ -139,6 +154,7 @@ fn difference() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn intersection() {
assert_evals_to!(
indoc!(
@ -159,6 +175,7 @@ fn intersection() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn walk_sum() {
assert_evals_to!(
indoc!(
@ -172,6 +189,7 @@ fn walk_sum() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn contains() {
assert_evals_to!(
indoc!(
@ -195,6 +213,7 @@ fn contains() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn from_list() {
assert_evals_to!(
indoc!(

View file

@ -1,11 +1,22 @@
#![cfg(test)]
#![cfg(not(feature = "gen-wasm"))]
use crate::assert_evals_to;
use crate::assert_llvm_evals_to;
#[cfg(feature = "gen-llvm")]
use crate::helpers::llvm::assert_evals_to;
#[cfg(feature = "gen-llvm")]
use crate::helpers::llvm::assert_llvm_evals_to;
#[cfg(feature = "gen-dev")]
use crate::helpers::dev::assert_evals_to;
#[cfg(feature = "gen-dev")]
use crate::helpers::dev::assert_evals_to as assert_llvm_evals_to;
#[allow(unused_imports)]
use indoc::indoc;
#[allow(unused_imports)]
use roc_std::{RocList, RocStr};
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_split_bigger_delimiter_small_str() {
assert_evals_to!(
indoc!(
@ -35,6 +46,7 @@ fn str_split_bigger_delimiter_small_str() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_split_str_concat_repeated() {
assert_evals_to!(
indoc!(
@ -58,6 +70,7 @@ fn str_split_str_concat_repeated() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_split_small_str_bigger_delimiter() {
assert_evals_to!(
indoc!(
@ -76,6 +89,7 @@ fn str_split_small_str_bigger_delimiter() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_split_big_str_small_delimiter() {
assert_evals_to!(
indoc!(
@ -105,6 +119,7 @@ fn str_split_big_str_small_delimiter() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_split_small_str_small_delimiter() {
assert_evals_to!(
indoc!(
@ -122,6 +137,7 @@ fn str_split_small_str_small_delimiter() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_split_bigger_delimiter_big_strs() {
assert_evals_to!(
indoc!(
@ -137,6 +153,7 @@ fn str_split_bigger_delimiter_big_strs() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_split_empty_strs() {
assert_evals_to!(
indoc!(
@ -150,6 +167,7 @@ fn str_split_empty_strs() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_split_minimal_example() {
assert_evals_to!(
indoc!(
@ -163,6 +181,7 @@ fn str_split_minimal_example() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_split_small_str_big_delimiter() {
assert_evals_to!(
indoc!(
@ -195,6 +214,7 @@ fn str_split_small_str_big_delimiter() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_split_small_str_20_char_delimiter() {
assert_evals_to!(
indoc!(
@ -214,6 +234,7 @@ fn str_split_small_str_20_char_delimiter() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_concat_big_to_big() {
assert_evals_to!(
indoc!(
@ -229,6 +250,7 @@ fn str_concat_big_to_big() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn small_str_literal() {
assert_llvm_evals_to!(
"\"JJJJJJJJJJJJJJJ\"",
@ -255,6 +277,7 @@ fn small_str_literal() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn small_str_zeroed_literal() {
// Verifies that we zero out unused bytes in the string.
// This is important so that string equality tests don't randomly
@ -284,6 +307,7 @@ fn small_str_zeroed_literal() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn small_str_concat_empty_first_arg() {
assert_llvm_evals_to!(
r#"Str.concat "" "JJJJJJJJJJJJJJJ""#,
@ -310,6 +334,7 @@ fn small_str_concat_empty_first_arg() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn small_str_concat_empty_second_arg() {
assert_llvm_evals_to!(
r#"Str.concat "JJJJJJJJJJJJJJJ" """#,
@ -336,6 +361,7 @@ fn small_str_concat_empty_second_arg() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn small_str_concat_small_to_big() {
assert_evals_to!(
r#"Str.concat "abc" " this is longer than 15 chars""#,
@ -345,6 +371,7 @@ fn small_str_concat_small_to_big() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn small_str_concat_small_to_small_staying_small() {
assert_llvm_evals_to!(
r#"Str.concat "J" "JJJJJJJJJJJJJJ""#,
@ -371,6 +398,7 @@ fn small_str_concat_small_to_small_staying_small() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn small_str_concat_small_to_small_overflow_to_big() {
assert_evals_to!(
r#"Str.concat "abcdefghijklm" "nopqrstuvwxyz""#,
@ -380,16 +408,19 @@ fn small_str_concat_small_to_small_overflow_to_big() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn str_concat_empty() {
assert_evals_to!(r#"Str.concat "" """#, RocStr::default(), RocStr);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn small_str_is_empty() {
assert_evals_to!(r#"Str.isEmpty "abc""#, false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn big_str_is_empty() {
assert_evals_to!(
r#"Str.isEmpty "this is more than 15 chars long""#,
@ -399,11 +430,13 @@ fn big_str_is_empty() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn empty_str_is_empty() {
assert_evals_to!(r#"Str.isEmpty """#, true, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_starts_with() {
assert_evals_to!(r#"Str.startsWith "hello world" "hell""#, true, bool);
assert_evals_to!(r#"Str.startsWith "hello world" """#, true, bool);
@ -413,6 +446,7 @@ fn str_starts_with() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_starts_with_code_point() {
assert_evals_to!(
&format!(r#"Str.startsWithCodePt "foobar" {}"#, 'f' as u32),
@ -427,6 +461,7 @@ fn str_starts_with_code_point() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_ends_with() {
assert_evals_to!(r#"Str.endsWith "hello world" "world""#, true, bool);
assert_evals_to!(r#"Str.endsWith "nope" "hello world""#, false, bool);
@ -434,16 +469,19 @@ fn str_ends_with() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_count_graphemes_small_str() {
assert_evals_to!(r#"Str.countGraphemes "å🤔""#, 2, usize);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_count_graphemes_three_js() {
assert_evals_to!(r#"Str.countGraphemes "JJJ""#, 3, usize);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_count_graphemes_big_str() {
assert_evals_to!(
r#"Str.countGraphemes "6🤔å🤔e¥🤔çppkd🙃1jdal🦯asdfa∆ltråø˚waia8918.,🏅jjc""#,
@ -453,6 +491,7 @@ fn str_count_graphemes_big_str() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_starts_with_same_big_str() {
assert_evals_to!(
r#"Str.startsWith "123456789123456789" "123456789123456789""#,
@ -462,6 +501,7 @@ fn str_starts_with_same_big_str() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_starts_with_different_big_str() {
assert_evals_to!(
r#"Str.startsWith "12345678912345678910" "123456789123456789""#,
@ -471,20 +511,24 @@ fn str_starts_with_different_big_str() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_starts_with_same_small_str() {
assert_evals_to!(r#"Str.startsWith "1234" "1234""#, true, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_starts_with_different_small_str() {
assert_evals_to!(r#"Str.startsWith "1234" "12""#, true, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_starts_with_false_small_str() {
assert_evals_to!(r#"Str.startsWith "1234" "23""#, false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_int() {
assert_evals_to!(
r#"Str.fromInt 1234"#,
@ -518,6 +562,7 @@ fn str_from_int() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_pass_single_ascii() {
assert_evals_to!(
indoc!(
@ -533,6 +578,7 @@ fn str_from_utf8_pass_single_ascii() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_pass_many_ascii() {
assert_evals_to!(
indoc!(
@ -548,6 +594,7 @@ fn str_from_utf8_pass_many_ascii() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_pass_single_unicode() {
assert_evals_to!(
indoc!(
@ -563,6 +610,7 @@ fn str_from_utf8_pass_single_unicode() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_pass_many_unicode() {
assert_evals_to!(
indoc!(
@ -578,6 +626,7 @@ fn str_from_utf8_pass_many_unicode() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_pass_single_grapheme() {
assert_evals_to!(
indoc!(
@ -593,6 +642,7 @@ fn str_from_utf8_pass_single_grapheme() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_pass_many_grapheme() {
assert_evals_to!(
indoc!(
@ -608,6 +658,7 @@ fn str_from_utf8_pass_many_grapheme() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_pass_all() {
assert_evals_to!(
indoc!(
@ -623,6 +674,7 @@ fn str_from_utf8_pass_all() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_fail_invalid_start_byte() {
assert_evals_to!(
indoc!(
@ -642,6 +694,7 @@ fn str_from_utf8_fail_invalid_start_byte() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_fail_unexpected_end_of_sequence() {
assert_evals_to!(
indoc!(
@ -661,6 +714,7 @@ fn str_from_utf8_fail_unexpected_end_of_sequence() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_fail_expected_continuation() {
assert_evals_to!(
indoc!(
@ -680,6 +734,7 @@ fn str_from_utf8_fail_expected_continuation() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_fail_overlong_encoding() {
assert_evals_to!(
indoc!(
@ -699,6 +754,7 @@ fn str_from_utf8_fail_overlong_encoding() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_fail_codepoint_too_large() {
assert_evals_to!(
indoc!(
@ -718,6 +774,7 @@ fn str_from_utf8_fail_codepoint_too_large() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_fail_surrogate_half() {
assert_evals_to!(
indoc!(
@ -737,6 +794,7 @@ fn str_from_utf8_fail_surrogate_half() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_equality() {
assert_evals_to!(r#""a" == "a""#, true, bool);
assert_evals_to!(
@ -761,6 +819,7 @@ fn str_clone() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn nested_recursive_literal() {
assert_evals_to!(
indoc!(
@ -791,6 +850,7 @@ fn nested_recursive_literal() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_join_comma_small() {
assert_evals_to!(
r#"Str.joinWith ["1", "2"] ", " "#,
@ -800,6 +860,7 @@ fn str_join_comma_small() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_join_comma_big() {
assert_evals_to!(
r#"Str.joinWith ["10000000", "2000000", "30000000"] ", " "#,
@ -809,16 +870,19 @@ fn str_join_comma_big() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_join_comma_single() {
assert_evals_to!(r#"Str.joinWith ["1"] ", " "#, RocStr::from("1"), RocStr);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_float() {
assert_evals_to!(r#"Str.fromFloat 3.14"#, RocStr::from("3.14"), RocStr);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_to_utf8() {
assert_evals_to!(
r#"Str.toUtf8 "hello""#,
@ -836,6 +900,7 @@ fn str_to_utf8() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_range() {
assert_evals_to!(
indoc!(
@ -852,6 +917,7 @@ fn str_from_utf8_range() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_range_slice() {
assert_evals_to!(
indoc!(
@ -868,6 +934,7 @@ fn str_from_utf8_range_slice() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_range_slice_not_end() {
assert_evals_to!(
indoc!(
@ -884,6 +951,7 @@ fn str_from_utf8_range_slice_not_end() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_range_order_does_not_matter() {
assert_evals_to!(
indoc!(
@ -900,6 +968,7 @@ fn str_from_utf8_range_order_does_not_matter() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_range_out_of_bounds_start_value() {
assert_evals_to!(
indoc!(
@ -917,6 +986,7 @@ fn str_from_utf8_range_out_of_bounds_start_value() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_range_count_too_high() {
assert_evals_to!(
indoc!(
@ -934,6 +1004,7 @@ fn str_from_utf8_range_count_too_high() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_from_utf8_range_count_too_high_for_start() {
assert_evals_to!(
indoc!(
@ -951,6 +1022,7 @@ fn str_from_utf8_range_count_too_high_for_start() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_repeat_small() {
assert_evals_to!(
indoc!(r#"Str.repeat "Roc" 3"#),
@ -960,6 +1032,7 @@ fn str_repeat_small() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_repeat_big() {
assert_evals_to!(
indoc!(r#"Str.repeat "more than 16 characters" 2"#),
@ -969,26 +1042,31 @@ fn str_repeat_big() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_repeat_empty_string() {
assert_evals_to!(indoc!(r#"Str.repeat "" 3"#), RocStr::from(""), RocStr);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_repeat_zero_times() {
assert_evals_to!(indoc!(r#"Str.repeat "Roc" 0"#), RocStr::from(""), RocStr);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_trim_empty_string() {
assert_evals_to!(indoc!(r#"Str.trim """#), RocStr::from(""), RocStr);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_trim_small_blank_string() {
assert_evals_to!(indoc!(r#"Str.trim " ""#), RocStr::from(""), RocStr);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_trim_small_to_small() {
assert_evals_to!(
indoc!(r#"Str.trim " hello world ""#),
@ -998,6 +1076,7 @@ fn str_trim_small_to_small() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_trim_large_to_large_unique() {
assert_evals_to!(
indoc!(r#"Str.trim (Str.concat " " "hello world from a large string ")"#),
@ -1007,6 +1086,7 @@ fn str_trim_large_to_large_unique() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_trim_large_to_small_unique() {
assert_evals_to!(
indoc!(r#"Str.trim (Str.concat " " "hello world ")"#),
@ -1016,6 +1096,7 @@ fn str_trim_large_to_small_unique() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_trim_large_to_large_shared() {
assert_evals_to!(
indoc!(
@ -1035,6 +1116,7 @@ fn str_trim_large_to_large_shared() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_trim_large_to_small_shared() {
assert_evals_to!(
indoc!(
@ -1054,6 +1136,7 @@ fn str_trim_large_to_small_shared() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_trim_small_to_small_shared() {
assert_evals_to!(
indoc!(

View file

@ -1,11 +1,20 @@
#![cfg(test)]
#![cfg(feature = "gen-llvm")]
#[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 crate::assert_evals_to;
// use crate::assert_wasm_evals_to as assert_evals_to;
use indoc::indoc;
use roc_std::{RocList, RocStr};
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn width_and_alignment_u8_u8() {
use roc_mono::layout::Builtin;
use roc_mono::layout::Layout;
@ -23,6 +32,7 @@ fn width_and_alignment_u8_u8() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn applied_tag_nothing_ir() {
assert_evals_to!(
indoc!(
@ -42,6 +52,7 @@ fn applied_tag_nothing_ir() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn applied_tag_nothing() {
assert_evals_to!(
indoc!(
@ -61,6 +72,7 @@ fn applied_tag_nothing() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn applied_tag_just() {
assert_evals_to!(
indoc!(
@ -79,6 +91,7 @@ fn applied_tag_just() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn applied_tag_just_ir() {
assert_evals_to!(
indoc!(
@ -97,6 +110,7 @@ fn applied_tag_just_ir() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn applied_tag_just_enum() {
assert_evals_to!(
indoc!(
@ -120,6 +134,7 @@ fn applied_tag_just_enum() {
}
// #[test]
#[cfg(any(feature = "gen-llvm"))]
// fn raw_result() {
// assert_evals_to!(
// indoc!(
@ -134,8 +149,8 @@ fn applied_tag_just_enum() {
// i8
// );
// }
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn true_is_true() {
assert_evals_to!(
indoc!(
@ -152,6 +167,7 @@ fn true_is_true() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn false_is_false() {
assert_evals_to!(
indoc!(
@ -168,6 +184,7 @@ fn false_is_false() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn basic_enum() {
assert_evals_to!(
indoc!(
@ -189,6 +206,7 @@ fn basic_enum() {
}
// #[test]
#[cfg(any(feature = "gen-llvm"))]
// fn linked_list_empty() {
// assert_evals_to!(
// indoc!(
@ -207,6 +225,7 @@ fn basic_enum() {
// }
//
// #[test]
#[cfg(any(feature = "gen-llvm"))]
// fn linked_list_singleton() {
// assert_evals_to!(
// indoc!(
@ -225,6 +244,7 @@ fn basic_enum() {
// }
//
// #[test]
#[cfg(any(feature = "gen-llvm"))]
// fn linked_list_is_empty() {
// assert_evals_to!(
// indoc!(
@ -244,8 +264,8 @@ fn basic_enum() {
// bool
// );
// }
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn even_odd() {
assert_evals_to!(
indoc!(
@ -271,6 +291,7 @@ fn even_odd() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn gen_literal_true() {
assert_evals_to!(
indoc!(
@ -284,6 +305,7 @@ fn gen_literal_true() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn gen_if_float() {
assert_evals_to!(
indoc!(
@ -296,6 +318,7 @@ fn gen_if_float() {
);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn when_on_nothing() {
assert_evals_to!(
indoc!(
@ -314,6 +337,7 @@ fn when_on_nothing() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn when_on_just() {
assert_evals_to!(
indoc!(
@ -332,6 +356,7 @@ fn when_on_just() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn when_on_result() {
assert_evals_to!(
indoc!(
@ -350,6 +375,7 @@ fn when_on_result() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn when_on_these() {
assert_evals_to!(
indoc!(
@ -371,6 +397,7 @@ fn when_on_these() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn match_on_two_values() {
// this will produce a Chain internally
assert_evals_to!(
@ -387,6 +414,7 @@ fn match_on_two_values() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn pair_with_guard_pattern() {
assert_evals_to!(
indoc!(
@ -403,6 +431,7 @@ fn pair_with_guard_pattern() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn result_with_guard_pattern() {
// This test revealed an issue with hashing Test values
assert_evals_to!(
@ -423,6 +452,7 @@ fn result_with_guard_pattern() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn maybe_is_just() {
assert_evals_to!(
indoc!(
@ -447,6 +477,7 @@ fn maybe_is_just() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn maybe_is_just_nested() {
assert_evals_to!(
indoc!(
@ -468,6 +499,7 @@ fn maybe_is_just_nested() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn nested_pattern_match() {
assert_evals_to!(
indoc!(
@ -488,6 +520,7 @@ fn nested_pattern_match() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn if_guard_vanilla() {
assert_evals_to!(
indoc!(
@ -503,6 +536,7 @@ fn if_guard_vanilla() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn when_on_single_value_tag() {
// this fails because the switched-on symbol is not defined
@ -520,6 +554,7 @@ fn when_on_single_value_tag() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn if_guard_multiple() {
assert_evals_to!(
indoc!(
@ -540,6 +575,7 @@ fn if_guard_multiple() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn if_guard_constructor_switch() {
assert_evals_to!(
indoc!(
@ -583,6 +619,7 @@ fn if_guard_constructor_switch() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn if_guard_constructor_chain() {
assert_evals_to!(
indoc!(
@ -599,6 +636,7 @@ fn if_guard_constructor_chain() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn if_guard_pattern_false() {
assert_evals_to!(
indoc!(
@ -617,6 +655,7 @@ fn if_guard_pattern_false() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn if_guard_switch() {
assert_evals_to!(
indoc!(
@ -635,6 +674,7 @@ fn if_guard_switch() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn if_guard_pattern_true() {
assert_evals_to!(
indoc!(
@ -653,6 +693,7 @@ fn if_guard_pattern_true() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn if_guard_exhaustiveness() {
assert_evals_to!(
indoc!(
@ -671,6 +712,7 @@ fn if_guard_exhaustiveness() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn when_on_enum() {
assert_evals_to!(
indoc!(
@ -692,6 +734,7 @@ fn when_on_enum() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn pattern_matching_unit() {
assert_evals_to!(
indoc!(
@ -750,6 +793,7 @@ fn pattern_matching_unit() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn one_element_tag() {
assert_evals_to!(
indoc!(
@ -766,6 +810,7 @@ fn one_element_tag() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn nested_tag_union() {
assert_evals_to!(
indoc!(
@ -786,6 +831,7 @@ fn nested_tag_union() {
);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn unit_type() {
assert_evals_to!(
indoc!(
@ -804,6 +850,7 @@ fn unit_type() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn nested_record_load() {
assert_evals_to!(
indoc!(
@ -821,6 +868,7 @@ fn nested_record_load() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn join_point_if() {
assert_evals_to!(
indoc!(
@ -837,6 +885,7 @@ fn join_point_if() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn join_point_when() {
assert_evals_to!(
indoc!(
@ -862,6 +911,7 @@ fn join_point_when() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn join_point_with_cond_expr() {
assert_evals_to!(
indoc!(
@ -900,6 +950,7 @@ fn join_point_with_cond_expr() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn alignment_in_single_tag_construction() {
assert_evals_to!(indoc!("Three (1 == 1) 32"), (32i64, true), (i64, bool));
@ -911,6 +962,7 @@ fn alignment_in_single_tag_construction() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn alignment_in_single_tag_pattern_match() {
assert_evals_to!(
indoc!(
@ -942,6 +994,7 @@ fn alignment_in_single_tag_pattern_match() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn alignment_in_multi_tag_construction_two() {
assert_evals_to!(
indoc!(
@ -959,6 +1012,7 @@ fn alignment_in_multi_tag_construction_two() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn alignment_in_multi_tag_construction_three() {
assert_evals_to!(
indoc!(
@ -975,6 +1029,7 @@ fn alignment_in_multi_tag_construction_three() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn alignment_in_multi_tag_pattern_match() {
assert_evals_to!(
indoc!(
@ -1013,6 +1068,7 @@ fn alignment_in_multi_tag_pattern_match() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn phantom_polymorphic() {
// see https://github.com/rtfeldman/roc/issues/786 and below
@ -1038,6 +1094,7 @@ fn phantom_polymorphic() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]
fn phantom_polymorphic_record() {
// see https://github.com/rtfeldman/roc/issues/786
@ -1065,6 +1122,7 @@ fn phantom_polymorphic_record() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn result_never() {
assert_evals_to!(
indoc!(
@ -1086,6 +1144,7 @@ fn result_never() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn nested_recursive_literal() {
assert_evals_to!(
indoc!(
@ -1105,6 +1164,7 @@ fn nested_recursive_literal() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn newtype_wrapper() {
assert_evals_to!(
indoc!(
@ -1128,6 +1188,7 @@ fn newtype_wrapper() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn applied_tag_function() {
assert_evals_to!(
indoc!(
@ -1147,6 +1208,7 @@ fn applied_tag_function() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn applied_tag_function_result() {
assert_evals_to!(
indoc!(
@ -1166,6 +1228,7 @@ fn applied_tag_function_result() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn applied_tag_function_linked_list() {
assert_evals_to!(
indoc!(
@ -1186,6 +1249,7 @@ fn applied_tag_function_linked_list() {
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[should_panic(expected = "")]
fn tag_must_be_its_own_type() {
assert_evals_to!(

View file

@ -210,7 +210,7 @@ pub fn helper(
(main_fn_name, delayed_errors, lib)
}
#[macro_export]
#[allow(unused_macros)]
macro_rules! assert_evals_to {
($src:expr, $expected:expr, $ty:ty) => {{
assert_evals_to!($src, $expected, $ty, (|val| val));
@ -237,7 +237,7 @@ macro_rules! assert_evals_to {
let arena = Bump::new();
let (main_fn_name, errors, lib) =
$crate::helpers::eval::helper(&arena, $src, stdlib, $leak, $lazy_literals);
$crate::helpers::dev::helper(&arena, $src, stdlib, $leak, $lazy_literals);
let transform = |success| {
let expected = $expected;
@ -247,3 +247,6 @@ macro_rules! assert_evals_to {
run_jit_function_raw!(lib, main_fn_name, $ty, transform, errors)
};
}
#[allow(unused_imports)]
pub(crate) use assert_evals_to;

View file

@ -1,3 +1,4 @@
use crate::helpers::from_wasm32_memory::FromWasm32Memory;
use inkwell::module::Module;
use libloading::Library;
use roc_build::link::module_to_dylib;
@ -10,7 +11,6 @@ use roc_module::symbol::Symbol;
use roc_mono::ir::OptLevel;
use roc_types::subs::VarStore;
use target_lexicon::Triple;
use test_wasm_util::from_wasm32_memory::FromWasm32Memory;
fn promote_expr_to_module(src: &str) -> String {
let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n");
@ -469,7 +469,7 @@ where
let stdlib = arena.alloc(roc_builtins::std::standard_stdlib());
let is_gen_test = true;
let instance = crate::helpers::eval::helper_wasm(
let instance = crate::helpers::llvm::helper_wasm(
&arena,
src,
stdlib,
@ -480,7 +480,7 @@ where
let memory = instance.exports.get_memory("memory").unwrap();
crate::helpers::eval::MEMORY.with(|f| {
crate::helpers::llvm::MEMORY.with(|f| {
*f.borrow_mut() = Some(unsafe { std::mem::transmute(memory) });
});
@ -494,7 +494,7 @@ where
_ => panic!(),
};
let output = <T as crate::helpers::eval::FromWasm32Memory>::decode(
let output = <T as crate::helpers::llvm::FromWasm32Memory>::decode(
memory,
// skip the RocCallResult tag id
address as u32 + 8,
@ -505,10 +505,10 @@ where
}
}
#[macro_export]
#[allow(unused_macros)]
macro_rules! assert_wasm_evals_to {
($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => {
match $crate::helpers::eval::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),
Ok(actual) => {
#[allow(clippy::bool_assert_comparison)]
@ -518,15 +518,21 @@ macro_rules! assert_wasm_evals_to {
};
($src:expr, $expected:expr, $ty:ty) => {
$crate::assert_wasm_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity, false);
$crate::helpers::llvm::assert_wasm_evals_to!(
$src,
$expected,
$ty,
$crate::helpers::llvm::identity,
false
);
};
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
$crate::assert_wasm_evals_to!($src, $expected, $ty, $transform, false);
$crate::helpers::llvm::assert_wasm_evals_to!($src, $expected, $ty, $transform, false);
};
}
#[macro_export]
#[allow(unused_macros)]
macro_rules! assert_llvm_evals_to {
($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => {
use bumpalo::Bump;
@ -540,7 +546,7 @@ macro_rules! assert_llvm_evals_to {
let stdlib = arena.alloc(roc_builtins::std::standard_stdlib());
let is_gen_test = true;
let (main_fn_name, errors, lib) = $crate::helpers::eval::helper(
let (main_fn_name, errors, lib) = $crate::helpers::llvm::helper(
&arena,
$src,
stdlib,
@ -559,26 +565,32 @@ macro_rules! assert_llvm_evals_to {
};
($src:expr, $expected:expr, $ty:ty) => {
$crate::assert_llvm_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity, false);
$crate::helpers::llvm::assert_llvm_evals_to!(
$src,
$expected,
$ty,
$crate::helpers::llvm::identity,
false
);
};
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
$crate::assert_llvm_evals_to!($src, $expected, $ty, $transform, false);
$crate::helpers::llvm::assert_llvm_evals_to!($src, $expected, $ty, $transform, false);
};
}
#[macro_export]
#[allow(unused_macros)]
macro_rules! assert_evals_to {
($src:expr, $expected:expr, $ty:ty) => {{
assert_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity);
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.
{
#[cfg(feature = "wasm-cli-run")]
$crate::assert_wasm_evals_to!($src, $expected, $ty, $transform, false);
$crate::helpers::llvm::assert_wasm_evals_to!($src, $expected, $ty, $transform, false);
$crate::assert_llvm_evals_to!($src, $expected, $ty, $transform, false);
$crate::helpers::llvm::assert_llvm_evals_to!($src, $expected, $ty, $transform, false);
}
};
}
@ -588,18 +600,32 @@ pub fn identity<T>(value: T) -> T {
value
}
#[macro_export]
#[allow(unused_macros)]
macro_rules! assert_non_opt_evals_to {
($src:expr, $expected:expr, $ty:ty) => {{
$crate::assert_llvm_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity);
$crate::helpers::llvm::assert_llvm_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.
{
$crate::assert_llvm_evals_to!($src, $expected, $ty, $transform, false);
$crate::helpers::llvm::assert_llvm_evals_to!($src, $expected, $ty, $transform, false);
}
};
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {{
$crate::assert_llvm_evals_to!($src, $expected, $ty, $transform);
$crate::helpers::llvm::assert_llvm_evals_to!($src, $expected, $ty, $transform);
}};
}
#[allow(unused_imports)]
pub(crate) use assert_evals_to;
#[allow(unused_imports)]
pub(crate) use assert_llvm_evals_to;
#[allow(unused_imports)]
pub(crate) use assert_non_opt_evals_to;
#[allow(unused_imports)]
pub(crate) use assert_wasm_evals_to;

View file

@ -1,7 +1,14 @@
extern crate bumpalo;
#[macro_use]
pub mod eval;
#[cfg(feature = "gen-dev")]
pub mod dev;
pub mod from_wasm32_memory;
#[cfg(feature = "gen-llvm")]
pub mod llvm;
#[cfg(feature = "gen-wasm")]
pub mod wasm;
#[cfg(feature = "gen-wasm")]
pub mod wasm32_test_result;
/// Used in the with_larger_debug_stack() function, for tests that otherwise
/// run out of stack space in debug builds (but don't in --release builds)

View file

@ -2,10 +2,10 @@ use std::cell::Cell;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use crate::helpers::from_wasm32_memory::FromWasm32Memory;
use crate::helpers::wasm32_test_result::Wasm32TestResult;
use roc_can::builtins::builtin_defs_map;
use roc_collections::all::{MutMap, MutSet};
use test_wasm_util::from_wasm32_memory::FromWasm32Memory;
const TEST_WRAPPER_NAME: &str = "test_wrapper";
@ -112,7 +112,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
);
let mut module_bytes = std::vec::Vec::with_capacity(4096);
wasm_module.serialize(&mut module_bytes);
wasm_module.serialize_mut(&mut module_bytes);
// for debugging (e.g. with wasm2wat or wasm-objdump)
if false {
@ -169,9 +169,9 @@ where
// NOTE the stdlib must be in the arena; just taking a reference will segfault
let stdlib = arena.alloc(roc_builtins::std::standard_stdlib());
let instance = crate::helpers::eval::helper_wasm(&arena, src, stdlib, &expected);
let instance = crate::helpers::wasm::helper_wasm(&arena, src, stdlib, &expected);
let memory = instance.exports.get_memory("memory").unwrap();
let memory = instance.exports.get_memory("__linear_memory").unwrap();
let test_wrapper = instance.exports.get_function(TEST_WRAPPER_NAME).unwrap();
@ -190,10 +190,10 @@ where
}
}
#[macro_export]
#[allow(unused_macros)]
macro_rules! assert_wasm_evals_to {
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
match $crate::helpers::eval::assert_wasm_evals_to_help::<$ty>($src, $expected) {
match $crate::helpers::wasm::assert_wasm_evals_to_help::<$ty>($src, $expected) {
Err(msg) => panic!("{:?}", msg),
Ok(actual) => {
assert_eq!($transform(actual), $expected)
@ -202,23 +202,28 @@ macro_rules! assert_wasm_evals_to {
};
($src:expr, $expected:expr, $ty:ty) => {
$crate::assert_wasm_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity);
$crate::helpers::wasm::assert_wasm_evals_to!(
$src,
$expected,
$ty,
$crate::helpers::wasm::identity
);
};
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
$crate::assert_wasm_evals_to!($src, $expected, $ty, $transform);
$crate::helpers::wasm::assert_wasm_evals_to!($src, $expected, $ty, $transform);
};
}
#[macro_export]
#[allow(unused_macros)]
macro_rules! assert_evals_to {
($src:expr, $expected:expr, $ty:ty) => {{
assert_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity);
assert_evals_to!($src, $expected, $ty, $crate::helpers::wasm::identity);
}};
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
// Same as above, except with an additional transformation argument.
{
$crate::assert_wasm_evals_to!($src, $expected, $ty, $transform);
$crate::helpers::wasm::assert_wasm_evals_to!($src, $expected, $ty, $transform);
}
};
}
@ -227,3 +232,8 @@ macro_rules! assert_evals_to {
pub fn identity<T>(value: T) -> T {
value
}
#[allow(unused_imports)]
pub(crate) use assert_evals_to;
#[allow(unused_imports)]
pub(crate) use assert_wasm_evals_to;

View file

@ -1,33 +1,42 @@
use bumpalo::collections::Vec;
use roc_gen_wasm::wasm_module::opcodes;
use crate::helpers::from_wasm32_memory::FromWasm32Memory;
use roc_gen_wasm::wasm_module::{
Align, CodeBuilder, Export, ExportType, LocalId, Signature, ValueType, WasmModule,
linking::SymInfo, linking::WasmObjectSymbol, Align, CodeBuilder, Export, ExportType, LocalId,
Signature, ValueType, WasmModule,
};
use roc_std::{RocDec, RocList, RocOrder, RocStr};
use test_wasm_util::from_wasm32_memory::FromWasm32Memory;
pub trait Wasm32TestResult {
fn insert_test_wrapper<'a>(
arena: &'a bumpalo::Bump,
wasm_module: &mut WasmModule<'a>,
module: &mut WasmModule<'a>,
wrapper_name: &str,
main_function_index: u32,
) {
wasm_module.add_function_signature(Signature {
let index = module.code.code_builders.len() as u32;
module.add_function_signature(Signature {
param_types: Vec::with_capacity_in(0, arena),
ret_type: Some(ValueType::I32),
});
wasm_module.export.entries.push(Export {
module.export.entries.push(Export {
name: wrapper_name.to_string(),
ty: ExportType::Func,
index: wasm_module.code.code_builders.len() as u32,
index,
});
let symbol_table = module.linking.symbol_table_mut();
symbol_table.push(SymInfo::Function(WasmObjectSymbol::Defined {
flags: 0,
index,
name: wrapper_name.to_string(),
}));
let mut code_builder = CodeBuilder::new(arena);
Self::build_wrapper_body(&mut code_builder, main_function_index);
wasm_module.code.code_builders.push(code_builder);
module.code.code_builders.push(code_builder);
}
fn build_wrapper_body(code_builder: &mut CodeBuilder, main_function_index: u32);
@ -40,14 +49,15 @@ macro_rules! build_wrapper_body_primitive {
let frame_pointer = Some(frame_pointer_id);
let local_types = &[ValueType::I32];
let frame_size = 8;
// Main's symbol index is the same as its function index, since the first symbols we created were for procs
let main_symbol_index = main_function_index;
code_builder.get_local(frame_pointer_id);
// Raw "call" instruction. Don't bother with symbol & relocation since we're not going to link.
code_builder.inst_imm32(opcodes::CALL, 0, true, main_function_index);
code_builder.call(main_function_index, main_symbol_index, 0, true);
code_builder.$store_instruction($align, 0);
code_builder.get_local(frame_pointer_id);
code_builder.finalize(local_types, frame_size, frame_pointer);
code_builder.build_fn_header(local_types, frame_size, frame_pointer);
}
};
}
@ -68,12 +78,13 @@ fn build_wrapper_body_stack_memory(
let local_id = LocalId(0);
let local_types = &[ValueType::I32];
let frame_pointer = Some(local_id);
// Main's symbol index is the same as its function index, since the first symbols we created were for procs
let main_symbol_index = main_function_index;
code_builder.get_local(local_id);
// Raw "call" instruction. Don't bother with symbol & relocation since we're not going to link.
code_builder.inst_imm32(opcodes::CALL, 0, true, main_function_index);
code_builder.call(main_function_index, main_symbol_index, 0, true);
code_builder.get_local(local_id);
code_builder.finalize(local_types, size as i32, frame_pointer);
code_builder.build_fn_header(local_types, size as i32, frame_pointer);
}
macro_rules! wasm_test_result_stack_memory {
@ -101,6 +112,7 @@ wasm_test_result_primitive!(u32, i32_store, Align::Bytes4);
wasm_test_result_primitive!(i32, i32_store, Align::Bytes4);
wasm_test_result_primitive!(u64, i64_store, Align::Bytes8);
wasm_test_result_primitive!(i64, i64_store, Align::Bytes8);
wasm_test_result_primitive!(usize, i32_store, Align::Bytes4);
wasm_test_result_primitive!(f32, f32_store, Align::Bytes8);
wasm_test_result_primitive!(f64, f64_store, Align::Bytes8);

View file

@ -10,8 +10,48 @@ pub mod gen_list;
pub mod gen_num;
pub mod gen_primitives;
pub mod gen_records;
pub mod gen_result;
pub mod gen_set;
pub mod gen_str;
pub mod gen_tags;
mod helpers;
pub mod wasm_str;
use core::ffi::c_void;
#[no_mangle]
pub unsafe fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void {
libc::malloc(size)
}
#[no_mangle]
pub unsafe fn roc_realloc(
c_ptr: *mut c_void,
new_size: usize,
_old_size: usize,
_alignment: u32,
) -> *mut c_void {
libc::realloc(c_ptr, new_size)
}
#[no_mangle]
pub unsafe fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) {
libc::free(c_ptr)
}
#[no_mangle]
pub unsafe fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
use roc_gen_llvm::llvm::build::PanicTagId;
use std::convert::TryFrom;
use std::ffi::CStr;
use std::os::raw::c_char;
match PanicTagId::try_from(tag_id) {
Ok(PanicTagId::NullTerminatedString) => {
let slice = CStr::from_ptr(c_ptr as *const c_char);
let string = slice.to_str().unwrap();
eprintln!("Roc hit a panic: {}", string);
std::process::exit(1);
}
Err(_) => unreachable!(),
}
}

View file

@ -1,6 +1,16 @@
#![cfg(test)]
// Wasm pointers are only 32bit. This effects RocStr.
// These are versions of the str tests assuming 32bit pointers.
#![cfg(not(feature = "gen-dev"))]
use crate::assert_evals_to;
// TODO: We need to make these tests work with the llvm wasm backend.
// #[cfg(feature = "gen-llvm")]
// use crate::helpers::llvm::assert_wasm_evals_to as assert_evals_to;
#[cfg(feature = "gen-wasm")]
use crate::helpers::wasm::assert_evals_to;
#[allow(unused_imports)]
use indoc::indoc;
// use roc_std::RocStr;
@ -228,6 +238,7 @@ use indoc::indoc;
// }
#[test]
#[cfg(any(feature = "gen-wasm"))]
fn small_str_literal() {
assert_evals_to!(
"\"JJJJJJJ\"",
@ -237,6 +248,7 @@ fn small_str_literal() {
}
#[test]
#[cfg(any(feature = "gen-wasm"))]
fn small_str_zeroed_literal() {
// Verifies that we zero out unused bytes in the string.
// This is important so that string equality tests don't randomly

View file

@ -1,30 +0,0 @@
[package]
name = "test_wasm"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[test]]
name = "test_wasm"
path = "src/tests.rs"
[dev-dependencies]
# roc_module = { path = "../module" }
# roc_mono = { path = "../mono" }
wasmer = { version = "2.0.0", default-features = false, features = ["default-cranelift", "default-universal"] }
wasmer-wasi = "2.0.0"
roc_collections = { path = "../collections" }
roc_std = { path = "../../roc_std" }
bumpalo = { version = "3.8.0", features = ["collections"] }
roc_gen_wasm = { path = "../gen_wasm" }
roc_can = { path = "../can" }
roc_builtins = { path = "../builtins" }
roc_load = { path = "../load" }
roc_types = { path = "../types" }
roc_module = { path = "../module" }
test_wasm_util = { path = "../test_wasm_util" }
indoc = "1.0.3"
libc = "0.2.106"
target-lexicon = "0.12.2"

View file

@ -1,43 +0,0 @@
#[macro_use]
pub mod eval;
pub mod wasm32_test_result;
/// Used in the with_larger_debug_stack() function, for tests that otherwise
/// run out of stack space in debug builds (but don't in --release builds)
#[allow(dead_code)]
const EXPANDED_STACK_SIZE: usize = 8 * 1024 * 1024;
/// Without this, some tests pass in `cargo test --release` but fail without
/// the --release flag because they run out of stack space. This increases
/// stack size for debug builds only, while leaving the stack space at the default
/// amount for release builds.
#[allow(dead_code)]
#[cfg(debug_assertions)]
pub fn with_larger_debug_stack<F>(run_test: F)
where
F: FnOnce(),
F: Send,
F: 'static,
{
std::thread::Builder::new()
.stack_size(EXPANDED_STACK_SIZE)
.spawn(run_test)
.expect("Error while spawning expanded dev stack size thread")
.join()
.expect("Error while joining expanded dev stack size thread")
}
/// In --release builds, don't increase the stack size. Run the test normally.
/// This way, we find out if any of our tests are blowing the stack even after
/// optimizations in release builds.
#[allow(dead_code)]
#[cfg(not(debug_assertions))]
#[inline(always)]
pub fn with_larger_debug_stack<F>(run_test: F)
where
F: FnOnce() -> (),
F: Send,
F: 'static,
{
run_test()
}

View file

@ -1,4 +0,0 @@
pub mod helpers;
pub mod wasm_num;
pub mod wasm_records;
pub mod wasm_str;

File diff suppressed because it is too large Load diff

View file

@ -1,911 +0,0 @@
#![cfg(all(test, target_os = "linux", any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
use crate::assert_evals_to;
use indoc::indoc;
// #[test]
// fn basic_record() {
// assert_evals_to!(
// indoc!(
// r#"
// { y: 17, x: 15, z: 19 }.x
// "#
// ),
// 15,
// i64
// );
//
// assert_evals_to!(
// indoc!(
// r#"
// { x: 15, y: 17, z: 19 }.y
// "#
// ),
// 17,
// i64
// );
//
// assert_evals_to!(
// indoc!(
// r#"
// { x: 15, y: 17, z: 19 }.z
// "#
// ),
// 19,
// i64
// );
// }
//
// #[test]
// fn nested_record() {
// assert_evals_to!(
// indoc!(
// r#"
// { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.x
// "#
// ),
// 15,
// i64
// );
//
// assert_evals_to!(
// indoc!(
// r#"
// { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.a
// "#
// ),
// 12,
// i64
// );
//
// assert_evals_to!(
// indoc!(
// r#"
// { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.b
// "#
// ),
// 15,
// i64
// );
//
// assert_evals_to!(
// indoc!(
// r#"
// { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.c
// "#
// ),
// 2,
// i64
// );
//
// assert_evals_to!(
// indoc!(
// r#"
// { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.z
// "#
// ),
// 19,
// i64
// );
// }
//
// #[test]
// fn f64_record() {
// assert_evals_to!(
// indoc!(
// r#"
// rec = { y: 17.2, x: 15.1, z: 19.3 }
//
// rec.x
// "#
// ),
// 15.1,
// f64
// );
//
// assert_evals_to!(
// indoc!(
// r#"
// rec = { y: 17.2, x: 15.1, z: 19.3 }
//
// rec.y
// "#
// ),
// 17.2,
// f64
// );
//
// assert_evals_to!(
// indoc!(
// r#"
// rec = { y: 17.2, x: 15.1, z: 19.3 }
//
// rec.z
// "#
// ),
// 19.3,
// f64
// );
// }
// #[test]
// fn fn_record() {
// assert_evals_to!(
// indoc!(
// r#"
// getRec = \x -> { y: 17, x, z: 19 }
// (getRec 15).x
// "#
// ),
// 15,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// rec = { x: 15, y: 17, z: 19 }
// rec.y
// "#
// ),
// 17,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// rec = { x: 15, y: 17, z: 19 }
// rec.z
// "#
// ),
// 19,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// rec = { x: 15, y: 17, z: 19 }
// rec.z + rec.x
// "#
// ),
// 34,
// i64
// );
// }
// #[test]
// fn def_record() {
// assert_evals_to!(
// indoc!(
// r#"
// rec = { y: 17, x: 15, z: 19 }
//
// rec.x
// "#
// ),
// 15,
// i64
// );
//
// assert_evals_to!(
// indoc!(
// r#"
// rec = { x: 15, y: 17, z: 19 }
//
// rec.y
// "#
// ),
// 17,
// i64
// );
//
// assert_evals_to!(
// indoc!(
// r#"
// rec = { x: 15, y: 17, z: 19 }
//
// rec.z
// "#
// ),
// 19,
// i64
// );
// }
//
// #[test]
// fn when_on_record() {
// assert_evals_to!(
// indoc!(
// r#"
// when { x: 0x2 } is
// { x } -> x + 3
// "#
// ),
// 5,
// i64
// );
// }
//
// #[test]
// fn when_record_with_guard_pattern() {
// assert_evals_to!(
// indoc!(
// r#"
// when { x: 0x2, y: 3.14 } is
// { x: var } -> var + 3
// "#
// ),
// 5,
// i64
// );
// }
//
// #[test]
// fn let_with_record_pattern() {
// assert_evals_to!(
// indoc!(
// r#"
// { x } = { x: 0x2, y: 3.14 }
//
// x
// "#
// ),
// 2,
// i64
// );
// }
//
// #[test]
// fn record_guard_pattern() {
// assert_evals_to!(
// indoc!(
// r#"
// when { x: 0x2, y: 3.14 } is
// { x: 0x4 } -> 5
// { x } -> x + 3
// "#
// ),
// 5,
// i64
// );
// }
//
// #[test]
// fn twice_record_access() {
// assert_evals_to!(
// indoc!(
// r#"
// x = {a: 0x2, b: 0x3 }
//
// x.a + x.b
// "#
// ),
// 5,
// i64
// );
// }
// #[test]
// fn empty_record() {
// assert_evals_to!(
// indoc!(
// r#"
// v = {}
//
// v
// "#
// ),
// (),
// ()
// );
// }
#[test]
fn i64_record1_literal() {
assert_evals_to!(
indoc!(
r#"
{ x: 3 }
"#
),
3,
i64
);
}
#[test]
fn i64_record2_literal() {
assert_evals_to!(
indoc!(
r#"
{ x: 3, y: 5 }
"#
),
(3, 5),
(i64, i64)
);
}
#[test]
fn i64_record3_literal() {
assert_evals_to!(
indoc!(
r#"
{ x: 3, y: 5, z: 17 }
"#
),
(3, 5, 17),
(i64, i64, i64)
);
}
#[test]
fn f64_record2_literal() {
assert_evals_to!(
indoc!(
r#"
{ x: 3.1, y: 5.1 }
"#
),
(3.1, 5.1),
(f64, f64)
);
}
#[test]
fn f64_record3_literal() {
assert_evals_to!(
indoc!(
r#"
{ x: 3.1, y: 5.1, z: 17.1 }
"#
),
(3.1, 5.1, 17.1),
(f64, f64, f64)
);
}
#[test]
fn bool_record4_literal() {
assert_evals_to!(
indoc!(
r#"
record : { a : Bool, b : Bool, c : Bool, d : Bool }
record = { a: True, b: False, c : False, d : True }
record
"#
),
[true, false, false, true],
[bool; 4]
);
}
#[test]
fn i64_record9_literal() {
assert_evals_to!(
indoc!(
r#"
{ a: 3, b: 5, c: 17, d: 1, e: 9, f: 12, g: 13, h: 14, i: 15 }
"#
),
[3, 5, 17, 1, 9, 12, 13, 14, 15],
[i64; 9]
);
}
#[test]
fn bool_literal() {
assert_evals_to!(
indoc!(
r#"
x : Bool
x = True
x
"#
),
true,
bool
);
}
// #[test]
// fn optional_field_when_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// main =
// a = f { x: Blue, y: 7 }
// b = f { x: Blue }
// c = f { x: Red, y: 11 }
// d = f { x: Red }
// a * b * c * d
// "#
// ),
// 3 * 5 * 7 * 11,
// i64
// );
// }
// #[test]
// fn optional_field_when_use_default_nested() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// a = f { x: Blue, y: 7 }
// b = f { x: Blue }
// c = f { x: Red, y: 11 }
// d = f { x: Red }
// a * b * c * d
// "#
// ),
// 3 * 5 * 7 * 11,
// i64
// );
// }
// #[test]
// fn optional_field_when_no_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// { x ? 10, y } = r
// x + y
// main =
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_when_no_use_default_nested() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// { x ? 10, y } = r
// x + y
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_let_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// { x ? 10, y } = r
// x + y
// main =
// f { y: 9 }
// "#
// ),
// 19,
// i64
// );
// }
// #[test]
// fn optional_field_let_no_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \r ->
// { x ? 10, y } = r
// x + y
// main =
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_let_no_use_default_nested() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// { x ? 10, y } = r
// x + y
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_function_use_default() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \{ x ? 10, y } -> x + y
// f { y: 9 }
// "#
// ),
// 19,
// i64
// );
// }
// #[test]
// #[ignore]
// fn optional_field_function_no_use_default() {
// // blocked on https://github.com/rtfeldman/roc/issues/786
// assert_evals_to!(
// indoc!(
// r#"
// app "test" provides [ main ] to "./platform"
// f = \{ x ? 10, y } -> x + y
// main =
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// #[ignore]
// fn optional_field_function_no_use_default_nested() {
// // blocked on https://github.com/rtfeldman/roc/issues/786
// assert_evals_to!(
// indoc!(
// r#"
// f = \{ x ? 10, y } -> x + y
// f { x: 4, y: 9 }
// "#
// ),
// 13,
// i64
// );
// }
// #[test]
// fn optional_field_singleton_record() {
// assert_evals_to!(
// indoc!(
// r#"
// when { x : 4 } is
// { x ? 3 } -> x
// "#
// ),
// 4,
// i64
// );
// }
// #[test]
// fn optional_field_empty_record() {
// assert_evals_to!(
// indoc!(
// r#"
// when { } is
// { x ? 3 } -> x
// "#
// ),
// 3,
// i64
// );
// }
#[test]
fn return_record_3() {
assert_evals_to!(
indoc!(
r#"
{ x: 3, y: 5, z: 4 }
"#
),
(3, 5, 4),
(i64, i64, i64)
);
}
#[test]
fn return_record_4() {
assert_evals_to!(
indoc!(
r#"
{ a: 3, b: 5, c: 4, d: 2 }
"#
),
[3, 5, 4, 2],
[i64; 4]
);
}
#[test]
fn return_record_5() {
assert_evals_to!(
indoc!(
r#"
{ a: 3, b: 5, c: 4, d: 2, e: 1 }
"#
),
[3, 5, 4, 2, 1],
[i64; 5]
);
}
#[test]
fn return_record_6() {
assert_evals_to!(
indoc!(
r#"
{ a: 3, b: 5, c: 4, d: 2, e: 1, f: 7 }
"#
),
[3, 5, 4, 2, 1, 7],
[i64; 6]
);
}
#[test]
fn return_record_7() {
assert_evals_to!(
indoc!(
r#"
{ a: 3, b: 5, c: 4, d: 2, e: 1, f: 7, g: 8 }
"#
),
[3, 5, 4, 2, 1, 7, 8],
[i64; 7]
);
}
#[test]
fn return_record_float_int() {
assert_evals_to!(
indoc!(
r#"
{ a: 3.14, b: 0x1 }
"#
),
(3.14, 0x1),
(f64, i64)
);
}
#[test]
fn return_record_int_float() {
assert_evals_to!(
indoc!(
r#"
{ a: 0x1, b: 3.14 }
"#
),
(0x1, 3.14),
(i64, f64)
);
}
#[test]
fn return_record_float_float() {
assert_evals_to!(
indoc!(
r#"
{ a: 6.28, b: 3.14 }
"#
),
(6.28, 3.14),
(f64, f64)
);
}
#[test]
fn return_record_float_float_float() {
assert_evals_to!(
indoc!(
r#"
{ a: 6.28, b: 3.14, c: 0.1 }
"#
),
(6.28, 3.14, 0.1),
(f64, f64, f64)
);
}
// #[test]
// fn return_nested_record() {
// assert_evals_to!(
// indoc!(
// r#"
// { flag: 0x0, payload: { a: 6.28, b: 3.14, c: 0.1 } }
// "#
// ),
// (0x0, (6.28, 3.14, 0.1)),
// (i64, (f64, f64, f64))
// );
// }
// #[test]
// fn accessor() {
// assert_evals_to!(
// indoc!(
// r#"
// .foo { foo: 4 } + .foo { bar: 6.28, foo: 3 }
// "#
// ),
// 7,
// i64
// );
// }
// #[test]
// fn accessor_single_element_record() {
// assert_evals_to!(
// indoc!(
// r#"
// .foo { foo: 4 }
// "#
// ),
// 4,
// i64
// );
// }
// #[test]
// fn update_record() {
// assert_evals_to!(
// indoc!(
// r#"
// rec = { foo: 42, bar: 6 }
// { rec & foo: rec.foo + 1 }
// "#
// ),
// (6, 43),
// (i64, i64)
// );
// }
// #[test]
// fn update_single_element_record() {
// assert_evals_to!(
// indoc!(
// r#"
// rec = { foo: 42}
// { rec & foo: rec.foo + 1 }
// "#
// ),
// 43,
// i64
// );
// }
// #[test]
// fn booleans_in_record() {
// assert_evals_to!(
// indoc!("{ x: 1 == 1, y: 1 == 1 }"),
// (true, true),
// (bool, bool)
// );
// assert_evals_to!(
// indoc!("{ x: 1 != 1, y: 1 == 1 }"),
// (false, true),
// (bool, bool)
// );
// assert_evals_to!(
// indoc!("{ x: 1 == 1, y: 1 != 1 }"),
// (true, false),
// (bool, bool)
// );
// assert_evals_to!(
// indoc!("{ x: 1 != 1, y: 1 != 1 }"),
// (false, false),
// (bool, bool)
// );
// }
// #[test]
// fn alignment_in_record() {
// assert_evals_to!(
// indoc!("{ c: 32, b: if True then Red else if True then Green else Blue, a: 1 == 1 }"),
// (32i64, true, 2u8),
// (i64, bool, u8)
// );
// }
#[test]
fn stack_memory_return_from_branch() {
// stack memory pointer should end up in the right place after returning from a branch
assert_evals_to!(
indoc!(
r#"
stackMemoryJunk = { x: 999, y: 111 }
if True then
{ x: 123, y: 321 }
else
stackMemoryJunk
"#
),
(123, 321),
(i64, i64)
);
}
// #[test]
// fn blue_and_present() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// f { x: Blue, y: 7 }
// "#
// ),
// 7,
// i64
// );
// }
// #[test]
// fn blue_and_absent() {
// assert_evals_to!(
// indoc!(
// r#"
// f = \r ->
// when r is
// { x: Blue, y ? 3 } -> y
// { x: Red, y ? 5 } -> y
// f { x: Blue }
// "#
// ),
// 3,
// i64
// );
// }

File diff suppressed because it is too large Load diff

View file

@ -1,13 +0,0 @@
[package]
name = "test_wasm_util"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# roc_module = { path = "../module" }
# roc_mono = { path = "../mono" }
wasmer = { version = "2.0.0", default-features = false, features = ["default-cranelift", "default-universal"] }
roc_std = { path = "../../roc_std" }

View file

@ -1 +0,0 @@
pub mod from_wasm32_memory;