Merge pull request #2109 from rtfeldman/refactor-passed-function

refactor passed (to higher order lowlevel) funcion
This commit is contained in:
Richard Feldman 2021-12-01 08:17:39 -05:00 committed by GitHub
commit e6bec46898
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 95 additions and 88 deletions

View file

@ -955,7 +955,7 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
} }
CallType::HigherOrder(higher_order) => { CallType::HigherOrder(higher_order) => {
let bytes = higher_order.specialization_id.to_bytes(); let bytes = higher_order.passed_function.specialization_id.to_bytes();
let callee_var = CalleeSpecVar(&bytes); let callee_var = CalleeSpecVar(&bytes);
let func_spec = func_spec_solutions.callee_spec(callee_var).unwrap(); let func_spec = func_spec_solutions.callee_spec(callee_var).unwrap();
@ -4686,20 +4686,23 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
func_spec: FuncSpec, func_spec: FuncSpec,
higher_order: &HigherOrderLowLevel<'a>, higher_order: &HigherOrderLowLevel<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
use roc_mono::ir::PassedFunction;
use roc_mono::low_level::HigherOrder::*; use roc_mono::low_level::HigherOrder::*;
let HigherOrderLowLevel { let HigherOrderLowLevel {
op, op,
arg_layouts: argument_layouts, passed_function,
ret_layout: result_layout,
function_owns_closure_data,
function_name,
function_env,
.. ..
} = higher_order; } = higher_order;
let function_owns_closure_data = *function_owns_closure_data; let PassedFunction {
let function_name = *function_name; argument_layouts,
return_layout: result_layout,
owns_captured_environment: function_owns_closure_data,
name: function_name,
captured_environment,
..
} = *passed_function;
// macros because functions cause lifetime issues related to the `env` or `layout_ids` // macros because functions cause lifetime issues related to the `env` or `layout_ids`
macro_rules! function_details { macro_rules! function_details {
@ -4712,7 +4715,8 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
return_layout, return_layout,
); );
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, function_env); let (closure, closure_layout) =
load_symbol_and_lambda_set(scope, &captured_environment);
(function, closure, closure_layout) (function, closure, closure_layout)
}}; }};
@ -4737,14 +4741,14 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout, closure_layout,
function_owns_closure_data, function_owns_closure_data,
argument_layouts, argument_layouts,
*result_layout, result_layout,
); );
crate::llvm::build_list::list_walk_generic( crate::llvm::build_list::list_walk_generic(
env, env,
layout_ids, layout_ids,
roc_function_call, roc_function_call,
result_layout, &result_layout,
list, list,
element_layout, element_layout,
default, default,
@ -4974,7 +4978,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout, closure_layout,
function_owns_closure_data, function_owns_closure_data,
argument_layouts, argument_layouts,
*result_layout, result_layout,
); );
list_keep_if(env, layout_ids, roc_function_call, list, element_layout) list_keep_if(env, layout_ids, roc_function_call, list, element_layout)
@ -5003,14 +5007,14 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout, closure_layout,
function_owns_closure_data, function_owns_closure_data,
argument_layouts, argument_layouts,
*result_layout, result_layout,
); );
list_keep_oks( list_keep_oks(
env, env,
layout_ids, layout_ids,
roc_function_call, roc_function_call,
result_layout, &result_layout,
list, list,
before_layout, before_layout,
after_layout, after_layout,
@ -5042,14 +5046,14 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout, closure_layout,
function_owns_closure_data, function_owns_closure_data,
argument_layouts, argument_layouts,
*result_layout, result_layout,
); );
list_keep_errs( list_keep_errs(
env, env,
layout_ids, layout_ids,
roc_function_call, roc_function_call,
result_layout, &result_layout,
list, list,
before_layout, before_layout,
after_layout, after_layout,
@ -5094,7 +5098,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout, closure_layout,
function_owns_closure_data, function_owns_closure_data,
argument_layouts, argument_layouts,
*result_layout, result_layout,
); );
list_sort_with( list_sort_with(
@ -5197,7 +5201,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout, closure_layout,
function_owns_closure_data, function_owns_closure_data,
argument_layouts, argument_layouts,
*result_layout, result_layout,
); );
dict_walk( dict_walk(

View file

@ -702,30 +702,30 @@ fn call_spec(
call.arguments, call.arguments,
), ),
HigherOrder(HigherOrderLowLevel { HigherOrder(HigherOrderLowLevel {
specialization_id,
closure_env_layout, closure_env_layout,
update_mode, update_mode,
op, op,
arg_layouts, passed_function,
ret_layout,
function_name,
function_env,
.. ..
}) => { }) => {
use crate::low_level::HigherOrder::*; use crate::low_level::HigherOrder::*;
let array = specialization_id.to_bytes(); let array = passed_function.specialization_id.to_bytes();
let spec_var = CalleeSpecVar(&array); let spec_var = CalleeSpecVar(&array);
let mode = update_mode.to_bytes(); let mode = update_mode.to_bytes();
let update_mode_var = UpdateModeVar(&mode); let update_mode_var = UpdateModeVar(&mode);
let it = arg_layouts.iter().copied(); let it = passed_function.argument_layouts.iter().copied();
let bytes = func_name_bytes_help(*function_name, it, ret_layout); let bytes =
func_name_bytes_help(passed_function.name, it, &passed_function.return_layout);
let name = FuncName(&bytes); let name = FuncName(&bytes);
let module = MOD_APP; let module = MOD_APP;
let closure_env = env.symbols[function_env]; let closure_env = env.symbols[&passed_function.captured_environment];
let return_layout = &passed_function.return_layout;
let argument_layouts = passed_function.argument_layouts;
macro_rules! call_function { macro_rules! call_function {
($builder: expr, $block:expr, [$($arg:expr),+ $(,)?]) => {{ ($builder: expr, $block:expr, [$($arg:expr),+ $(,)?]) => {{
@ -757,7 +757,7 @@ fn call_spec(
Ok(new_state) Ok(new_state)
}; };
let state_layout = arg_layouts[0]; let state_layout = argument_layouts[0];
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = state; let init_state = state;
@ -778,7 +778,7 @@ fn call_spec(
Ok(new_state) Ok(new_state)
}; };
let state_layout = arg_layouts[0]; let state_layout = argument_layouts[0];
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = state; let init_state = state;
@ -802,7 +802,7 @@ fn call_spec(
Ok(new_state) Ok(new_state)
}; };
let state_layout = arg_layouts[0]; let state_layout = argument_layouts[0];
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = state; let init_state = state;
@ -823,9 +823,9 @@ fn call_spec(
list_append(builder, block, update_mode_var, state, new_element) list_append(builder, block, update_mode_var, state, new_element)
}; };
let output_element_type = layout_spec(builder, ret_layout)?; let output_element_type = layout_spec(builder, return_layout)?;
let state_layout = Layout::Builtin(Builtin::List(ret_layout)); let state_layout = Layout::Builtin(Builtin::List(return_layout));
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = new_list(builder, block, output_element_type)?; let init_state = new_list(builder, block, output_element_type)?;
@ -846,9 +846,9 @@ fn call_spec(
list_append(builder, block, update_mode_var, state, new_element) list_append(builder, block, update_mode_var, state, new_element)
}; };
let output_element_type = layout_spec(builder, ret_layout)?; let output_element_type = layout_spec(builder, return_layout)?;
let state_layout = Layout::Builtin(Builtin::List(ret_layout)); let state_layout = Layout::Builtin(Builtin::List(return_layout));
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = new_list(builder, block, output_element_type)?; let init_state = new_list(builder, block, output_element_type)?;
@ -873,7 +873,7 @@ fn call_spec(
with_new_heap_cell(builder, block, bag) with_new_heap_cell(builder, block, bag)
}; };
let state_layout = Layout::Builtin(Builtin::List(&arg_layouts[0])); let state_layout = Layout::Builtin(Builtin::List(&argument_layouts[0]));
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = list; let init_state = list;
@ -898,9 +898,9 @@ fn call_spec(
list_append(builder, block, update_mode_var, state, new_element) list_append(builder, block, update_mode_var, state, new_element)
}; };
let output_element_type = layout_spec(builder, ret_layout)?; let output_element_type = layout_spec(builder, return_layout)?;
let state_layout = Layout::Builtin(Builtin::List(ret_layout)); let state_layout = Layout::Builtin(Builtin::List(return_layout));
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = new_list(builder, block, output_element_type)?; let init_state = new_list(builder, block, output_element_type)?;
@ -931,9 +931,9 @@ fn call_spec(
list_append(builder, block, update_mode_var, state, new_element) list_append(builder, block, update_mode_var, state, new_element)
}; };
let output_element_type = layout_spec(builder, ret_layout)?; let output_element_type = layout_spec(builder, return_layout)?;
let state_layout = Layout::Builtin(Builtin::List(ret_layout)); let state_layout = Layout::Builtin(Builtin::List(return_layout));
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = new_list(builder, block, output_element_type)?; let init_state = new_list(builder, block, output_element_type)?;
@ -970,9 +970,9 @@ fn call_spec(
list_append(builder, block, update_mode_var, state, new_element) list_append(builder, block, update_mode_var, state, new_element)
}; };
let output_element_type = layout_spec(builder, ret_layout)?; let output_element_type = layout_spec(builder, return_layout)?;
let state_layout = Layout::Builtin(Builtin::List(ret_layout)); let state_layout = Layout::Builtin(Builtin::List(return_layout));
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = new_list(builder, block, output_element_type)?; let init_state = new_list(builder, block, output_element_type)?;
@ -1004,7 +1004,7 @@ fn call_spec(
with_new_heap_cell(builder, block, new_bag) with_new_heap_cell(builder, block, new_bag)
}; };
let state_layout = Layout::Builtin(Builtin::List(&arg_layouts[0])); let state_layout = Layout::Builtin(Builtin::List(&argument_layouts[0]));
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = list; let init_state = list;
@ -1019,7 +1019,7 @@ fn call_spec(
_ => unreachable!(), _ => unreachable!(),
}; };
let result_repr = ResultRepr::from_layout(ret_layout); let result_repr = ResultRepr::from_layout(return_layout);
let output_element_layout = match (keep_result, result_repr) { let output_element_layout = match (keep_result, result_repr) {
(KeepResult::Errs, ResultRepr::ResultConcrete { err, .. }) => err, (KeepResult::Errs, ResultRepr::ResultConcrete { err, .. }) => err,
@ -1132,7 +1132,7 @@ fn call_spec(
let list = env.symbols[xs]; let list = env.symbols[xs];
// ListFindUnsafe returns { value: v, found: Bool=Int1 } // ListFindUnsafe returns { value: v, found: Bool=Int1 }
let output_layouts = vec![arg_layouts[0], Layout::Builtin(Builtin::Bool)]; let output_layouts = vec![argument_layouts[0], Layout::Builtin(Builtin::Bool)];
let output_layout = Layout::Struct(&output_layouts); let output_layout = Layout::Struct(&output_layouts);
let output_type = layout_spec(builder, &output_layout)?; let output_type = layout_spec(builder, &output_layout)?;

View file

@ -595,20 +595,17 @@ impl<'a> BorrowInfState<'a> {
HigherOrder(HigherOrderLowLevel { HigherOrder(HigherOrderLowLevel {
op, op,
arg_layouts, passed_function,
ret_layout,
function_name,
function_env,
.. ..
}) => { }) => {
use crate::low_level::HigherOrder::*; use crate::low_level::HigherOrder::*;
let closure_layout = ProcLayout { let closure_layout = ProcLayout {
arguments: arg_layouts, arguments: passed_function.argument_layouts,
result: *ret_layout, result: passed_function.return_layout,
}; };
let function_ps = match param_map.get_symbol(*function_name, closure_layout) { let function_ps = match param_map.get_symbol(passed_function.name, closure_layout) {
Some(function_ps) => function_ps, Some(function_ps) => function_ps,
None => unreachable!(), None => unreachable!(),
}; };
@ -692,7 +689,7 @@ impl<'a> BorrowInfState<'a> {
// own the closure environment if the function needs to own it // own the closure environment if the function needs to own it
let function_env_position = op.function_arity(); let function_env_position = op.function_arity();
if let Some(false) = function_ps.get(function_env_position).map(|p| p.borrow) { if let Some(false) = function_ps.get(function_env_position).map(|p| p.borrow) {
self.own_var(*function_env); self.own_var(passed_function.captured_environment);
} }
} }

View file

@ -468,12 +468,8 @@ impl<'a> Context<'a> {
HigherOrder(HigherOrderLowLevel { HigherOrder(HigherOrderLowLevel {
op, op,
closure_env_layout, closure_env_layout,
specialization_id,
update_mode, update_mode,
arg_layouts, passed_function,
ret_layout,
function_name,
function_env,
.. ..
}) => { }) => {
// setup // setup
@ -483,16 +479,14 @@ impl<'a> Context<'a> {
($borrows:expr) => { ($borrows:expr) => {
Expr::Call(crate::ir::Call { Expr::Call(crate::ir::Call {
call_type: if let Some(OWNED) = $borrows.map(|p| p.borrow) { call_type: if let Some(OWNED) = $borrows.map(|p| p.borrow) {
let mut passed_function = *passed_function;
passed_function.owns_captured_environment = true;
let higher_order = HigherOrderLowLevel { let higher_order = HigherOrderLowLevel {
op: *op, op: *op,
closure_env_layout: *closure_env_layout, closure_env_layout: *closure_env_layout,
function_owns_closure_data: true,
specialization_id: *specialization_id,
update_mode: *update_mode, update_mode: *update_mode,
function_name: *function_name, passed_function,
function_env: *function_env,
arg_layouts,
ret_layout: *ret_layout,
}; };
CallType::HigherOrder(self.arena.alloc(higher_order)) CallType::HigherOrder(self.arena.alloc(higher_order))
@ -521,11 +515,14 @@ impl<'a> Context<'a> {
const CLOSURE_DATA: bool = BORROWED; const CLOSURE_DATA: bool = BORROWED;
let function_layout = ProcLayout { let function_layout = ProcLayout {
arguments: arg_layouts, arguments: passed_function.argument_layouts,
result: *ret_layout, result: passed_function.return_layout,
}; };
let function_ps = match self.param_map.get_symbol(*function_name, function_layout) { let function_ps = match self
.param_map
.get_symbol(passed_function.name, function_layout)
{
Some(function_ps) => function_ps, Some(function_ps) => function_ps,
None => unreachable!(), None => unreachable!(),
}; };

View file

@ -1346,31 +1346,35 @@ pub enum CallType<'a> {
HigherOrder(&'a HigherOrderLowLevel<'a>), HigherOrder(&'a HigherOrderLowLevel<'a>),
} }
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PassedFunction<'a> {
/// name of the top-level function that is passed as an argument
/// e.g. in `List.map xs Num.abs` this would be `Num.abs`
pub name: Symbol,
pub argument_layouts: &'a [Layout<'a>],
pub return_layout: Layout<'a>,
pub specialization_id: CallSpecId,
/// Symbol of the environment captured by the function argument
pub captured_environment: Symbol,
pub owns_captured_environment: bool,
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct HigherOrderLowLevel<'a> { pub struct HigherOrderLowLevel<'a> {
pub op: crate::low_level::HigherOrder, pub op: crate::low_level::HigherOrder,
/// TODO I _think_ we can get rid of this, perhaps only keeping track of
/// the layout of the closure argument, if any /// the layout of the closure argument, if any
pub closure_env_layout: Option<Layout<'a>>, pub closure_env_layout: Option<Layout<'a>>,
/// name of the top-level function that is passed as an argument
/// e.g. in `List.map xs Num.abs` this would be `Num.abs`
pub function_name: Symbol,
/// Symbol of the environment captured by the function argument
pub function_env: Symbol,
/// does the function argument need to own the closure data
pub function_owns_closure_data: bool,
/// specialization id of the function argument, used for name generation
pub specialization_id: CallSpecId,
/// update mode of the higher order lowlevel itself /// update mode of the higher order lowlevel itself
pub update_mode: UpdateModeId, pub update_mode: UpdateModeId,
/// function layout, used for name generation pub passed_function: PassedFunction<'a>,
pub arg_layouts: &'a [Layout<'a>],
pub ret_layout: Layout<'a>,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -4193,16 +4197,21 @@ pub fn with_hole<'a>(
op, op,
closure_data_symbol, closure_data_symbol,
|(top_level_function, closure_data, closure_env_layout, specialization_id, update_mode)| { |(top_level_function, closure_data, closure_env_layout, specialization_id, update_mode)| {
let passed_function = PassedFunction {
name: top_level_function,
captured_environment: closure_data_symbol,
owns_captured_environment: false,
specialization_id,
argument_layouts: arg_layouts,
return_layout: ret_layout,
};
let higher_order = HigherOrderLowLevel { let higher_order = HigherOrderLowLevel {
op: crate::low_level::HigherOrder::$ho { $($x,)* }, op: crate::low_level::HigherOrder::$ho { $($x,)* },
closure_env_layout, closure_env_layout,
specialization_id,
update_mode, update_mode,
function_owns_closure_data: false, passed_function,
function_env: closure_data_symbol,
function_name: top_level_function,
arg_layouts,
ret_layout,
}; };
self::Call { self::Call {