diff --git a/cli/src/repl/eval.rs b/cli/src/repl/eval.rs index 89fd30e74f..ef6dfec3a4 100644 --- a/cli/src/repl/eval.rs +++ b/cli/src/repl/eval.rs @@ -6,6 +6,7 @@ use roc_gen_llvm::{run_jit_function, run_jit_function_dynamic_type}; use roc_module::ident::{Lowercase, TagName}; use roc_module::operator::CalledVia; use roc_module::symbol::{Interns, ModuleId, Symbol}; +use roc_mono::ir::TopLevelFunctionLayout; use roc_mono::layout::{union_sorted_tags_help, Builtin, Layout, UnionLayout, UnionVariant}; use roc_parse::ast::{AssignedField, Expr, StrLiteral}; use roc_region::all::{Located, Region}; @@ -37,7 +38,7 @@ pub unsafe fn jit_to_ast<'a>( arena: &'a Bump, lib: Library, main_fn_name: &str, - layout: &Layout<'a>, + layout: TopLevelFunctionLayout<'a>, content: &Content, interns: &Interns, home: ModuleId, @@ -53,11 +54,14 @@ pub unsafe fn jit_to_ast<'a>( }; match layout { - Layout::FunctionPointer(&[], result) => { + TopLevelFunctionLayout { + arguments: [], + result, + } => { // this is a thunk - jit_to_ast_help(&env, lib, main_fn_name, result, content) + jit_to_ast_help(&env, lib, main_fn_name, &result, content) } - _ => jit_to_ast_help(&env, lib, main_fn_name, layout, content), + _ => Err(ToAstProblem::FunctionLayout), } } diff --git a/cli/src/repl/gen.rs b/cli/src/repl/gen.rs index 699d244908..797fdba999 100644 --- a/cli/src/repl/gen.rs +++ b/cli/src/repl/gen.rs @@ -226,7 +226,7 @@ pub fn gen_and_eval<'a>( &arena, lib, main_fn_name, - &arena.alloc(main_fn_layout).full(), + main_fn_layout, &content, &env.interns, home, diff --git a/compiler/gen_dev/src/object_builder.rs b/compiler/gen_dev/src/object_builder.rs index 03bbc854de..c2ccda29d2 100644 --- a/compiler/gen_dev/src/object_builder.rs +++ b/compiler/gen_dev/src/object_builder.rs @@ -9,8 +9,7 @@ use object::{ }; use roc_collections::all::MutMap; use roc_module::symbol; -use roc_mono::ir::Proc; -use roc_mono::layout::Layout; +use roc_mono::ir::{Proc, TopLevelFunctionLayout}; use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Triple}; // This is used by some code below which is currently commented out. @@ -22,7 +21,7 @@ use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Tripl pub fn build_module<'a>( env: &'a Env, target: &Triple, - procedures: MutMap<(symbol::Symbol, Layout<'a>), Proc<'a>>, + procedures: MutMap<(symbol::Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>, ) -> Result { match target { Triple { @@ -145,7 +144,7 @@ fn generate_wrapper<'a, B: Backend<'a>>( fn build_object<'a, B: Backend<'a>>( env: &'a Env, - procedures: MutMap<(symbol::Symbol, Layout<'a>), Proc<'a>>, + procedures: MutMap<(symbol::Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>, mut backend: B, mut output: Object, ) -> Result { @@ -187,7 +186,7 @@ fn build_object<'a, B: Backend<'a>>( let mut procs = Vec::with_capacity_in(procedures.len(), env.arena); for ((sym, layout), proc) in procedures { let fn_name = layout_ids - .get(sym, &layout) + .get_toplevel(sym, &layout) .to_symbol_string(sym, &env.interns); let section_id = output.add_section( diff --git a/compiler/gen_dev/tests/helpers/eval.rs b/compiler/gen_dev/tests/helpers/eval.rs index 9800444959..f3403bb9d4 100644 --- a/compiler/gen_dev/tests/helpers/eval.rs +++ b/compiler/gen_dev/tests/helpers/eval.rs @@ -69,8 +69,8 @@ pub fn helper<'a>( let mut procedures = MutMap::default(); - for ((symbol, top_level), proc) in top_procedures { - procedures.insert((symbol, arena.alloc(top_level).full()), proc); + for (key, proc) in top_procedures { + procedures.insert(key, proc); } /* @@ -87,17 +87,12 @@ pub fn helper<'a>( println!("=================================\n"); */ debug_assert_eq!(exposed_to_host.len(), 1); - let main_fn_symbol = exposed_to_host.keys().copied().next().unwrap(); - - let main_fn_layout = procedures - .keys() - .find(|(s, _)| *s == main_fn_symbol) - .map(|t| t.1) - .unwrap(); + let main_fn_symbol = loaded.entry_point.symbol; + let main_fn_layout = loaded.entry_point.layout; let mut layout_ids = roc_mono::layout::LayoutIds::default(); let main_fn_name = layout_ids - .get(main_fn_symbol, &main_fn_layout) + .get_toplevel(main_fn_symbol, &main_fn_layout) .to_symbol_string(main_fn_symbol, &interns); let mut lines = Vec::new(); diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 3eaafa5651..6b65b7d985 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -17,8 +17,8 @@ use crate::llvm::build_str::{ }; use crate::llvm::compare::{generic_eq, generic_neq}; use crate::llvm::convert::{ - basic_type_from_builtin, basic_type_from_layout, block_of_memory, block_of_memory_slices, - ptr_int, + basic_type_from_builtin, basic_type_from_function_layout, basic_type_from_layout, + block_of_memory, block_of_memory_slices, ptr_int, }; use crate::llvm::refcounting::{ decrement_refcount_layout, increment_refcount_layout, PointerToRefcount, @@ -118,7 +118,7 @@ impl<'ctx> Iterator for FunctionIterator<'ctx> { #[derive(Default, Debug, Clone, PartialEq)] pub struct Scope<'a, 'ctx> { symbols: ImMap, BasicValueEnum<'ctx>)>, - pub top_level_thunks: ImMap, FunctionValue<'ctx>)>, + pub top_level_thunks: ImMap, FunctionValue<'ctx>)>, join_points: ImMap, &'a [PointerValue<'ctx>])>, } @@ -136,7 +136,7 @@ impl<'a, 'ctx> Scope<'a, 'ctx> { function_value: FunctionValue<'ctx>, ) { self.top_level_thunks - .insert(symbol, (layout.full(), function_value)); + .insert(symbol, (*layout, function_value)); } fn remove(&mut self, symbol: &Symbol) { self.symbols.remove(symbol); @@ -602,7 +602,9 @@ fn promote_to_main_function<'a, 'ctx, 'env>( "we expect only one specialization of this symbol" ); - let roc_main_fn = function_value_by_func_spec(env, *func_spec, symbol, Layout::Struct(&[])); + // NOTE fake layout; it is only used for debug prints + let roc_main_fn = + function_value_by_func_spec(env, *func_spec, symbol, &[], &Layout::Struct(&[])); let main_fn_name = "$Test.main"; @@ -800,8 +802,9 @@ pub fn build_exp_call<'a, 'ctx, 'env>( match call_type { CallType::ByName { name, - full_layout, specialization_id, + arg_layouts, + ret_layout, .. } => { let mut arg_tuples: Vec = @@ -817,7 +820,8 @@ pub fn build_exp_call<'a, 'ctx, 'env>( roc_call_with_args( env, - &full_layout, + arg_layouts, + ret_layout, *name, func_spec, arg_tuples.into_bump_slice(), @@ -839,7 +843,6 @@ pub fn build_exp_call<'a, 'ctx, 'env>( let bytes = specialization_id.to_bytes(); let callee_var = CalleeSpecVar(&bytes); let func_spec = func_spec_solutions.callee_spec(callee_var).unwrap(); - // let fn_val = function_value_by_func_spec(env, func_spec, symbol, *layout); run_higher_order_low_level( env, @@ -2051,7 +2054,8 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( } => match call.call_type { CallType::ByName { name, - ref full_layout, + arg_layouts, + ref ret_layout, specialization_id, .. } => { @@ -2060,7 +2064,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( let func_spec = func_spec_solutions.callee_spec(callee_var).unwrap(); let function_value = - function_value_by_func_spec(env, func_spec, name, *full_layout); + function_value_by_func_spec(env, func_spec, name, arg_layouts, ret_layout); invoke_roc_function( env, @@ -3392,8 +3396,8 @@ pub fn build_closure_caller<'a, 'ctx, 'env>( ); // STEP 4: build a {} -> u64 function that gives the size of the closure - let layout = Layout::Closure(arguments, lambda_set, result); - build_host_exposed_alias_size(env, def_name, alias_symbol, &layout); + let layout = lambda_set.runtime_representation(); + build_host_exposed_alias_size(env, def_name, alias_symbol, layout); } fn build_function_caller<'a, 'ctx, 'env>( @@ -3431,10 +3435,8 @@ fn build_function_caller<'a, 'ctx, 'env>( // pretend the closure layout is empty args.push(Layout::Struct(&[])); - let function_layout = Layout::FunctionPointer(&args, result); - // this is already a (function) pointer type - basic_type_from_layout(env, &function_layout) + basic_type_from_function_layout(env, &args, result) }; argument_types.push(function_pointer_type); @@ -3474,10 +3476,7 @@ fn build_function_caller<'a, 'ctx, 'env>( let _closure_data_ptr = parameters.pop().unwrap().into_pointer_value(); let function_ptr = parameters.pop().unwrap().into_pointer_value(); - // let closure_data = context.struct_type(&[], false).const_zero().into(); - - let actual_function_type = - basic_type_from_layout(env, &Layout::FunctionPointer(arguments, result)); + let actual_function_type = basic_type_from_function_layout(env, arguments, result); let function_ptr = builder .build_bitcast(function_ptr, actual_function_type, "cast") @@ -3513,22 +3512,22 @@ fn build_function_caller<'a, 'ctx, 'env>( ); // STEP 4: build a {} -> u64 function that gives the size of the function - let layout = Layout::FunctionPointer(arguments, result); - build_host_exposed_alias_size(env, def_name, alias_symbol, &layout); + let layout = Layout::Struct(&[]); + build_host_exposed_alias_size(env, def_name, alias_symbol, layout); } fn build_host_exposed_alias_size<'a, 'ctx, 'env>( env: &'a Env<'a, 'ctx, 'env>, def_name: &str, alias_symbol: Symbol, - layout: &Layout<'a>, + layout: Layout<'a>, ) { build_host_exposed_alias_size_help( env, def_name, alias_symbol, None, - basic_type_from_layout(env, layout), + basic_type_from_layout(env, &layout), ) } @@ -3597,8 +3596,6 @@ pub fn build_proc<'a, 'ctx, 'env>( // * roc__mainForHost_1_Update_size() -> i64 // * roc__mainForHost_1_Update_result_size() -> i64 - let evaluator_layout = env.arena.alloc(top_level).full(); - let it = top_level.arguments.iter().copied(); let bytes = roc_mono::alias_analysis::func_name_bytes_help( symbol, @@ -3615,8 +3612,13 @@ pub fn build_proc<'a, 'ctx, 'env>( "we expect only one specialization of this symbol" ); - let evaluator = - function_value_by_func_spec(env, *func_spec, symbol, evaluator_layout); + let evaluator = function_value_by_func_spec( + env, + *func_spec, + symbol, + top_level.arguments, + &top_level.result, + ); let ident_string = proc.name.ident_string(&env.interns); let fn_name: String = format!("{}_1", ident_string); @@ -3690,17 +3692,19 @@ fn function_value_by_func_spec<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, func_spec: FuncSpec, symbol: Symbol, - layout: Layout<'a>, + arguments: &[Layout<'a>], + result: &Layout<'a>, ) -> FunctionValue<'ctx> { let fn_name = func_spec_name(env.arena, &env.interns, symbol, func_spec); let fn_name = fn_name.as_str(); - function_value_by_name_help(env, layout, symbol, fn_name) + function_value_by_name_help(env, arguments, result, symbol, fn_name) } fn function_value_by_name_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - layout: Layout<'a>, + arguments: &[Layout<'a>], + result: &Layout<'a>, symbol: Symbol, fn_name: &str, ) -> FunctionValue<'ctx> { @@ -3708,7 +3712,8 @@ fn function_value_by_name_help<'a, 'ctx, 'env>( if symbol.is_builtin() { eprintln!( "Unrecognized builtin function: {:?}\nLayout: {:?}\n", - fn_name, layout + fn_name, + (arguments, result) ); eprintln!("Is the function defined? If so, maybe there is a problem with the layout"); @@ -3720,7 +3725,9 @@ fn function_value_by_name_help<'a, 'ctx, 'env>( // Unrecognized non-builtin function: eprintln!( "Unrecognized non-builtin function: {:?}\n\nSymbol: {:?}\nLayout: {:?}\n", - fn_name, symbol, layout + fn_name, + symbol, + (arguments, result) ); eprintln!("Is the function defined? If so, maybe there is a problem with the layout"); @@ -3736,12 +3743,14 @@ fn function_value_by_name_help<'a, 'ctx, 'env>( #[inline(always)] fn roc_call_with_args<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - layout: &Layout<'a>, + argument_layouts: &[Layout<'a>], + result_layout: &Layout<'a>, symbol: Symbol, func_spec: FuncSpec, args: &[BasicValueEnum<'ctx>], ) -> BasicValueEnum<'ctx> { - let fn_val = function_value_by_func_spec(env, func_spec, symbol, *layout); + let fn_val = + function_value_by_func_spec(env, func_spec, symbol, argument_layouts, result_layout); let call = env.builder.build_call(fn_val, args, "call"); @@ -3837,9 +3846,14 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( macro_rules! passed_function_at_index { ($index:expr) => {{ 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, + argument_layouts, + return_layout, + ) }}; } diff --git a/compiler/gen_llvm/src/llvm/convert.rs b/compiler/gen_llvm/src/llvm/convert.rs index 124ad9ca50..e00c03c333 100644 --- a/compiler/gen_llvm/src/llvm/convert.rs +++ b/compiler/gen_llvm/src/llvm/convert.rs @@ -4,10 +4,9 @@ use inkwell::types::{BasicType, BasicTypeEnum, IntType, StructType}; use inkwell::AddressSpace; use roc_mono::layout::{Builtin, Layout, UnionLayout}; -fn basic_type_from_function_layout<'a, 'ctx, 'env>( +pub fn basic_type_from_function_layout<'a, 'ctx, 'env>( env: &crate::llvm::build::Env<'a, 'ctx, 'env>, args: &[Layout<'_>], - closure_type: Option>, ret_layout: &Layout<'_>, ) -> BasicTypeEnum<'ctx> { let ret_type = basic_type_from_layout(env, &ret_layout); @@ -17,10 +16,6 @@ fn basic_type_from_function_layout<'a, 'ctx, 'env>( arg_basic_types.push(basic_type_from_layout(env, arg_layout)); } - if let Some(closure) = closure_type { - arg_basic_types.push(closure); - } - let fn_type = ret_type.fn_type(arg_basic_types.into_bump_slice(), false); let ptr_type = fn_type.ptr_type(AddressSpace::Generic); @@ -49,9 +44,7 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>( use Layout::*; match layout { - FunctionPointer(args, ret_layout) => { - basic_type_from_function_layout(env, args, None, ret_layout) - } + FunctionPointer(args, ret_layout) => basic_type_from_function_layout(env, args, ret_layout), Closure(_args, closure_layout, _ret_layout) => { let closure_data_layout = closure_layout.runtime_representation(); basic_type_from_layout(env, &closure_data_layout) diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 845b0313c4..ebba54fb80 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -445,7 +445,6 @@ fn call_spec( match &call.call_type { ByName { name: symbol, - full_layout: _, ret_layout, arg_layouts, specialization_id, diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index b919afe510..54808abfaf 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -24,9 +24,8 @@ pub fn infer_borrow<'a>( items: MutMap::default(), }; - for ((s, top_level), proc) in procs { - let key = (*s, arena.alloc(*top_level).full()); - param_map.visit_proc(arena, proc, key); + for (key, proc) in procs { + param_map.visit_proc(arena, proc, *key); } let mut env = BorrowInfState { @@ -51,8 +50,7 @@ pub fn infer_borrow<'a>( // mutually recursive functions (or just make all their arguments owned) for (key, proc) in procs { - let layout = arena.alloc(key.1).full(); - env.collect_proc(proc, layout); + env.collect_proc(proc, key.1); } if !env.modified { @@ -69,7 +67,7 @@ pub fn infer_borrow<'a>( #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub enum Key<'a> { - Declaration(Symbol, Layout<'a>), + Declaration(Symbol, TopLevelFunctionLayout<'a>), JoinPoint(JoinPointId), } @@ -98,7 +96,11 @@ impl<'a> IntoIterator for &'a ParamMap<'a> { } impl<'a> ParamMap<'a> { - pub fn get_symbol(&self, symbol: Symbol, layout: Layout<'a>) -> Option<&'a [Param<'a>]> { + pub fn get_symbol( + &self, + symbol: Symbol, + layout: TopLevelFunctionLayout<'a>, + ) -> Option<&'a [Param<'a>]> { let key = Key::Declaration(symbol, layout); self.items.get(&key).copied() @@ -153,7 +155,12 @@ impl<'a> ParamMap<'a> { .into_bump_slice() } - fn visit_proc(&mut self, arena: &'a Bump, proc: &Proc<'a>, key: (Symbol, Layout<'a>)) { + fn visit_proc( + &mut self, + arena: &'a Bump, + proc: &Proc<'a>, + key: (Symbol, TopLevelFunctionLayout<'a>), + ) { if proc.must_own_arguments { self.visit_proc_always_owned(arena, proc, key); return; @@ -171,7 +178,7 @@ impl<'a> ParamMap<'a> { &mut self, arena: &'a Bump, proc: &Proc<'a>, - key: (Symbol, Layout<'a>), + key: (Symbol, TopLevelFunctionLayout<'a>), ) { let already_in_there = self.items.insert( Key::Declaration(proc.name, key.1), @@ -359,12 +366,17 @@ impl<'a> BorrowInfState<'a> { match call_type { ByName { - name, full_layout, .. + name, + ret_layout, + arg_layouts, + .. } => { + let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout); + // get the borrow signature of the applied function let ps = self .param_map - .get_symbol(*name, *full_layout) + .get_symbol(*name, top_level) .expect("function is defined"); // the return value will be owned @@ -402,7 +414,10 @@ impl<'a> BorrowInfState<'a> { debug_assert!(op.is_higher_order()); - let closure_layout = Layout::FunctionPointer(arg_layouts, ret_layout); + let closure_layout = TopLevelFunctionLayout { + arguments: arg_layouts, + result: *ret_layout, + }; match op { ListMap | ListKeepIf | ListKeepOks | ListKeepErrs => { @@ -584,7 +599,8 @@ impl<'a> BorrowInfState<'a> { call_type: crate::ir::CallType::ByName { name: g, - full_layout, + arg_layouts, + ret_layout, .. }, arguments: ys, @@ -593,10 +609,12 @@ impl<'a> BorrowInfState<'a> { Stmt::Ret(z), ) = (v, b) { + let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout); + if self.current_proc == *g && x == *z { // anonymous functions (for which the ps may not be known) // can never be tail-recursive, so this is fine - if let Some(ps) = self.param_map.get_symbol(*g, *full_layout) { + if let Some(ps) = self.param_map.get_symbol(*g, top_level) { self.own_params_using_args(ys, ps) } } @@ -684,7 +702,7 @@ impl<'a> BorrowInfState<'a> { } } - fn collect_proc(&mut self, proc: &Proc<'a>, layout: Layout<'a>) { + fn collect_proc(&mut self, proc: &Proc<'a>, layout: TopLevelFunctionLayout<'a>) { let old = self.param_set.clone(); let ys = Vec::from_iter_in(proc.args.iter().map(|t| t.1), self.arena).into_bump_slice(); diff --git a/compiler/mono/src/expand_rc.rs b/compiler/mono/src/expand_rc.rs index 4fd274ed55..ed848c8308 100644 --- a/compiler/mono/src/expand_rc.rs +++ b/compiler/mono/src/expand_rc.rs @@ -245,9 +245,6 @@ fn layout_for_constructor<'a>( HasFields(fields) } Closure(_arguments, _lambda_set, _result) => { - // TODO can this be improved again? - // let fpointer = Layout::FunctionPointer(arguments, result); - // let fields = arena.alloc([fpointer, *lambda_set.layout]); // HasFields(fields) ConstructorLayout::Unknown } diff --git a/compiler/mono/src/inc_dec.rs b/compiler/mono/src/inc_dec.rs index d2dcd32092..0e9964a8f5 100644 --- a/compiler/mono/src/inc_dec.rs +++ b/compiler/mono/src/inc_dec.rs @@ -1,5 +1,5 @@ use crate::borrow::{ParamMap, BORROWED, OWNED}; -use crate::ir::{Expr, JoinPointId, ModifyRc, Param, Proc, Stmt}; +use crate::ir::{Expr, JoinPointId, ModifyRc, Param, Proc, Stmt, TopLevelFunctionLayout}; use crate::layout::Layout; use bumpalo::collections::Vec; use bumpalo::Bump; @@ -497,7 +497,10 @@ impl<'a> Context<'a> { const FUNCTION: bool = BORROWED; const CLOSURE_DATA: bool = BORROWED; - let function_layout = Layout::FunctionPointer(arg_layouts, ret_layout); + let function_layout = TopLevelFunctionLayout { + arguments: arg_layouts, + result: *ret_layout, + }; match op { roc_module::low_level::LowLevel::ListMap @@ -679,12 +682,17 @@ impl<'a> Context<'a> { } ByName { - name, full_layout, .. + name, + ret_layout, + arg_layouts, + .. } => { + let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout); + // get the borrow signature let ps = self .param_map - .get_symbol(*name, *full_layout) + .get_symbol(*name, top_level) .expect("function is defined"); let v = Expr::Call(crate::ir::Call { @@ -963,12 +971,18 @@ impl<'a> Context<'a> { } CallType::ByName { - name, full_layout, .. + name, + ret_layout, + arg_layouts, + .. } => { + let top_level = + TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout); + // get the borrow signature let ps = self .param_map - .get_symbol(*name, *full_layout) + .get_symbol(*name, top_level) .expect("function is defined"); self.add_dec_after_application(call.arguments, ps, cont, &invoke_live_vars) } @@ -1222,7 +1236,7 @@ pub fn visit_proc<'a>( arena: &'a Bump, param_map: &'a ParamMap<'a>, proc: &mut Proc<'a>, - layout: Layout<'a>, + layout: TopLevelFunctionLayout<'a>, ) { let ctx = Context::new(arena, param_map); diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index fdb5db4f76..c5a9ad2e14 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -215,7 +215,7 @@ impl<'a> Proc<'a> { let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, procs)); for (key, proc) in procs.iter_mut() { - crate::inc_dec::visit_proc(arena, borrow_params, proc, arena.alloc(key.1).full()); + crate::inc_dec::visit_proc(arena, borrow_params, proc, key.1); } } @@ -410,8 +410,7 @@ impl<'a> Procs<'a> { let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, &result)); for (key, proc) in result.iter_mut() { - let layout = arena.alloc(key.1).full(); - crate::inc_dec::visit_proc(arena, borrow_params, proc, layout); + crate::inc_dec::visit_proc(arena, borrow_params, proc, key.1); } result @@ -454,8 +453,7 @@ impl<'a> Procs<'a> { let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, &result)); for (key, proc) in result.iter_mut() { - let layout = arena.alloc(key.1).full(); - crate::inc_dec::visit_proc(arena, borrow_params, proc, layout); + crate::inc_dec::visit_proc(arena, borrow_params, proc, key.1); } (result, borrow_params) @@ -1138,7 +1136,6 @@ impl UpdateModeId { pub enum CallType<'a> { ByName { name: Symbol, - full_layout: Layout<'a>, ret_layout: Layout<'a>, arg_layouts: &'a [Layout<'a>], specialization_id: CallSpecId, @@ -2627,10 +2624,6 @@ impl<'a> TopLevelFunctionLayout<'a> { }, } } - - pub fn full(&'a self) -> Layout<'a> { - Layout::FunctionPointer(self.arguments, &self.result) - } } fn specialize_naked_symbol<'a>( @@ -3701,7 +3694,7 @@ pub fn with_hole<'a>( } => { let loc_body = *boxed_body; - match layout_cache.from_var(env.arena, function_type, env.subs) { + match layout_cache.raw_from_var(env.arena, function_type, env.subs) { Err(e) => panic!("invalid layout {:?}", e), Ok(Layout::Closure(_argument_layouts, lambda_set, _ret_layout)) => { let mut captured_symbols = Vec::from_iter_in(captured_symbols, env.arena); @@ -3738,43 +3731,6 @@ pub fn with_hole<'a>( construct_closure_data(env, lambda_set, name, symbols, assigned, hole) } - Ok(Layout::FunctionPointer(_, _)) => { - // CLEANUP - unreachable!("closures should never have a function pointer layout"); - - // match procs.insert_anonymous( - // env, - // name, - // function_type, - // arguments, - // loc_body, - // CapturedSymbols::None, - // return_type, - // layout_cache, - // ) { - // Ok(layout) => { - // bg!(name); - // // TODO should the let have layout Pointer? - // // Stmt::Let(assigned, Expr::Struct(&[]), Layout::Struct(&[]), hole) - // if false { - // let mut hole = hole.clone(); - // substitute_in_exprs(env.arena, &mut hole, assigned, name); - // hole - // } else { - // Stmt::Let( - // assigned, - // call_by_pointer(env, procs, name, layout), - // layout, - // hole, - // ) - // } - // } - // - // Err(_error) => Stmt::RuntimeError( - // "TODO convert anonymous function error to a RuntimeError string", - // ), - // } - } Ok(_) => unreachable!(), } } @@ -3833,11 +3789,10 @@ pub fn with_hole<'a>( let full_layout = return_on_layout_error!( env, - layout_cache.from_var(env.arena, fn_var, env.subs) + layout_cache.raw_from_var(env.arena, fn_var, env.subs) ); let arg_layouts = match full_layout { - Layout::FunctionPointer(args, _) => args, Layout::Closure(args, _, _) => args, _ => unreachable!("function has layout that is not function pointer"), }; @@ -3905,38 +3860,6 @@ pub fn with_hole<'a>( env.arena.alloc(result), ); } - Layout::FunctionPointer(_, _) => { - // CLEANUP - unreachable!("should not be a function pointer"); - - // let function_symbol = env.unique_symbol(); - // let closure_data_symbol = function_symbol; - // - // // layout of the closure record - // let closure_data_layout = Layout::Struct(&[]); - // - // result = lambda_set_to_switch_make_branch_help( - // env, - // function_symbol, - // closure_data_symbol, - // closure_data_layout, - // arg_symbols, - // arg_layouts, - // ret_layout, - // assigned, - // hole, - // ); - // - // result = with_hole( - // env, - // loc_expr.value, - // fn_var, - // procs, - // layout_cache, - // closure_data_symbol, - // env.arena.alloc(result), - // ); - } _ => { todo!("{:?}", full_layout) } @@ -5461,13 +5384,11 @@ fn substitute_in_call<'a>( name, arg_layouts, ret_layout, - full_layout, specialization_id, } => substitute(subs, *name).map(|new| CallType::ByName { name: new, arg_layouts, ret_layout: *ret_layout, - full_layout: *full_layout, specialization_id: *specialization_id, }), CallType::Foreign { .. } => None, @@ -5930,13 +5851,10 @@ fn force_thunk<'a>( assigned: Symbol, hole: &'a Stmt<'a>, ) -> Stmt<'a> { - let full_layout = Layout::FunctionPointer(&[], env.arena.alloc(layout)); - let call = self::Call { call_type: CallType::ByName { name: thunk_name, ret_layout: layout, - full_layout, arg_layouts: &[], specialization_id: env.next_call_specialization_id(), }, @@ -6396,7 +6314,6 @@ fn call_by_name_help<'a>( // debug_assert!(!procs.module_thunks.contains(&proc_name), "{:?}", proc_name); let top_level_layout = TopLevelFunctionLayout::new(env.arena, argument_layouts, *ret_layout); - let function_layout = env.arena.alloc(top_level_layout).full(); // the arguments given to the function, stored in symbols let field_symbols = Vec::from_iter_in( @@ -6438,7 +6355,6 @@ fn call_by_name_help<'a>( call_type: CallType::ByName { name: proc_name, ret_layout: *ret_layout, - full_layout: function_layout, arg_layouts: argument_layouts, specialization_id: env.next_call_specialization_id(), }, @@ -6471,7 +6387,6 @@ fn call_by_name_help<'a>( call_type: CallType::ByName { name: proc_name, ret_layout: *ret_layout, - full_layout: function_layout, arg_layouts: argument_layouts, specialization_id: env.next_call_specialization_id(), }, @@ -6524,7 +6439,6 @@ fn call_by_name_help<'a>( call_type: CallType::ByName { name: proc_name, ret_layout: *ret_layout, - full_layout: function_layout, arg_layouts: argument_layouts, specialization_id: env.next_call_specialization_id(), }, @@ -6775,7 +6689,6 @@ fn call_specialized_proc<'a>( call_type: CallType::ByName { name: proc_name, ret_layout: function_layout.result, - full_layout: function_layout.full(), arg_layouts: function_layout.arguments, specialization_id: env.next_call_specialization_id(), }, @@ -6795,14 +6708,13 @@ fn call_specialized_proc<'a>( call_type: CallType::ByName { name: proc_name, ret_layout: function_layout.result, - full_layout: function_layout.full(), arg_layouts: function_layout.arguments, specialization_id: env.next_call_specialization_id(), }, arguments: field_symbols, }; - build_call(env, call, assigned, function_layout.full(), hole) + build_call(env, call, assigned, function_layout.result, hole) } } } else { @@ -6819,7 +6731,6 @@ fn call_specialized_proc<'a>( call_type: CallType::ByName { name: proc_name, ret_layout: function_layout.result, - full_layout: function_layout.full(), arg_layouts: function_layout.arguments, specialization_id: env.next_call_specialization_id(), }, @@ -8091,13 +8002,10 @@ fn union_lambda_set_branch_help<'a>( } }; - let full_layout = Layout::FunctionPointer(argument_layouts, env.arena.alloc(return_layout)); - // build the call let call = self::Call { call_type: CallType::ByName { name: function_symbol, - full_layout, ret_layout: return_layout, arg_layouts: argument_layouts, specialization_id: env.next_call_specialization_id(), @@ -8212,12 +8120,9 @@ fn enum_lambda_set_branch<'a>( } }; - let full_layout = Layout::FunctionPointer(argument_layouts, env.arena.alloc(return_layout)); - let call = self::Call { call_type: CallType::ByName { name: function_symbol, - full_layout, ret_layout: return_layout, arg_layouts: argument_layouts, specialization_id: env.next_call_specialization_id(), diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 44e6854cd5..953f41ff71 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -791,6 +791,50 @@ impl<'a> LayoutCache<'a> { } } + pub fn raw_from_var( + &mut self, + arena: &'a Bump, + var: Variable, + subs: &Subs, + ) -> Result, LayoutProblem> { + // Store things according to the root Variable, to avoid duplicate work. + let var = subs.get_root_key_without_compacting(var); + + let cached_var = CachedVariable::new(var); + + self.expand_to_fit(cached_var); + + use CachedLayout::*; + match self.layouts.probe_value(cached_var) { + Cached(result) => Ok(result), + Problem(problem) => Err(problem), + NotCached => { + let mut env = Env { + arena, + subs, + seen: MutSet::default(), + }; + + let result = Layout::from_var(&mut env, var); + + // Don't actually cache. The layout cache is very hard to get right in the presence + // of specialization, it's turned of for now so an invalid cache is never the cause + // of a problem + if false { + let cached_layout = match &result { + Ok(layout) => Cached(*layout), + Err(problem) => Problem(problem.clone()), + }; + + self.layouts + .update_value(cached_var, |existing| existing.value = cached_layout); + } + + result + } + } + } + fn expand_to_fit(&mut self, var: CachedVariable<'a>) { use ven_ena::unify::UnifyKey; @@ -1909,6 +1953,7 @@ impl LayoutId { struct IdsByLayout<'a> { by_id: MutMap, u32>, + toplevels_by_id: MutMap, u32>, next_id: u32, } @@ -1925,6 +1970,7 @@ impl<'a> LayoutIds<'a> { // There's probably a nicer way to write it that still works. let ids = self.by_symbol.entry(symbol).or_insert_with(|| IdsByLayout { by_id: HashMap::with_capacity_and_hasher(1, default_hasher()), + toplevels_by_id: Default::default(), next_id: 1, }); @@ -1941,6 +1987,39 @@ impl<'a> LayoutIds<'a> { LayoutId(answer) } + + /// Returns a LayoutId which is unique for the given symbol and layout. + /// If given the same symbol and same layout, returns the same LayoutId. + pub fn get_toplevel<'b>( + &mut self, + symbol: Symbol, + layout: &'b crate::ir::TopLevelFunctionLayout<'a>, + ) -> LayoutId { + // Note: this function does some weird stuff to satisfy the borrow checker. + // There's probably a nicer way to write it that still works. + let ids = self.by_symbol.entry(symbol).or_insert_with(|| IdsByLayout { + by_id: Default::default(), + toplevels_by_id: HashMap::with_capacity_and_hasher(1, default_hasher()), + next_id: 1, + }); + + // Get the id associated with this layout, or default to next_id. + let answer = ids + .toplevels_by_id + .get(&layout) + .copied() + .unwrap_or(ids.next_id); + + // If we had to default to next_id, it must not have been found; + // store the ID we're going to return and increment next_id. + if answer == ids.next_id { + ids.toplevels_by_id.insert(*layout, ids.next_id); + + ids.next_id += 1; + } + + LayoutId(answer) + } } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]