closure_env_layout

This commit is contained in:
Folkert 2021-06-16 22:15:55 +02:00
parent b54033a2f5
commit cc98237a0a
6 changed files with 57 additions and 45 deletions

View file

@ -830,9 +830,10 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
CallType::HigherOrderLowLevel { CallType::HigherOrderLowLevel {
op, op,
closure_layout,
function_owns_closure_data, function_owns_closure_data,
specialization_id, specialization_id,
arg_layouts,
ret_layout,
.. ..
} => { } => {
let bytes = specialization_id.to_bytes(); let bytes = specialization_id.to_bytes();
@ -846,8 +847,9 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
scope, scope,
layout, layout,
*op, *op,
*closure_layout,
func_spec, func_spec,
arg_layouts,
ret_layout,
*function_owns_closure_data, *function_owns_closure_data,
arguments, arguments,
) )
@ -3815,8 +3817,9 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
scope: &Scope<'a, 'ctx>, scope: &Scope<'a, 'ctx>,
return_layout: &Layout<'a>, return_layout: &Layout<'a>,
op: LowLevel, op: LowLevel,
function_layout: Layout<'a>,
func_spec: FuncSpec, func_spec: FuncSpec,
argument_layouts: &[Layout<'a>],
result_layout: &Layout<'a>,
function_owns_closure_data: bool, function_owns_closure_data: bool,
args: &[Symbol], args: &[Symbol],
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
@ -3828,6 +3831,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
macro_rules! passed_function_at_index { macro_rules! passed_function_at_index {
($index:expr) => {{ ($index:expr) => {{
let function_symbol = args[$index]; let function_symbol = args[$index];
let function_layout = Layout::FunctionPointer(argument_layouts, return_layout);
function_value_by_func_spec(env, func_spec, function_symbol, function_layout) function_value_by_func_spec(env, func_spec, function_symbol, function_layout)
}}; }};
@ -4095,7 +4099,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
env, env,
layout_ids, layout_ids,
roc_function_call, roc_function_call,
&function_layout, result_layout,
list, list,
before_layout, before_layout,
after_layout, after_layout,
@ -4139,7 +4143,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
env, env,
layout_ids, layout_ids,
roc_function_call, roc_function_call,
&function_layout, result_layout,
list, list,
before_layout, before_layout,
after_layout, after_layout,

View file

@ -601,18 +601,12 @@ pub fn list_keep_oks<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>, layout_ids: &mut LayoutIds<'a>,
roc_function_call: RocFunctionCall<'ctx>, roc_function_call: RocFunctionCall<'ctx>,
function_layout: &Layout<'a>, // Layout of the `Result after *`
result_layout: &Layout<'a>,
list: BasicValueEnum<'ctx>, list: BasicValueEnum<'ctx>,
before_layout: &Layout<'a>, before_layout: &Layout<'a>,
after_layout: &Layout<'a>, after_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
// Layout of the `Result after *`
let result_layout = match function_layout {
Layout::FunctionPointer(_, ret) => ret,
Layout::Closure(_, _, ret) => ret,
_ => unreachable!("not a callable layout"),
};
let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout); let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout);
call_bitcode_fn( call_bitcode_fn(
@ -638,18 +632,12 @@ pub fn list_keep_errs<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>, layout_ids: &mut LayoutIds<'a>,
roc_function_call: RocFunctionCall<'ctx>, roc_function_call: RocFunctionCall<'ctx>,
function_layout: &Layout<'a>, // Layout of the `Result * err`
result_layout: &Layout<'a>,
list: BasicValueEnum<'ctx>, list: BasicValueEnum<'ctx>,
before_layout: &Layout<'a>, before_layout: &Layout<'a>,
after_layout: &Layout<'a>, after_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
// Layout of the `Result after *`
let result_layout = match function_layout {
Layout::FunctionPointer(_, ret) => ret,
Layout::Closure(_, _, ret) => ret,
_ => unreachable!("not a callable layout"),
};
let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout); let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout);
call_bitcode_fn( call_bitcode_fn(

View file

@ -393,15 +393,20 @@ impl<'a> BorrowInfState<'a> {
} }
HigherOrderLowLevel { HigherOrderLowLevel {
op, closure_layout, .. op,
arg_layouts,
ret_layout,
..
} => { } => {
use roc_module::low_level::LowLevel::*; use roc_module::low_level::LowLevel::*;
debug_assert!(op.is_higher_order()); debug_assert!(op.is_higher_order());
let closure_layout = Layout::FunctionPointer(arg_layouts, ret_layout);
match op { match op {
ListMap | ListKeepIf | ListKeepOks | ListKeepErrs => { ListMap | ListKeepIf | ListKeepOks | ListKeepErrs => {
match self.param_map.get_symbol(arguments[1], *closure_layout) { match self.param_map.get_symbol(arguments[1], closure_layout) {
Some(function_ps) => { Some(function_ps) => {
// own the list if the function wants to own the element // own the list if the function wants to own the element
if !function_ps[0].borrow { if !function_ps[0].borrow {
@ -417,7 +422,7 @@ impl<'a> BorrowInfState<'a> {
} }
} }
ListMapWithIndex => { ListMapWithIndex => {
match self.param_map.get_symbol(arguments[1], *closure_layout) { match self.param_map.get_symbol(arguments[1], closure_layout) {
Some(function_ps) => { Some(function_ps) => {
// own the list if the function wants to own the element // own the list if the function wants to own the element
if !function_ps[1].borrow { if !function_ps[1].borrow {
@ -432,7 +437,7 @@ impl<'a> BorrowInfState<'a> {
None => unreachable!(), None => unreachable!(),
} }
} }
ListMap2 => match self.param_map.get_symbol(arguments[2], *closure_layout) { ListMap2 => match self.param_map.get_symbol(arguments[2], closure_layout) {
Some(function_ps) => { Some(function_ps) => {
// own the lists if the function wants to own the element // own the lists if the function wants to own the element
if !function_ps[0].borrow { if !function_ps[0].borrow {
@ -450,7 +455,7 @@ impl<'a> BorrowInfState<'a> {
} }
None => unreachable!(), None => unreachable!(),
}, },
ListMap3 => match self.param_map.get_symbol(arguments[3], *closure_layout) { ListMap3 => match self.param_map.get_symbol(arguments[3], closure_layout) {
Some(function_ps) => { Some(function_ps) => {
// own the lists if the function wants to own the element // own the lists if the function wants to own the element
if !function_ps[0].borrow { if !function_ps[0].borrow {
@ -471,7 +476,7 @@ impl<'a> BorrowInfState<'a> {
None => unreachable!(), None => unreachable!(),
}, },
ListSortWith => { ListSortWith => {
match self.param_map.get_symbol(arguments[1], *closure_layout) { match self.param_map.get_symbol(arguments[1], closure_layout) {
Some(function_ps) => { Some(function_ps) => {
// always own the input list // always own the input list
self.own_var(arguments[0]); self.own_var(arguments[0]);
@ -485,7 +490,7 @@ impl<'a> BorrowInfState<'a> {
} }
} }
ListWalk | ListWalkUntil | ListWalkBackwards | DictWalk => { ListWalk | ListWalkUntil | ListWalkBackwards | DictWalk => {
match self.param_map.get_symbol(arguments[2], *closure_layout) { match self.param_map.get_symbol(arguments[2], closure_layout) {
Some(function_ps) => { Some(function_ps) => {
// own the data structure if the function wants to own the element // own the data structure if the function wants to own the element
if !function_ps[0].borrow { if !function_ps[0].borrow {

View file

@ -455,7 +455,7 @@ impl<'a> Context<'a> {
HigherOrderLowLevel { HigherOrderLowLevel {
op, op,
closure_layout, closure_env_layout,
specialization_id, specialization_id,
arg_layouts, arg_layouts,
ret_layout, ret_layout,
@ -467,7 +467,7 @@ impl<'a> Context<'a> {
call_type: if let Some(OWNED) = $borrows.map(|p| p.borrow) { call_type: if let Some(OWNED) = $borrows.map(|p| p.borrow) {
HigherOrderLowLevel { HigherOrderLowLevel {
op: *op, op: *op,
closure_layout: *closure_layout, closure_env_layout: *closure_env_layout,
function_owns_closure_data: true, function_owns_closure_data: true,
specialization_id: *specialization_id, specialization_id: *specialization_id,
arg_layouts, arg_layouts,
@ -497,12 +497,14 @@ impl<'a> Context<'a> {
const FUNCTION: bool = BORROWED; const FUNCTION: bool = BORROWED;
const CLOSURE_DATA: bool = BORROWED; const CLOSURE_DATA: bool = BORROWED;
let function_layout = Layout::FunctionPointer(arg_layouts, ret_layout);
match op { match op {
roc_module::low_level::LowLevel::ListMap roc_module::low_level::LowLevel::ListMap
| roc_module::low_level::LowLevel::ListKeepIf | roc_module::low_level::LowLevel::ListKeepIf
| roc_module::low_level::LowLevel::ListKeepOks | roc_module::low_level::LowLevel::ListKeepOks
| roc_module::low_level::LowLevel::ListKeepErrs => { | roc_module::low_level::LowLevel::ListKeepErrs => {
match self.param_map.get_symbol(arguments[1], *closure_layout) { match self.param_map.get_symbol(arguments[1], function_layout) {
Some(function_ps) => { Some(function_ps) => {
let borrows = [function_ps[0].borrow, FUNCTION, CLOSURE_DATA]; let borrows = [function_ps[0].borrow, FUNCTION, CLOSURE_DATA];
@ -524,7 +526,7 @@ impl<'a> Context<'a> {
} }
} }
roc_module::low_level::LowLevel::ListMapWithIndex => { roc_module::low_level::LowLevel::ListMapWithIndex => {
match self.param_map.get_symbol(arguments[1], *closure_layout) { match self.param_map.get_symbol(arguments[1], function_layout) {
Some(function_ps) => { Some(function_ps) => {
let borrows = [function_ps[1].borrow, FUNCTION, CLOSURE_DATA]; let borrows = [function_ps[1].borrow, FUNCTION, CLOSURE_DATA];
@ -545,7 +547,7 @@ impl<'a> Context<'a> {
} }
} }
roc_module::low_level::LowLevel::ListMap2 => { roc_module::low_level::LowLevel::ListMap2 => {
match self.param_map.get_symbol(arguments[2], *closure_layout) { match self.param_map.get_symbol(arguments[2], function_layout) {
Some(function_ps) => { Some(function_ps) => {
let borrows = [ let borrows = [
function_ps[0].borrow, function_ps[0].borrow,
@ -572,7 +574,7 @@ impl<'a> Context<'a> {
} }
} }
roc_module::low_level::LowLevel::ListMap3 => { roc_module::low_level::LowLevel::ListMap3 => {
match self.param_map.get_symbol(arguments[3], *closure_layout) { match self.param_map.get_symbol(arguments[3], function_layout) {
Some(function_ps) => { Some(function_ps) => {
let borrows = [ let borrows = [
function_ps[0].borrow, function_ps[0].borrow,
@ -601,7 +603,7 @@ impl<'a> Context<'a> {
} }
} }
roc_module::low_level::LowLevel::ListSortWith => { roc_module::low_level::LowLevel::ListSortWith => {
match self.param_map.get_symbol(arguments[1], *closure_layout) { match self.param_map.get_symbol(arguments[1], function_layout) {
Some(function_ps) => { Some(function_ps) => {
let borrows = [OWNED, FUNCTION, CLOSURE_DATA]; let borrows = [OWNED, FUNCTION, CLOSURE_DATA];
@ -623,7 +625,7 @@ impl<'a> Context<'a> {
| roc_module::low_level::LowLevel::ListWalkUntil | roc_module::low_level::LowLevel::ListWalkUntil
| roc_module::low_level::LowLevel::ListWalkBackwards | roc_module::low_level::LowLevel::ListWalkBackwards
| roc_module::low_level::LowLevel::DictWalk => { | roc_module::low_level::LowLevel::DictWalk => {
match self.param_map.get_symbol(arguments[2], *closure_layout) { match self.param_map.get_symbol(arguments[2], function_layout) {
Some(function_ps) => { Some(function_ps) => {
// borrow data structure based on first argument of the folded function // borrow data structure based on first argument of the folded function
// borrow the default based on second argument of the folded function // borrow the default based on second argument of the folded function

View file

@ -1152,7 +1152,7 @@ pub enum CallType<'a> {
HigherOrderLowLevel { HigherOrderLowLevel {
op: LowLevel, op: LowLevel,
/// the layout of the closure argument, if any /// the layout of the closure argument, if any
closure_layout: Layout<'a>, closure_env_layout: Option<Layout<'a>>,
/// specialization id of the function argument /// specialization id of the function argument
specialization_id: CallSpecId, specialization_id: CallSpecId,
/// does the function need to own the closure data /// does the function need to own the closure data
@ -2724,10 +2724,10 @@ macro_rules! match_on_closure_argument {
$env, $env,
lambda_set, lambda_set,
$closure_data_symbol, $closure_data_symbol,
|top_level_function, closure_data, function_layout, specialization_id| self::Call { |top_level_function, closure_data, closure_env_layout, specialization_id| self::Call {
call_type: CallType::HigherOrderLowLevel { call_type: CallType::HigherOrderLowLevel {
op: $op, op: $op,
closure_layout: function_layout, closure_env_layout,
specialization_id, specialization_id,
function_owns_closure_data: false, function_owns_closure_data: false,
arg_layouts, arg_layouts,
@ -7715,7 +7715,7 @@ fn lowlevel_match_on_lambda_set<'a, ToLowLevelCall>(
hole: &'a Stmt<'a>, hole: &'a Stmt<'a>,
) -> Stmt<'a> ) -> Stmt<'a>
where where
ToLowLevelCall: Fn(Symbol, Symbol, Layout<'a>, CallSpecId) -> Call<'a> + Copy, ToLowLevelCall: Fn(Symbol, Symbol, Option<Layout<'a>>, CallSpecId) -> Call<'a> + Copy,
{ {
match lambda_set.runtime_representation() { match lambda_set.runtime_representation() {
Layout::Union(_) => { Layout::Union(_) => {
@ -7727,6 +7727,7 @@ where
closure_tag_id_symbol, closure_tag_id_symbol,
Layout::Builtin(crate::layout::TAG_SIZE), Layout::Builtin(crate::layout::TAG_SIZE),
closure_data_symbol, closure_data_symbol,
lambda_set.is_represented(),
to_lowlevel_call, to_lowlevel_call,
function_layout, function_layout,
return_layout, return_layout,
@ -7756,7 +7757,7 @@ where
let call = to_lowlevel_call( let call = to_lowlevel_call(
function_symbol, function_symbol,
closure_data_symbol, closure_data_symbol,
function_layout, lambda_set.is_represented(),
call_spec_id, call_spec_id,
); );
@ -7771,6 +7772,7 @@ where
closure_tag_id_symbol, closure_tag_id_symbol,
Layout::Builtin(Builtin::Int1), Layout::Builtin(Builtin::Int1),
closure_data_symbol, closure_data_symbol,
lambda_set.is_represented(),
to_lowlevel_call, to_lowlevel_call,
function_layout, function_layout,
return_layout, return_layout,
@ -7787,6 +7789,7 @@ where
closure_tag_id_symbol, closure_tag_id_symbol,
Layout::Builtin(Builtin::Int8), Layout::Builtin(Builtin::Int8),
closure_data_symbol, closure_data_symbol,
lambda_set.is_represented(),
to_lowlevel_call, to_lowlevel_call,
function_layout, function_layout,
return_layout, return_layout,
@ -7805,6 +7808,7 @@ fn lowlevel_union_lambda_set_to_switch<'a, ToLowLevelCall>(
closure_tag_id_symbol: Symbol, closure_tag_id_symbol: Symbol,
closure_tag_id_layout: Layout<'a>, closure_tag_id_layout: Layout<'a>,
closure_data_symbol: Symbol, closure_data_symbol: Symbol,
closure_env_layout: Option<Layout<'a>>,
to_lowlevel_call: ToLowLevelCall, to_lowlevel_call: ToLowLevelCall,
function_layout: Layout<'a>, function_layout: Layout<'a>,
return_layout: Layout<'a>, return_layout: Layout<'a>,
@ -7812,7 +7816,7 @@ fn lowlevel_union_lambda_set_to_switch<'a, ToLowLevelCall>(
hole: &'a Stmt<'a>, hole: &'a Stmt<'a>,
) -> Stmt<'a> ) -> Stmt<'a>
where where
ToLowLevelCall: Fn(Symbol, Symbol, Layout<'a>, CallSpecId) -> Call<'a> + Copy, ToLowLevelCall: Fn(Symbol, Symbol, Option<Layout<'a>>, CallSpecId) -> Call<'a> + Copy,
{ {
debug_assert!(!lambda_set.is_empty()); debug_assert!(!lambda_set.is_empty());
@ -7829,7 +7833,7 @@ where
let call = to_lowlevel_call( let call = to_lowlevel_call(
*function_symbol, *function_symbol,
closure_data_symbol, closure_data_symbol,
function_layout, closure_env_layout,
call_spec_id, call_spec_id,
); );
let stmt = build_call(env, call, assigned, return_layout, env.arena.alloc(hole)); let stmt = build_call(env, call, assigned, return_layout, env.arena.alloc(hole));
@ -8230,6 +8234,7 @@ fn lowlevel_enum_lambda_set_to_switch<'a, ToLowLevelCall>(
closure_tag_id_symbol: Symbol, closure_tag_id_symbol: Symbol,
closure_tag_id_layout: Layout<'a>, closure_tag_id_layout: Layout<'a>,
closure_data_symbol: Symbol, closure_data_symbol: Symbol,
closure_env_layout: Option<Layout<'a>>,
to_lowlevel_call: ToLowLevelCall, to_lowlevel_call: ToLowLevelCall,
function_layout: Layout<'a>, function_layout: Layout<'a>,
return_layout: Layout<'a>, return_layout: Layout<'a>,
@ -8237,7 +8242,7 @@ fn lowlevel_enum_lambda_set_to_switch<'a, ToLowLevelCall>(
hole: &'a Stmt<'a>, hole: &'a Stmt<'a>,
) -> Stmt<'a> ) -> Stmt<'a>
where where
ToLowLevelCall: Fn(Symbol, Symbol, Layout<'a>, CallSpecId) -> Call<'a> + Copy, ToLowLevelCall: Fn(Symbol, Symbol, Option<Layout<'a>>, CallSpecId) -> Call<'a> + Copy,
{ {
debug_assert!(!lambda_set.is_empty()); debug_assert!(!lambda_set.is_empty());
@ -8254,7 +8259,7 @@ where
let call = to_lowlevel_call( let call = to_lowlevel_call(
*function_symbol, *function_symbol,
closure_data_symbol, closure_data_symbol,
function_layout, closure_env_layout,
call_spec_id, call_spec_id,
); );
let stmt = build_call( let stmt = build_call(

View file

@ -143,6 +143,14 @@ impl<'a> LambdaSet<'a> {
*self.representation *self.representation
} }
pub fn is_represented(&self) -> Option<Layout<'a>> {
if let Layout::Struct(&[]) = self.representation {
None
} else {
Some(*self.representation)
}
}
pub fn layout_for_member(&self, function_symbol: Symbol) -> ClosureRepresentation<'a> { pub fn layout_for_member(&self, function_symbol: Symbol) -> ClosureRepresentation<'a> {
debug_assert!( debug_assert!(
self.set.iter().any(|(s, _)| *s == function_symbol), self.set.iter().any(|(s, _)| *s == function_symbol),