clarify how we deal with a closure layout

This commit is contained in:
Folkert 2020-10-18 21:04:58 +02:00
parent b26f778ee0
commit b0ef8b9b07
2 changed files with 60 additions and 31 deletions

View file

@ -1025,7 +1025,6 @@ mod gen_primitives {
main : Float main : Float
main = main =
runEffect foo runEffect foo
"# "#
), ),
3.14, 3.14,

View file

@ -1497,7 +1497,7 @@ fn build_specialized_proc<'a>(
layout_cache: &mut LayoutCache<'a>, layout_cache: &mut LayoutCache<'a>,
pattern_symbols: &[Symbol], pattern_symbols: &[Symbol],
pattern_vars: &[Variable], pattern_vars: &[Variable],
closure_layout: Option<ClosureLayout<'a>>, opt_closure_layout: Option<ClosureLayout<'a>>,
ret_var: Variable, ret_var: Variable,
) -> Result<(&'a [(Layout<'a>, Symbol)], Layout<'a>), LayoutProblem> { ) -> Result<(&'a [(Layout<'a>, Symbol)], Layout<'a>), LayoutProblem> {
let mut proc_args = Vec::with_capacity_in(pattern_vars.len(), &env.arena); let mut proc_args = Vec::with_capacity_in(pattern_vars.len(), &env.arena);
@ -1508,39 +1508,69 @@ fn build_specialized_proc<'a>(
proc_args.push((layout, *arg_name)); proc_args.push((layout, *arg_name));
} }
// is the final argument symbol the closure symbol? then add the closure variable to the // Given
// pattern variables //
if pattern_symbols.last() == Some(&Symbol::ARG_CLOSURE) { // foo =
let layout = closure_layout.unwrap().as_layout(); // x = 42
proc_args.push((layout, Symbol::ARG_CLOSURE)); //
// f = \{} -> x
//
// We desugar that into
//
// f = \{}, x -> x
//
// foo =
// x = 42
//
// f_closure = { ptr: f, closure: x }
//
// then
match opt_closure_layout {
Some(layout) if pattern_symbols.last() == Some(&Symbol::ARG_CLOSURE) => {
// here we define the lifted (now top-level) f function. Its final argument is `Symbol::ARG_CLOSURE`,
// it stores the closure structure (just an integer in this case)
proc_args.push((layout.as_layout(), Symbol::ARG_CLOSURE));
debug_assert_eq!( debug_assert_eq!(
pattern_vars.len() + 1, pattern_vars.len() + 1,
pattern_symbols.len(), pattern_symbols.len(),
"Tried to zip two vecs with different lengths!" "Tried to zip two vecs with different lengths!"
); );
} else if let Some(layout) = closure_layout { }
let ret_layout = layout_cache Some(layout) => {
.from_var(&env.arena, ret_var, env.subs) // else if there is a closure layout, we're building the `f_closure` value
.unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err)); // that means we're really creating a ( function_ptr, closure_data ) pair
let ret_layout = layout_cache
.from_var(&env.arena, ret_var, env.subs)
.unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err));
let closure_data_layout = layout.as_layout(); let closure_data_layout = layout.as_layout();
let function_ptr_layout = Layout::FunctionPointer( let function_ptr_layout = Layout::FunctionPointer(
env.arena env.arena
.alloc([Layout::Struct(&[]), closure_data_layout.clone()]), .alloc([Layout::Struct(&[]), closure_data_layout.clone()]),
env.arena.alloc(ret_layout), env.arena.alloc(ret_layout),
); );
let closure_layout = let closure_layout =
Layout::Struct(env.arena.alloc([function_ptr_layout, closure_data_layout])); Layout::Struct(env.arena.alloc([function_ptr_layout, closure_data_layout]));
return Ok((&[], closure_layout)); return Ok((&[], closure_layout));
} else { }
debug_assert_eq!( None => {
pattern_vars.len(), // else we're making a normal function, no closure problems to worry about
pattern_symbols.len(), // we'll just assert some things
"Tried to zip two vecs with different lengths!"
); // make sure there is not arg_closure argument without a closure layout
debug_assert!(pattern_symbols.last() != Some(&Symbol::ARG_CLOSURE));
// since this is not a closure, the number of arguments should match between symbols
// and layout
debug_assert_eq!(
pattern_vars.len(),
pattern_symbols.len(),
"Tried to zip two vecs with different lengths!"
);
}
} }
let proc_args = proc_args.into_bump_slice(); let proc_args = proc_args.into_bump_slice();