This commit is contained in:
Folkert 2021-10-17 20:45:49 +02:00
parent 434ccbbf68
commit a4f7ddb1f5
6 changed files with 3 additions and 1061 deletions

View file

@ -952,32 +952,6 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
}
CallType::HigherOrderLowLevel {
op,
function_owns_closure_data,
specialization_id,
arg_layouts,
ret_layout,
..
} => {
let bytes = specialization_id.to_bytes();
let callee_var = CalleeSpecVar(&bytes);
let func_spec = func_spec_solutions.callee_spec(callee_var).unwrap();
run_higher_order_low_level(
env,
layout_ids,
scope,
layout,
*op,
func_spec,
arg_layouts,
ret_layout,
*function_owns_closure_data,
arguments,
)
}
CallType::NewHigherOrderLowLevel {
op,
function_owns_closure_data,
specialization_id,
@ -4895,451 +4869,6 @@ fn run_new_higher_order_low_level<'a, 'ctx, 'env>(
}
}
#[allow(clippy::too_many_arguments)]
fn run_higher_order_low_level<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
scope: &Scope<'a, 'ctx>,
return_layout: &Layout<'a>,
op: LowLevel,
func_spec: FuncSpec,
argument_layouts: &[Layout<'a>],
result_layout: &Layout<'a>,
function_owns_closure_data: bool,
args: &[Symbol],
) -> BasicValueEnum<'ctx> {
use LowLevel::*;
debug_assert!(op.is_higher_order());
// macros because functions cause lifetime issues related to the `env` or `layout_ids`
macro_rules! passed_function_at_index {
($index:expr) => {{
let function_symbol = args[$index];
function_value_by_func_spec(
env,
func_spec,
function_symbol,
argument_layouts,
return_layout,
)
}};
}
macro_rules! list_walk {
($variant:expr) => {{
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let (default, default_layout) = load_symbol_and_layout(scope, &args[1]);
let function = passed_function_at_index!(2);
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[3]);
match list_layout {
Layout::Builtin(Builtin::EmptyList) => default,
Layout::Builtin(Builtin::List(element_layout)) => {
let argument_layouts = &[*default_layout, **element_layout];
let roc_function_call = roc_function_call(
env,
layout_ids,
function,
closure,
closure_layout,
function_owns_closure_data,
argument_layouts,
);
crate::llvm::build_list::list_walk_generic(
env,
layout_ids,
roc_function_call,
result_layout,
list,
element_layout,
default,
default_layout,
$variant,
)
}
_ => unreachable!("invalid list layout"),
}
}};
}
match op {
ListMap => {
// List.map : List before, (before -> after) -> List after
debug_assert_eq!(args.len(), 3);
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let function = passed_function_at_index!(1);
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
match (list_layout, return_layout) {
(Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
(
Layout::Builtin(Builtin::List(element_layout)),
Layout::Builtin(Builtin::List(result_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_map(env, roc_function_call, list, element_layout, result_layout)
}
_ => unreachable!("invalid list layout"),
}
}
ListMap2 => {
debug_assert_eq!(args.len(), 4);
let (list1, list1_layout) = load_symbol_and_layout(scope, &args[0]);
let (list2, list2_layout) = load_symbol_and_layout(scope, &args[1]);
let function = passed_function_at_index!(2);
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[3]);
match (list1_layout, list2_layout, return_layout) {
(
Layout::Builtin(Builtin::List(element1_layout)),
Layout::Builtin(Builtin::List(element2_layout)),
Layout::Builtin(Builtin::List(result_layout)),
) => {
let argument_layouts = &[**element1_layout, **element2_layout];
let roc_function_call = roc_function_call(
env,
layout_ids,
function,
closure,
closure_layout,
function_owns_closure_data,
argument_layouts,
);
list_map2(
env,
layout_ids,
roc_function_call,
list1,
list2,
element1_layout,
element2_layout,
result_layout,
)
}
(Layout::Builtin(Builtin::EmptyList), _, _)
| (_, Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
_ => unreachable!("invalid list layout"),
}
}
ListMap3 => {
debug_assert_eq!(args.len(), 5);
let (list1, list1_layout) = load_symbol_and_layout(scope, &args[0]);
let (list2, list2_layout) = load_symbol_and_layout(scope, &args[1]);
let (list3, list3_layout) = load_symbol_and_layout(scope, &args[2]);
let function = passed_function_at_index!(3);
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[4]);
match (list1_layout, list2_layout, list3_layout, return_layout) {
(
Layout::Builtin(Builtin::List(element1_layout)),
Layout::Builtin(Builtin::List(element2_layout)),
Layout::Builtin(Builtin::List(element3_layout)),
Layout::Builtin(Builtin::List(result_layout)),
) => {
let argument_layouts =
&[**element1_layout, **element2_layout, **element3_layout];
let roc_function_call = roc_function_call(
env,
layout_ids,
function,
closure,
closure_layout,
function_owns_closure_data,
argument_layouts,
);
list_map3(
env,
layout_ids,
roc_function_call,
list1,
list2,
list3,
element1_layout,
element2_layout,
element3_layout,
result_layout,
)
}
(Layout::Builtin(Builtin::EmptyList), _, _, _)
| (_, Layout::Builtin(Builtin::EmptyList), _, _)
| (_, _, Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
_ => unreachable!("invalid list layout"),
}
}
ListMapWithIndex => {
// List.mapWithIndex : List before, (Nat, before -> after) -> List after
debug_assert_eq!(args.len(), 3);
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let function = passed_function_at_index!(1);
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
match (list_layout, return_layout) {
(Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
(
Layout::Builtin(Builtin::List(element_layout)),
Layout::Builtin(Builtin::List(result_layout)),
) => {
let argument_layouts = &[Layout::Builtin(Builtin::Usize), **element_layout];
let roc_function_call = roc_function_call(
env,
layout_ids,
function,
closure,
closure_layout,
function_owns_closure_data,
argument_layouts,
);
list_map_with_index(env, roc_function_call, list, element_layout, result_layout)
}
_ => unreachable!("invalid list layout"),
}
}
ListKeepIf => {
// List.keepIf : List elem, (elem -> Bool) -> List elem
debug_assert_eq!(args.len(), 3);
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let function = passed_function_at_index!(1);
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
match list_layout {
Layout::Builtin(Builtin::EmptyList) => empty_list(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_keep_if(env, layout_ids, roc_function_call, list, element_layout)
}
_ => unreachable!("invalid list layout"),
}
}
ListKeepOks => {
// List.keepOks : List before, (before -> Result after *) -> List after
debug_assert_eq!(args.len(), 3);
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let function = passed_function_at_index!(1);
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
match (list_layout, return_layout) {
(_, Layout::Builtin(Builtin::EmptyList))
| (Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
(
Layout::Builtin(Builtin::List(before_layout)),
Layout::Builtin(Builtin::List(after_layout)),
) => {
let argument_layouts = &[**before_layout];
let roc_function_call = roc_function_call(
env,
layout_ids,
function,
closure,
closure_layout,
function_owns_closure_data,
argument_layouts,
);
list_keep_oks(
env,
layout_ids,
roc_function_call,
result_layout,
list,
before_layout,
after_layout,
)
}
(other1, other2) => {
unreachable!("invalid list layouts:\n{:?}\n{:?}", other1, other2)
}
}
}
ListKeepErrs => {
// List.keepErrs : List before, (before -> Result * after) -> List after
debug_assert_eq!(args.len(), 3);
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let function = passed_function_at_index!(1);
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
match (list_layout, return_layout) {
(_, Layout::Builtin(Builtin::EmptyList))
| (Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
(
Layout::Builtin(Builtin::List(before_layout)),
Layout::Builtin(Builtin::List(after_layout)),
) => {
let argument_layouts = &[**before_layout];
let roc_function_call = roc_function_call(
env,
layout_ids,
function,
closure,
closure_layout,
function_owns_closure_data,
argument_layouts,
);
list_keep_errs(
env,
layout_ids,
roc_function_call,
result_layout,
list,
before_layout,
after_layout,
)
}
(other1, other2) => {
unreachable!("invalid list layouts:\n{:?}\n{:?}", other1, other2)
}
}
}
ListWalk => {
list_walk!(crate::llvm::build_list::ListWalk::Walk)
}
ListWalkUntil => {
list_walk!(crate::llvm::build_list::ListWalk::WalkUntil)
}
ListWalkBackwards => {
list_walk!(crate::llvm::build_list::ListWalk::WalkBackwards)
}
ListSortWith => {
// List.sortWith : List a, (a, a -> Ordering) -> List a
debug_assert_eq!(args.len(), 3);
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let function = passed_function_at_index!(1);
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
match list_layout {
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
Layout::Builtin(Builtin::List(element_layout)) => {
use crate::llvm::bitcode::build_compare_wrapper;
let argument_layouts = &[**element_layout, **element_layout];
let compare_wrapper =
build_compare_wrapper(env, function, closure_layout, element_layout)
.as_global_value()
.as_pointer_value();
let roc_function_call = roc_function_call(
env,
layout_ids,
function,
closure,
closure_layout,
function_owns_closure_data,
argument_layouts,
);
list_sort_with(
env,
roc_function_call,
compare_wrapper,
list,
element_layout,
)
}
_ => unreachable!("invalid list layout"),
}
}
DictWalk => {
debug_assert_eq!(args.len(), 4);
let (dict, dict_layout) = load_symbol_and_layout(scope, &args[0]);
let (default, default_layout) = load_symbol_and_layout(scope, &args[1]);
let function = passed_function_at_index!(2);
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[3]);
match dict_layout {
Layout::Builtin(Builtin::EmptyDict) => {
// no elements, so `key` is not in here
panic!("key type unknown")
}
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
let argument_layouts = &[*default_layout, **key_layout, **value_layout];
let roc_function_call = roc_function_call(
env,
layout_ids,
function,
closure,
closure_layout,
function_owns_closure_data,
argument_layouts,
);
dict_walk(
env,
roc_function_call,
dict,
default,
key_layout,
value_layout,
default_layout,
)
}
_ => unreachable!("invalid dict layout"),
}
}
_ => unreachable!(),
}
}
// TODO: Fix me! I should be different in tests vs. user code!
fn expect_failed() {
panic!("An expectation failed!");