diff --git a/cli/src/repl/eval.rs b/cli/src/repl/eval.rs index ef6dfec3a4..e0e55541c2 100644 --- a/cli/src/repl/eval.rs +++ b/cli/src/repl/eval.rs @@ -6,7 +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::ir::ProcLayout; 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}; @@ -38,7 +38,7 @@ pub unsafe fn jit_to_ast<'a>( arena: &'a Bump, lib: Library, main_fn_name: &str, - layout: TopLevelFunctionLayout<'a>, + layout: ProcLayout<'a>, content: &Content, interns: &Interns, home: ModuleId, @@ -54,7 +54,7 @@ pub unsafe fn jit_to_ast<'a>( }; match layout { - TopLevelFunctionLayout { + ProcLayout { arguments: [], result, } => { @@ -153,20 +153,30 @@ fn jit_to_ast_help<'a>( Layout::Struct(field_layouts) => { let ptr_to_ast = |ptr: *const u8| match content { Content::Structure(FlatType::Record(fields, _)) => { - struct_to_ast(env, ptr, field_layouts, fields) + Ok(struct_to_ast(env, ptr, field_layouts, fields)) } Content::Structure(FlatType::EmptyRecord) => { - struct_to_ast(env, ptr, field_layouts, &MutMap::default()) + Ok(struct_to_ast(env, ptr, field_layouts, &MutMap::default())) } Content::Structure(FlatType::TagUnion(tags, _)) => { debug_assert_eq!(tags.len(), 1); let (tag_name, payload_vars) = tags.iter().next().unwrap(); - single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), payload_vars) + Ok(single_tag_union_to_ast( + env, + ptr, + field_layouts, + tag_name.clone(), + payload_vars, + )) } - Content::Structure(FlatType::FunctionOrTagUnion(tag_name, _, _)) => { - single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), &[]) + Content::Structure(FlatType::FunctionOrTagUnion(tag_name, _, _)) => Ok( + single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), &[]), + ), + Content::Structure(FlatType::Func(_, _, _)) => { + // a function with a struct as the closure environment + Err(ToAstProblem::FunctionLayout) } other => { unreachable!( @@ -181,12 +191,12 @@ fn jit_to_ast_help<'a>( let result_stack_size = layout.stack_size(env.ptr_bytes); - Ok(run_jit_function_dynamic_type!( + run_jit_function_dynamic_type!( lib, main_fn_name, result_stack_size as usize, |bytes: *const u8| { ptr_to_ast(bytes as *const u8) } - )) + ) } Layout::Union(UnionLayout::NonRecursive(union_layouts)) => match content { Content::Structure(FlatType::TagUnion(tags, _)) => { @@ -265,7 +275,6 @@ fn jit_to_ast_help<'a>( } Layout::Closure(_, _, _) => Err(ToAstProblem::FunctionLayout), - Layout::FunctionPointer(_, _) => Err(ToAstProblem::FunctionLayout), } } diff --git a/compiler/builtins/bitcode/src/str.zig b/compiler/builtins/bitcode/src/str.zig index 845fd2b853..2a81b69fc6 100644 --- a/compiler/builtins/bitcode/src/str.zig +++ b/compiler/builtins/bitcode/src/str.zig @@ -910,13 +910,14 @@ test "endsWith: hello world ends with world" { } // Str.concat -pub fn strConcatC(result_in_place: InPlace, arg1: RocStr, arg2: RocStr) callconv(.C) RocStr { - return @call(.{ .modifier = always_inline }, strConcat, .{ result_in_place, arg1, arg2 }); +pub fn strConcatC(arg1: RocStr, arg2: RocStr) callconv(.C) RocStr { + return @call(.{ .modifier = always_inline }, strConcat, .{ arg1, arg2 }); } -fn strConcat(result_in_place: InPlace, arg1: RocStr, arg2: RocStr) RocStr { +fn strConcat(arg1: RocStr, arg2: RocStr) RocStr { if (arg1.isEmpty()) { // the second argument is borrowed, so we must increment its refcount before returning + const result_in_place = InPlace.Clone; return RocStr.clone(result_in_place, arg2); } else if (arg2.isEmpty()) { // the first argument is owned, so we can return it without cloning @@ -974,7 +975,7 @@ test "RocStr.concat: small concat small" { roc_str3.deinit(); } - const result = strConcat(InPlace.Clone, roc_str1, roc_str2); + const result = strConcat(roc_str1, roc_str2); defer result.deinit(); diff --git a/compiler/gen_dev/src/object_builder.rs b/compiler/gen_dev/src/object_builder.rs index c2ccda29d2..e3b09d7b52 100644 --- a/compiler/gen_dev/src/object_builder.rs +++ b/compiler/gen_dev/src/object_builder.rs @@ -9,7 +9,7 @@ use object::{ }; use roc_collections::all::MutMap; use roc_module::symbol; -use roc_mono::ir::{Proc, TopLevelFunctionLayout}; +use roc_mono::ir::{Proc, ProcLayout}; use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Triple}; // This is used by some code below which is currently commented out. @@ -21,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, TopLevelFunctionLayout<'a>), Proc<'a>>, + procedures: MutMap<(symbol::Symbol, ProcLayout<'a>), Proc<'a>>, ) -> Result { match target { Triple { @@ -144,7 +144,7 @@ fn generate_wrapper<'a, B: Backend<'a>>( fn build_object<'a, B: Backend<'a>>( env: &'a Env, - procedures: MutMap<(symbol::Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>, + procedures: MutMap<(symbol::Symbol, ProcLayout<'a>), Proc<'a>>, mut backend: B, mut output: Object, ) -> Result { diff --git a/compiler/gen_llvm/src/llvm/bitcode.rs b/compiler/gen_llvm/src/llvm/bitcode.rs index b9cd56ff58..5bf645980f 100644 --- a/compiler/gen_llvm/src/llvm/bitcode.rs +++ b/compiler/gen_llvm/src/llvm/bitcode.rs @@ -151,9 +151,6 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( } match closure_data_layout { - Layout::FunctionPointer(_, _) => { - // do nothing - } Layout::Closure(_, lambda_set, _) => { if let Layout::Struct(&[]) = lambda_set.runtime_representation() { // do nothing @@ -508,7 +505,6 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>( let default = [value1, value2]; let arguments_cast = match closure_data_layout { - Layout::FunctionPointer(_, _) => &default, Layout::Closure(_, lambda_set, _) => { if let Layout::Struct(&[]) = lambda_set.runtime_representation() { &default diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 6b65b7d985..64b48ac3b8 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_function_layout, basic_type_from_layout, - block_of_memory, block_of_memory_slices, ptr_int, + basic_type_from_builtin, basic_type_from_layout, block_of_memory, block_of_memory_slices, + ptr_int, }; use crate::llvm::refcounting::{ decrement_refcount_layout, increment_refcount_layout, PointerToRefcount, @@ -49,11 +49,10 @@ use roc_module::ident::TagName; use roc_module::low_level::LowLevel; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_mono::ir::{ - BranchInfo, CallType, EntryPoint, ExceptionId, JoinPointId, ModifyRc, OptLevel, - TopLevelFunctionLayout, Wrapped, + BranchInfo, CallType, EntryPoint, ExceptionId, JoinPointId, ModifyRc, OptLevel, ProcLayout, + Wrapped, }; -use roc_mono::layout::{Builtin, InPlace, LambdaSet, Layout, LayoutIds, UnionLayout}; -use std::convert::TryFrom; +use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, UnionLayout}; /// This is for Inkwell's FunctionValue::verify - we want to know the verification /// output in debug builds, but we don't want it to print to stdout in release builds! @@ -118,7 +117,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>])>, } @@ -132,7 +131,7 @@ impl<'a, 'ctx> Scope<'a, 'ctx> { pub fn insert_top_level_thunk( &mut self, symbol: Symbol, - layout: &'a TopLevelFunctionLayout<'a>, + layout: &'a ProcLayout<'a>, function_value: FunctionValue<'ctx>, ) { self.top_level_thunks @@ -588,7 +587,7 @@ fn promote_to_main_function<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, mod_solutions: &'a ModSolutions, symbol: Symbol, - top_level: TopLevelFunctionLayout<'a>, + top_level: ProcLayout<'a>, ) -> (&'static str, FunctionValue<'ctx>) { let it = top_level.arguments.iter().copied(); let bytes = roc_mono::alias_analysis::func_name_bytes_help(symbol, it, top_level.result); @@ -1638,9 +1637,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( } } EmptyArray => empty_polymorphic_list(env), - Array { elem_layout, elems } => { - list_literal(env, layout.in_place(), scope, elem_layout, elems) - } + Array { elem_layout, elems } => list_literal(env, scope, elem_layout, elems), RuntimeErrorFunction(_) => todo!(), } } @@ -1794,7 +1791,6 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>( fn list_literal<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - inplace: InPlace, scope: &Scope<'a, 'ctx>, elem_layout: &Layout<'a>, elems: &&[Symbol], @@ -1808,7 +1804,7 @@ fn list_literal<'a, 'ctx, 'env>( let len_type = env.ptr_int(); let len = len_type.const_int(len_u64, false); - allocate_list(env, inplace, elem_layout, len) + allocate_list(env, elem_layout, len) }; // Copy the elements from the list literal into the array @@ -3102,7 +3098,7 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>( pub fn build_proc_headers<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, mod_solutions: &'a ModSolutions, - procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), roc_mono::ir::Proc<'a>>, + procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>, scope: &mut Scope<'a, 'ctx>, // alias_analysis_solutions: AliasAnalysisSolutions, ) -> Vec< @@ -3144,7 +3140,7 @@ pub fn build_proc_headers<'a, 'ctx, 'env>( pub fn build_procedures<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, opt_level: OptLevel, - procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), roc_mono::ir::Proc<'a>>, + procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>, entry_point: EntryPoint<'a>, ) { build_procedures_help(env, opt_level, procedures, entry_point); @@ -3153,7 +3149,7 @@ pub fn build_procedures<'a, 'ctx, 'env>( pub fn build_procedures_return_main<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, opt_level: OptLevel, - procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), roc_mono::ir::Proc<'a>>, + procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>, entry_point: EntryPoint<'a>, ) -> (&'static str, FunctionValue<'ctx>) { let mod_solutions = build_procedures_help(env, opt_level, procedures, entry_point); @@ -3164,7 +3160,7 @@ pub fn build_procedures_return_main<'a, 'ctx, 'env>( fn build_procedures_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, opt_level: OptLevel, - procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), roc_mono::ir::Proc<'a>>, + procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>, entry_point: EntryPoint<'a>, ) -> &'a ModSolutions { let mut layout_ids = roc_mono::layout::LayoutIds::default(); @@ -3400,122 +3396,6 @@ pub fn build_closure_caller<'a, 'ctx, 'env>( build_host_exposed_alias_size(env, def_name, alias_symbol, layout); } -fn build_function_caller<'a, 'ctx, 'env>( - env: &'a Env<'a, 'ctx, 'env>, - def_name: &str, - alias_symbol: Symbol, - arguments: &[Layout<'a>], - result: &Layout<'a>, -) { - let context = &env.context; - let builder = env.builder; - - // STEP 1: build function header - - // e.g. `roc__main_1_Fx_caller` - let function_name = format!( - "roc_{}_{}_caller", - def_name, - alias_symbol.ident_string(&env.interns) - ); - - let mut argument_types = Vec::with_capacity_in(arguments.len() + 3, env.arena); - - for layout in arguments { - let arg_type = basic_type_from_layout(env, layout); - let arg_ptr_type = arg_type.ptr_type(AddressSpace::Generic); - - argument_types.push(arg_ptr_type.into()); - } - - let function_pointer_type = { - let mut args = Vec::new_in(env.arena); - args.extend(arguments.iter().cloned()); - - // pretend the closure layout is empty - args.push(Layout::Struct(&[])); - - // this is already a (function) pointer type - basic_type_from_function_layout(env, &args, result) - }; - argument_types.push(function_pointer_type); - - let closure_argument_type = { - let basic_type = basic_type_from_layout(env, &Layout::Struct(&[])); - - basic_type.ptr_type(AddressSpace::Generic) - }; - argument_types.push(closure_argument_type.into()); - - let result_type = basic_type_from_layout(env, result); - - let roc_call_result_type = - context.struct_type(&[context.i64_type().into(), result_type], false); - - let output_type = { roc_call_result_type.ptr_type(AddressSpace::Generic) }; - argument_types.push(output_type.into()); - - let function_type = context.void_type().fn_type(&argument_types, false); - - let function_value = add_func( - env.module, - function_name.as_str(), - function_type, - Linkage::External, - C_CALL_CONV, - ); - - // STEP 2: build function body - - let entry = context.append_basic_block(function_value, "entry"); - - builder.position_at_end(entry); - - let mut parameters = function_value.get_params(); - let output = parameters.pop().unwrap().into_pointer_value(); - let _closure_data_ptr = parameters.pop().unwrap().into_pointer_value(); - let function_ptr = parameters.pop().unwrap().into_pointer_value(); - - let actual_function_type = basic_type_from_function_layout(env, arguments, result); - - let function_ptr = builder - .build_bitcast(function_ptr, actual_function_type, "cast") - .into_pointer_value(); - - let mut parameters = parameters; - - for param in parameters.iter_mut() { - debug_assert!(param.is_pointer_value()); - *param = builder.build_load(param.into_pointer_value(), "load_param"); - } - - let call_result = invoke_and_catch( - env, - function_value, - CallableValue::try_from(function_ptr).unwrap(), - C_CALL_CONV, - ¶meters, - result_type, - ); - - builder.build_store(output, call_result); - - builder.build_return(None); - - // STEP 3: build a {} -> u64 function that gives the size of the return type - build_host_exposed_alias_size_help( - env, - def_name, - alias_symbol, - Some("result"), - roc_call_result_type.into(), - ); - - // STEP 4: build a {} -> u64 function that gives the size of the function - 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, @@ -3583,14 +3463,14 @@ pub fn build_proc<'a, 'ctx, 'env>( fn_val: FunctionValue<'ctx>, ) { use roc_mono::ir::HostExposedLayouts; + use roc_mono::layout::RawFunctionLayout; let copy = proc.host_exposed_layouts.clone(); - let fn_name = fn_val.get_name().to_string_lossy(); match copy { HostExposedLayouts::NotHostExposed => {} HostExposedLayouts::HostExposed { rigids: _, aliases } => { for (name, (symbol, top_level, layout)) in aliases { match layout { - Layout::Closure(arguments, closure, result) => { + RawFunctionLayout::Function(arguments, closure, result) => { // define closure size and return value size, e.g. // // * roc__mainForHost_1_Update_size() -> i64 @@ -3627,18 +3507,10 @@ pub fn build_proc<'a, 'ctx, 'env>( env, &fn_name, evaluator, name, arguments, closure, result, ) } - Layout::FunctionPointer(arguments, result) => { - // define function size (equal to pointer size) and return value size, e.g. - // - // * roc__mainForHost_1_Update_size() -> i64 - // * roc__mainForHost_1_Update_result_size() -> i64 - build_function_caller(env, &fn_name, name, arguments, result) - } - Layout::Builtin(_) => {} - Layout::Struct(_) => {} - Layout::Union(_) => {} - Layout::RecursivePointer => {} + RawFunctionLayout::ZeroArgumentThunk(_) => { + // do nothing + } } } } @@ -4289,13 +4161,13 @@ fn run_low_level<'a, 'ctx, 'env>( // Str.concat : Str, Str -> Str debug_assert_eq!(args.len(), 2); - str_concat(env, layout.in_place(), scope, args[0], args[1]) + str_concat(env, scope, args[0], args[1]) } StrJoinWith => { // Str.joinWith : List Str, Str -> Str debug_assert_eq!(args.len(), 2); - str_join_with(env, layout.in_place(), scope, args[0], args[1]) + str_join_with(env, scope, args[0], args[1]) } StrStartsWith => { // Str.startsWith : Str, Str -> Bool @@ -4349,7 +4221,7 @@ fn run_low_level<'a, 'ctx, 'env>( // Str.split : Str, Str -> List Str debug_assert_eq!(args.len(), 2); - str_split(env, scope, layout.in_place(), args[0], args[1]) + str_split(env, scope, args[0], args[1]) } StrIsEmpty => { // Str.isEmpty : Str -> Str @@ -4384,7 +4256,7 @@ fn run_low_level<'a, 'ctx, 'env>( let (arg, arg_layout) = load_symbol_and_layout(scope, &args[0]); - list_single(env, layout.in_place(), arg, arg_layout) + list_single(env, arg, arg_layout) } ListRepeat => { // List.repeat : Int, elem -> List elem @@ -4401,7 +4273,7 @@ fn run_low_level<'a, 'ctx, 'env>( let (list, list_layout) = load_symbol_and_layout(scope, &args[0]); - list_reverse(env, layout.in_place(), list, list_layout) + list_reverse(env, list, list_layout) } ListConcat => { debug_assert_eq!(args.len(), 2); @@ -4410,14 +4282,7 @@ fn run_low_level<'a, 'ctx, 'env>( let second_list = load_symbol(scope, &args[1]); - list_concat( - env, - layout.in_place(), - parent, - first_list, - second_list, - list_layout, - ) + list_concat(env, parent, first_list, second_list, list_layout) } ListContains => { // List.contains : List elem, elem -> Bool @@ -4450,7 +4315,7 @@ fn run_low_level<'a, 'ctx, 'env>( let original_wrapper = load_symbol(scope, &args[0]).into_struct_value(); let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]); - list_append(env, layout.in_place(), original_wrapper, elem, elem_layout) + list_append(env, original_wrapper, elem, elem_layout) } ListSwap => { // List.swap : List elem, Nat, Nat -> List elem @@ -4502,7 +4367,7 @@ fn run_low_level<'a, 'ctx, 'env>( let original_wrapper = load_symbol(scope, &args[0]).into_struct_value(); let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]); - list_prepend(env, layout.in_place(), original_wrapper, elem, elem_layout) + list_prepend(env, original_wrapper, elem, elem_layout) } ListJoin => { // List.join : List (List elem) -> List elem @@ -4510,7 +4375,7 @@ fn run_low_level<'a, 'ctx, 'env>( let (list, outer_list_layout) = load_symbol_and_layout(scope, &args[0]); - list_join(env, layout.in_place(), parent, list, outer_list_layout) + list_join(env, parent, list, outer_list_layout) } NumAbs | NumNeg | NumRound | NumSqrtUnchecked | NumLogUnchecked | NumSin | NumCos | NumCeiling | NumFloor | NumToFloat | NumIsFinite | NumAtan | NumAcos | NumAsin => { diff --git a/compiler/gen_llvm/src/llvm/build_hash.rs b/compiler/gen_llvm/src/llvm/build_hash.rs index d72b02cad5..23728d778c 100644 --- a/compiler/gen_llvm/src/llvm/build_hash.rs +++ b/compiler/gen_llvm/src/llvm/build_hash.rs @@ -88,7 +88,7 @@ fn build_hash_layout<'a, 'ctx, 'env>( } }, - Layout::FunctionPointer(_, _) | Layout::Closure(_, _, _) => { + Layout::Closure(_, _, _) => { unreachable!("the type system will guarantee these are never hashed") } } diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index e3b9901a0e..f62442df02 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -1,7 +1,7 @@ #![allow(clippy::too_many_arguments)] use crate::llvm::bitcode::{ - build_dec_wrapper, build_eq_wrapper, build_inc_n_wrapper, build_inc_wrapper, - build_transform_caller, call_bitcode_fn, call_void_bitcode_fn, + build_dec_wrapper, build_eq_wrapper, build_inc_n_wrapper, build_inc_wrapper, call_bitcode_fn, + call_void_bitcode_fn, }; use crate::llvm::build::{ allocate_with_refcount_help, cast_basic_basic, complex_bitcast, Env, RocFunctionCall, @@ -14,7 +14,7 @@ use inkwell::types::{BasicType, BasicTypeEnum, PointerType}; use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue}; use inkwell::{AddressSpace, IntPredicate}; use roc_builtins::bitcode; -use roc_mono::layout::{Builtin, InPlace, Layout, LayoutIds}; +use roc_mono::layout::{Builtin, Layout, LayoutIds}; fn list_returned_from_zig<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, @@ -83,7 +83,6 @@ pub fn pass_as_opaque<'a, 'ctx, 'env>( /// List.single : a -> List a pub fn list_single<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - _inplace: InPlace, element: BasicValueEnum<'ctx>, element_layout: &Layout<'a>, ) -> BasicValueEnum<'ctx> { @@ -124,7 +123,6 @@ pub fn list_repeat<'a, 'ctx, 'env>( /// List.prepend : List elem, elem -> List elem pub fn list_prepend<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - inplace: InPlace, original_wrapper: StructValue<'ctx>, elem: BasicValueEnum<'ctx>, elem_layout: &Layout<'a>, @@ -146,7 +144,7 @@ pub fn list_prepend<'a, 'ctx, 'env>( ); // Allocate space for the new array that we'll copy into. - let clone_ptr = allocate_list(env, inplace, elem_layout, new_list_len); + let clone_ptr = allocate_list(env, elem_layout, new_list_len); builder.build_store(clone_ptr, elem); @@ -189,7 +187,6 @@ pub fn list_prepend<'a, 'ctx, 'env>( /// List.join : List (List elem) -> List elem pub fn list_join<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - _inplace: InPlace, _parent: FunctionValue<'ctx>, outer_list: BasicValueEnum<'ctx>, outer_list_layout: &Layout<'a>, @@ -221,17 +218,16 @@ pub fn list_join<'a, 'ctx, 'env>( /// List.reverse : List elem -> List elem pub fn list_reverse<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - _output_inplace: InPlace, list: BasicValueEnum<'ctx>, list_layout: &Layout<'a>, ) -> BasicValueEnum<'ctx> { - let (_, element_layout) = match *list_layout { - Layout::Builtin(Builtin::EmptyList) => ( - InPlace::InPlace, + let element_layout = match *list_layout { + Layout::Builtin(Builtin::EmptyList) => { // this pointer will never actually be dereferenced - Layout::Builtin(Builtin::Int64), - ), - Layout::Builtin(Builtin::List(elem_layout)) => (InPlace::Clone, *elem_layout), + Layout::Builtin(Builtin::Int64) + } + + Layout::Builtin(Builtin::List(elem_layout)) => *elem_layout, _ => unreachable!("Invalid layout {:?} in List.reverse", list_layout), }; @@ -287,7 +283,6 @@ pub fn list_get_unsafe<'a, 'ctx, 'env>( /// List.append : List elem, elem -> List elem pub fn list_append<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - _inplace: InPlace, original_wrapper: StructValue<'ctx>, element: BasicValueEnum<'ctx>, element_layout: &Layout<'a>, @@ -658,54 +653,6 @@ pub fn list_keep_errs<'a, 'ctx, 'env>( ) } -pub fn list_keep_result<'a, 'ctx, 'env>( - env: &Env<'a, 'ctx, 'env>, - layout_ids: &mut LayoutIds<'a>, - transform: FunctionValue<'ctx>, - transform_layout: Layout<'a>, - closure_data: BasicValueEnum<'ctx>, - closure_data_layout: Layout<'a>, - list: BasicValueEnum<'ctx>, - before_layout: &Layout<'a>, - after_layout: &Layout<'a>, - op: &str, -) -> BasicValueEnum<'ctx> { - let builder = env.builder; - - let result_layout = match transform_layout { - Layout::FunctionPointer(_, ret) => ret, - Layout::Closure(_, _, ret) => ret, - _ => unreachable!("not a callable layout"), - }; - - let closure_data_ptr = builder.build_alloca(closure_data.get_type(), "closure_data_ptr"); - env.builder.build_store(closure_data_ptr, closure_data); - - let stepper_caller = - build_transform_caller(env, transform, closure_data_layout, &[*before_layout]) - .as_global_value() - .as_pointer_value(); - - let inc_closure = build_inc_wrapper(env, layout_ids, &transform_layout); - let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout); - - call_bitcode_fn( - env, - &[ - pass_list_as_i128(env, list), - pass_as_opaque(env, closure_data_ptr), - stepper_caller.into(), - env.alignment_intvalue(&before_layout), - layout_width(env, before_layout), - layout_width(env, after_layout), - layout_width(env, result_layout), - inc_closure.as_global_value().as_pointer_value().into(), - dec_result_fn.as_global_value().as_pointer_value().into(), - ], - op, - ) -} - /// List.sortWith : List a, (a, a -> Ordering) -> List a pub fn list_sort_with<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, @@ -852,7 +799,6 @@ pub fn list_map3<'a, 'ctx, 'env>( /// List.concat : List elem, List elem -> List elem pub fn list_concat<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - _inplace: InPlace, _parent: FunctionValue<'ctx>, first_list: BasicValueEnum<'ctx>, second_list: BasicValueEnum<'ctx>, @@ -1118,7 +1064,6 @@ pub fn load_list_ptr<'ctx>( pub fn allocate_list<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - inplace: InPlace, elem_layout: &Layout<'a>, number_of_elements: IntValue<'ctx>, ) -> PointerValue<'ctx> { @@ -1131,14 +1076,9 @@ pub fn allocate_list<'a, 'ctx, 'env>( let number_of_data_bytes = builder.build_int_mul(bytes_per_element, number_of_elements, "data_length"); - let rc1 = match inplace { - InPlace::InPlace => number_of_elements, - InPlace::Clone => { - // the refcount of a new list is initially 1 - // we assume that the list is indeed used (dead variables are eliminated) - crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes) - } - }; + // the refcount of a new list is initially 1 + // we assume that the list is indeed used (dead variables are eliminated) + let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes); allocate_with_refcount_help(env, elem_layout, number_of_data_bytes, rc1) } diff --git a/compiler/gen_llvm/src/llvm/build_str.rs b/compiler/gen_llvm/src/llvm/build_str.rs index 4692f5eaa8..ee8576ceb8 100644 --- a/compiler/gen_llvm/src/llvm/build_str.rs +++ b/compiler/gen_llvm/src/llvm/build_str.rs @@ -6,7 +6,7 @@ use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, Str use inkwell::AddressSpace; use roc_builtins::bitcode; use roc_module::symbol::Symbol; -use roc_mono::layout::{Builtin, InPlace, Layout}; +use roc_mono::layout::{Builtin, Layout}; use super::build::load_symbol; @@ -16,7 +16,6 @@ pub static CHAR_LAYOUT: Layout = Layout::Builtin(Builtin::Int8); pub fn str_split<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, scope: &Scope<'a, 'ctx>, - inplace: InPlace, str_symbol: Symbol, delimiter_symbol: Symbol, ) -> BasicValueEnum<'ctx> { @@ -33,7 +32,7 @@ pub fn str_split<'a, 'ctx, 'env>( .into_int_value(); // a pointer to the elements - let ret_list_ptr = allocate_list(env, inplace, &Layout::Builtin(Builtin::Str), segment_count); + let ret_list_ptr = allocate_list(env, &Layout::Builtin(Builtin::Str), segment_count); // get the RocStr type defined by zig let roc_str_type = env.module.get_struct_type("str.RocStr").unwrap(); @@ -109,7 +108,6 @@ pub fn destructure<'ctx>( /// Str.concat : Str, Str -> Str pub fn str_concat<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - inplace: InPlace, scope: &Scope<'a, 'ctx>, str1_symbol: Symbol, str2_symbol: Symbol, @@ -120,14 +118,7 @@ pub fn str_concat<'a, 'ctx, 'env>( call_bitcode_fn( env, - &[ - env.context - .i8_type() - .const_int(inplace as u64, false) - .into(), - str1_i128.into(), - str2_i128.into(), - ], + &[str1_i128.into(), str2_i128.into()], &bitcode::STR_CONCAT, ) } @@ -135,7 +126,6 @@ pub fn str_concat<'a, 'ctx, 'env>( /// Str.join : List Str, Str -> Str pub fn str_join_with<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - _inplace: InPlace, scope: &Scope<'a, 'ctx>, list_symbol: Symbol, str_symbol: Symbol, diff --git a/compiler/gen_llvm/src/llvm/compare.rs b/compiler/gen_llvm/src/llvm/compare.rs index fa0185f01e..8b1758eaf5 100644 --- a/compiler/gen_llvm/src/llvm/compare.rs +++ b/compiler/gen_llvm/src/llvm/compare.rs @@ -195,7 +195,7 @@ fn build_eq<'a, 'ctx, 'env>( } }, - Layout::FunctionPointer(_, _) | Layout::Closure(_, _, _) => { + Layout::Closure(_, _, _) => { unreachable!("the type system will guarantee these are never compared") } } @@ -336,7 +336,7 @@ fn build_neq<'a, 'ctx, 'env>( unreachable!("recursion pointers should never be compared directly") } - Layout::FunctionPointer(_, _) | Layout::Closure(_, _, _) => { + Layout::Closure(_, _, _) => { unreachable!("the type system will guarantee these are never compared") } } diff --git a/compiler/gen_llvm/src/llvm/convert.rs b/compiler/gen_llvm/src/llvm/convert.rs index e00c03c333..27b9c82356 100644 --- a/compiler/gen_llvm/src/llvm/convert.rs +++ b/compiler/gen_llvm/src/llvm/convert.rs @@ -4,24 +4,6 @@ use inkwell::types::{BasicType, BasicTypeEnum, IntType, StructType}; use inkwell::AddressSpace; use roc_mono::layout::{Builtin, Layout, UnionLayout}; -pub fn basic_type_from_function_layout<'a, 'ctx, 'env>( - env: &crate::llvm::build::Env<'a, 'ctx, 'env>, - args: &[Layout<'_>], - ret_layout: &Layout<'_>, -) -> BasicTypeEnum<'ctx> { - let ret_type = basic_type_from_layout(env, &ret_layout); - let mut arg_basic_types = Vec::with_capacity_in(args.len(), env.arena); - - for arg_layout in args.iter() { - arg_basic_types.push(basic_type_from_layout(env, arg_layout)); - } - - let fn_type = ret_type.fn_type(arg_basic_types.into_bump_slice(), false); - let ptr_type = fn_type.ptr_type(AddressSpace::Generic); - - ptr_type.as_basic_type_enum() -} - fn basic_type_from_record<'a, 'ctx, 'env>( env: &crate::llvm::build::Env<'a, 'ctx, 'env>, fields: &[Layout<'_>], @@ -44,7 +26,6 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>( use Layout::*; match 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/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index 773b02e9cf..dbee02c4a3 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -750,8 +750,6 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( Some(function) } }, - - FunctionPointer(_, _) => None, } } diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 572d224b05..e306b7cbd7 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -20,7 +20,7 @@ use roc_module::symbol::{ }; use roc_mono::ir::{ CapturedSymbols, EntryPoint, ExternalSpecializations, PartialProc, PendingSpecialization, Proc, - Procs, TopLevelFunctionLayout, + ProcLayout, Procs, }; use roc_mono::layout::{Layout, LayoutCache, LayoutProblem}; use roc_parse::ast::{self, StrLiteral, TypeAnnotation}; @@ -708,7 +708,7 @@ pub struct MonomorphizedModule<'a> { pub can_problems: MutMap>, pub type_problems: MutMap>, pub mono_problems: MutMap>, - pub procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>, + pub procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, pub entry_point: EntryPoint<'a>, pub exposed_to_host: MutMap, pub header_sources: MutMap)>, @@ -781,7 +781,7 @@ enum Msg<'a> { ident_ids: IdentIds, layout_cache: LayoutCache<'a>, external_specializations_requested: BumpMap>, - procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>, + procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, problems: Vec, module_timing: ModuleTiming, subs: Subs, @@ -829,7 +829,7 @@ struct State<'a> { pub module_cache: ModuleCache<'a>, pub dependencies: Dependencies<'a>, - pub procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>, + pub procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, pub exposed_to_host: MutMap, /// This is the "final" list of IdentIds, after canonicalization and constraint gen @@ -860,7 +860,7 @@ struct State<'a> { pub needs_specialization: MutSet, pub all_pending_specializations: - MutMap, PendingSpecialization<'a>>>, + MutMap, PendingSpecialization<'a>>>, pub specializations_in_flight: u32, @@ -2065,8 +2065,6 @@ fn update<'a>( && state.dependencies.solved_all() && state.goal_phase == Phase::MakeSpecializations { - Proc::insert_refcount_operations(arena, &mut state.procedures); - // display the mono IR of the module, for debug purposes if roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS { let procs_string = state @@ -2080,6 +2078,8 @@ fn update<'a>( println!("{}", result); } + Proc::insert_refcount_operations(arena, &mut state.procedures); + // This is not safe with the new non-recursive RC updates that we do for tag unions // // Proc::optimize_refcount_operations( @@ -2237,7 +2237,7 @@ fn finish_specialization( // the entry point is not specialized. This can happen if the repl output // is a function value EntryPoint { - layout: roc_mono::ir::TopLevelFunctionLayout { + layout: roc_mono::ir::ProcLayout { arguments: &[], result: Layout::Struct(&[]), }, @@ -4056,7 +4056,7 @@ fn add_def_to_module<'a>( procs.insert_exposed( symbol, - TopLevelFunctionLayout::from_layout(mono_env.arena, layout), + ProcLayout::from_layout(mono_env.arena, layout), mono_env.arena, mono_env.subs, def.annotation, @@ -4087,14 +4087,14 @@ fn add_def_to_module<'a>( if is_exposed { let annotation = def.expr_var; - let layout = match layout_cache.from_var( + let top_level = match layout_cache.from_var( mono_env.arena, annotation, mono_env.subs, ) { Ok(l) => { // remember, this is a 0-argument thunk - Layout::FunctionPointer(&[], mono_env.arena.alloc(l)) + ProcLayout::new(mono_env.arena, &[], l) } Err(LayoutProblem::Erroneous) => { let message = "top level function has erroneous type"; @@ -4115,7 +4115,7 @@ fn add_def_to_module<'a>( procs.insert_exposed( symbol, - TopLevelFunctionLayout::from_layout(mono_env.arena, layout), + top_level, mono_env.arena, mono_env.subs, def.annotation, diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index f56c5799f7..d107bdffe4 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -396,17 +396,15 @@ impl<'a> PackageModuleIds<'a> { fn insert_debug_name(module_id: ModuleId, module_name: &PQModuleName) { let mut names = DEBUG_MODULE_ID_NAMES.lock().expect("Failed to acquire lock for Debug interning into DEBUG_MODULE_ID_NAMES, presumably because a thread panicked."); - if !names.contains_key(&module_id.0) { - match module_name { - PQModuleName::Unqualified(module) => { - names.insert(module_id.0, module.to_string().into()); - } + names + .entry(module_id.0) + .or_insert_with(|| match module_name { + PQModuleName::Unqualified(module) => module.to_string().into(), PQModuleName::Qualified(package, module) => { let name = format!("{}.{}", package, module).into(); - names.insert(module_id.0, name); + name } - } - } + }); } #[cfg(not(debug_assertions))] @@ -464,9 +462,9 @@ impl ModuleIds { let mut names = DEBUG_MODULE_ID_NAMES.lock().expect("Failed to acquire lock for Debug interning into DEBUG_MODULE_ID_NAMES, presumably because a thread panicked."); // TODO make sure modules are never added more than once! - if !names.contains_key(&module_id.0) { - names.insert(module_id.0, module_name.to_string().into()); - } + names + .entry(module_id.0) + .or_insert_with(|| module_name.to_string().into()); } #[cfg(not(debug_assertions))] diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index ebba54fb80..24b83b98f4 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -144,7 +144,7 @@ where "{:?}: {:?} with {:?} args", proc.name, bytes_as_ascii(&bytes), - proc.args.len() + (proc.args, proc.ret_layout), ); } @@ -173,10 +173,7 @@ where morphic_lib::solve(program) } -fn build_entry_point( - layout: crate::ir::TopLevelFunctionLayout, - func_name: FuncName, -) -> Result { +fn build_entry_point(layout: crate::ir::ProcLayout, func_name: FuncName) -> Result { let mut builder = FuncDefBuilder::new(); let block = builder.add_block(); @@ -976,7 +973,6 @@ fn layout_spec(builder: &mut FuncDefBuilder, layout: &Layout) -> Result } => worst_case_type(builder), }, RecursivePointer => worst_case_type(builder), - FunctionPointer(_, _) => todo!(), Closure(_, lambda_set, _) => layout_spec(builder, &lambda_set.runtime_representation()), } } diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 54808abfaf..1d28bd091a 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -1,4 +1,4 @@ -use crate::ir::{Expr, JoinPointId, Param, Proc, Stmt, TopLevelFunctionLayout}; +use crate::ir::{Expr, JoinPointId, Param, Proc, ProcLayout, Stmt}; use crate::layout::Layout; use bumpalo::collections::Vec; use bumpalo::Bump; @@ -18,7 +18,7 @@ fn should_borrow_layout(layout: &Layout) -> bool { pub fn infer_borrow<'a>( arena: &'a Bump, - procs: &MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>, + procs: &MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, ) -> ParamMap<'a> { let mut param_map = ParamMap { items: MutMap::default(), @@ -67,7 +67,7 @@ pub fn infer_borrow<'a>( #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub enum Key<'a> { - Declaration(Symbol, TopLevelFunctionLayout<'a>), + Declaration(Symbol, ProcLayout<'a>), JoinPoint(JoinPointId), } @@ -96,11 +96,7 @@ impl<'a> IntoIterator for &'a ParamMap<'a> { } impl<'a> ParamMap<'a> { - pub fn get_symbol( - &self, - symbol: Symbol, - layout: TopLevelFunctionLayout<'a>, - ) -> Option<&'a [Param<'a>]> { + pub fn get_symbol(&self, symbol: Symbol, layout: ProcLayout<'a>) -> Option<&'a [Param<'a>]> { let key = Key::Declaration(symbol, layout); self.items.get(&key).copied() @@ -155,12 +151,7 @@ impl<'a> ParamMap<'a> { .into_bump_slice() } - fn visit_proc( - &mut self, - arena: &'a Bump, - proc: &Proc<'a>, - key: (Symbol, TopLevelFunctionLayout<'a>), - ) { + fn visit_proc(&mut self, arena: &'a Bump, proc: &Proc<'a>, key: (Symbol, ProcLayout<'a>)) { if proc.must_own_arguments { self.visit_proc_always_owned(arena, proc, key); return; @@ -178,7 +169,7 @@ impl<'a> ParamMap<'a> { &mut self, arena: &'a Bump, proc: &Proc<'a>, - key: (Symbol, TopLevelFunctionLayout<'a>), + key: (Symbol, ProcLayout<'a>), ) { let already_in_there = self.items.insert( Key::Declaration(proc.name, key.1), @@ -371,7 +362,7 @@ impl<'a> BorrowInfState<'a> { arg_layouts, .. } => { - let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout); + let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout); // get the borrow signature of the applied function let ps = self @@ -414,7 +405,7 @@ impl<'a> BorrowInfState<'a> { debug_assert!(op.is_higher_order()); - let closure_layout = TopLevelFunctionLayout { + let closure_layout = ProcLayout { arguments: arg_layouts, result: *ret_layout, }; @@ -609,7 +600,7 @@ impl<'a> BorrowInfState<'a> { Stmt::Ret(z), ) = (v, b) { - let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout); + let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout); if self.current_proc == *g && x == *z { // anonymous functions (for which the ps may not be known) @@ -702,7 +693,7 @@ impl<'a> BorrowInfState<'a> { } } - fn collect_proc(&mut self, proc: &Proc<'a>, layout: TopLevelFunctionLayout<'a>) { + fn collect_proc(&mut self, proc: &Proc<'a>, layout: ProcLayout<'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/inc_dec.rs b/compiler/mono/src/inc_dec.rs index 0e9964a8f5..d7ca917aa8 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, TopLevelFunctionLayout}; +use crate::ir::{Expr, JoinPointId, ModifyRc, Param, Proc, ProcLayout, Stmt}; use crate::layout::Layout; use bumpalo::collections::Vec; use bumpalo::Bump; @@ -497,7 +497,7 @@ impl<'a> Context<'a> { const FUNCTION: bool = BORROWED; const CLOSURE_DATA: bool = BORROWED; - let function_layout = TopLevelFunctionLayout { + let function_layout = ProcLayout { arguments: arg_layouts, result: *ret_layout, }; @@ -687,7 +687,7 @@ impl<'a> Context<'a> { arg_layouts, .. } => { - let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout); + let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout); // get the borrow signature let ps = self @@ -976,8 +976,7 @@ impl<'a> Context<'a> { arg_layouts, .. } => { - let top_level = - TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout); + let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout); // get the borrow signature let ps = self @@ -1236,7 +1235,7 @@ pub fn visit_proc<'a>( arena: &'a Bump, param_map: &'a ParamMap<'a>, proc: &mut Proc<'a>, - layout: TopLevelFunctionLayout<'a>, + layout: ProcLayout<'a>, ) { let ctx = Context::new(arena, param_map); diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index c5a9ad2e14..9a91d5443e 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -3,8 +3,8 @@ use self::InProgressProc::*; use crate::exhaustive::{Ctor, Guard, RenderAs, TagId}; use crate::layout::{ - Builtin, ClosureRepresentation, LambdaSet, Layout, LayoutCache, LayoutProblem, UnionLayout, - WrappedVariant, TAG_SIZE, + Builtin, ClosureRepresentation, LambdaSet, Layout, LayoutCache, LayoutProblem, + RawFunctionLayout, UnionLayout, WrappedVariant, TAG_SIZE, }; use bumpalo::collections::Vec; use bumpalo::Bump; @@ -25,14 +25,22 @@ macro_rules! return_on_layout_error { ($env:expr, $layout_result:expr) => { match $layout_result { Ok(cached) => cached, - Err(LayoutProblem::UnresolvedTypeVar(_)) => { + Err(error) => return_on_layout_error_help!($env, error), + } + }; +} + +macro_rules! return_on_layout_error_help { + ($env:expr, $error:expr) => { + match $error { + LayoutProblem::UnresolvedTypeVar(_) => { return Stmt::RuntimeError($env.arena.alloc(format!( "UnresolvedTypeVar {} line {}", file!(), line!() ))); } - Err(LayoutProblem::Erroneous) => { + LayoutProblem::Erroneous => { return Stmt::RuntimeError($env.arena.alloc(format!( "Erroneous {} line {}", file!(), @@ -57,7 +65,7 @@ pub enum MonoProblem { #[derive(Debug, Clone, Copy)] pub struct EntryPoint<'a> { pub symbol: Symbol, - pub layout: TopLevelFunctionLayout<'a>, + pub layout: ProcLayout<'a>, } #[derive(Clone, Debug, PartialEq)] @@ -142,7 +150,7 @@ pub enum HostExposedLayouts<'a> { NotHostExposed, HostExposed { rigids: BumpMap>, - aliases: BumpMap, Layout<'a>)>, + aliases: BumpMap, RawFunctionLayout<'a>)>, }, } @@ -210,7 +218,7 @@ impl<'a> Proc<'a> { pub fn insert_refcount_operations( arena: &'a Bump, - procs: &mut MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>, + procs: &mut MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, ) { let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, procs)); @@ -299,8 +307,8 @@ pub struct Procs<'a> { pub imported_module_thunks: BumpSet, pub module_thunks: BumpSet, pub pending_specializations: - Option, PendingSpecialization<'a>>>>, - pub specialized: BumpMap<(Symbol, TopLevelFunctionLayout<'a>), InProgressProc<'a>>, + Option, PendingSpecialization<'a>>>>, + pub specialized: BumpMap<(Symbol, ProcLayout<'a>), InProgressProc<'a>>, pub runtime_errors: BumpMap, pub call_by_pointer_wrappers: BumpMap, pub externals_we_need: BumpMap>, @@ -331,7 +339,7 @@ impl<'a> Procs<'a> { pub fn get_specialized_procs_without_rc( self, arena: &'a Bump, - ) -> MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>> { + ) -> MutMap<(Symbol, ProcLayout<'a>), Proc<'a>> { let mut result = MutMap::with_capacity_and_hasher(self.specialized.len(), default_hasher()); let cloned = self.specialized.clone(); @@ -379,7 +387,7 @@ impl<'a> Procs<'a> { pub fn get_specialized_procs( self, arena: &'a Bump, - ) -> MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>> { + ) -> MutMap<(Symbol, ProcLayout<'a>), Proc<'a>> { let mut result = MutMap::with_capacity_and_hasher(self.specialized.len(), default_hasher()); for ((s, toplevel), in_prog_proc) in self.specialized.into_iter() { @@ -420,7 +428,7 @@ impl<'a> Procs<'a> { self, arena: &'a Bump, ) -> ( - MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>, + MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, &'a crate::borrow::ParamMap<'a>, ) { let mut result = MutMap::with_capacity_and_hasher(self.specialized.len(), default_hasher()); @@ -527,7 +535,7 @@ impl<'a> Procs<'a> { captured_symbols: CapturedSymbols<'a>, ret_var: Variable, layout_cache: &mut LayoutCache<'a>, - ) -> Result, RuntimeError> { + ) -> Result, RuntimeError> { // anonymous functions cannot reference themselves, therefore cannot be tail-recursive let is_self_recursive = false; @@ -535,7 +543,7 @@ impl<'a> Procs<'a> { .from_var(env.arena, annotation, env.subs) .unwrap_or_else(|err| panic!("TODO turn fn_var into a RuntimeError {:?}", err)); - let top_level = TopLevelFunctionLayout::from_layout(env.arena, layout); + let top_level = ProcLayout::from_layout(env.arena, layout); match patterns_to_when(env, layout_cache, loc_args, ret_var, loc_body) { Ok((_, pattern_symbols, body)) => { @@ -600,8 +608,7 @@ impl<'a> Procs<'a> { match specialize(env, self, symbol, layout_cache, pending, partial_proc) { Ok((proc, layout)) => { - let top_level = - TopLevelFunctionLayout::from_layout(env.arena, layout); + let top_level = ProcLayout::from_raw(env.arena, layout); debug_assert_eq!(outside_layout, top_level); @@ -629,7 +636,7 @@ impl<'a> Procs<'a> { pub fn insert_exposed( &mut self, name: Symbol, - layout: TopLevelFunctionLayout<'a>, + layout: ProcLayout<'a>, arena: &'a Bump, subs: &Subs, opt_annotation: Option, @@ -673,7 +680,7 @@ impl<'a> Procs<'a> { env: &mut Env<'a, '_>, fn_var: Variable, name: Symbol, - layout: TopLevelFunctionLayout<'a>, + layout: ProcLayout<'a>, layout_cache: &mut LayoutCache<'a>, ) { let tuple = (name, layout); @@ -737,10 +744,10 @@ impl<'a> Procs<'a> { fn add_pending<'a>( pending_specializations: &mut BumpMap< Symbol, - MutMap, PendingSpecialization<'a>>, + MutMap, PendingSpecialization<'a>>, >, symbol: Symbol, - layout: TopLevelFunctionLayout<'a>, + layout: ProcLayout<'a>, pending: PendingSpecialization<'a>, ) { let all_pending = pending_specializations @@ -950,9 +957,9 @@ pub enum ModifyRc { } impl ModifyRc { - pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D) -> DocBuilder<'b, D, A> + pub fn to_doc<'a, D, A>(self, alloc: &'a D) -> DocBuilder<'a, D, A> where - D: DocAllocator<'b, A>, + D: DocAllocator<'a, A>, D::Doc: Clone, A: Clone, { @@ -961,20 +968,20 @@ impl ModifyRc { match self { Inc(symbol, 1) => alloc .text("inc ") - .append(symbol_to_doc(alloc, *symbol)) + .append(symbol_to_doc(alloc, symbol)) .append(";"), Inc(symbol, n) => alloc .text("inc ") .append(alloc.text(format!("{}", n))) - .append(symbol_to_doc(alloc, *symbol)) + .append(symbol_to_doc(alloc, symbol)) .append(";"), Dec(symbol) => alloc .text("dec ") - .append(symbol_to_doc(alloc, *symbol)) + .append(symbol_to_doc(alloc, symbol)) .append(";"), DecRef(symbol) => alloc .text("decref ") - .append(symbol_to_doc(alloc, *symbol)) + .append(symbol_to_doc(alloc, symbol)) .append(";"), } } @@ -1784,10 +1791,15 @@ pub fn specialize_all<'a>( ) { Ok((proc, layout)) => { // TODO thiscode is duplicated elsewhere - let top_level = TopLevelFunctionLayout::from_layout(env.arena, layout); + let top_level = ProcLayout::from_raw(env.arena, layout); if procs.module_thunks.contains(&proc.name) { - debug_assert!(top_level.arguments.is_empty(), "{:?}", name); + debug_assert!( + top_level.arguments.is_empty(), + "{:?} from {:?}", + name, + layout + ); } debug_assert_eq!(outside_layout, top_level, " in {:?}", name); @@ -1798,8 +1810,8 @@ pub fn specialize_all<'a>( }) => { let proc = generate_runtime_error_function(env, name, attempted_layout); - let top_level = - TopLevelFunctionLayout::from_layout(env.arena, attempted_layout); + let top_level = ProcLayout::from_raw(env.arena, attempted_layout); + procs.specialized.insert((name, top_level), Done(proc)); } } @@ -1859,7 +1871,7 @@ fn specialize_all_help<'a>( partial_proc, ) { Ok((proc, layout)) => { - let top_level = TopLevelFunctionLayout::from_layout(env.arena, layout); + let top_level = ProcLayout::from_raw(env.arena, layout); if procs.module_thunks.contains(&name) { debug_assert!(top_level.arguments.is_empty()); @@ -1873,7 +1885,8 @@ fn specialize_all_help<'a>( }) => { let proc = generate_runtime_error_function(env, name, attempted_layout); - let top_level = TopLevelFunctionLayout::from_layout(env.arena, attempted_layout); + let top_level = ProcLayout::from_raw(env.arena, attempted_layout); + procs.specialized.insert((name, top_level), Done(proc)); } } @@ -1883,19 +1896,8 @@ fn specialize_all_help<'a>( fn generate_runtime_error_function<'a>( env: &mut Env<'a, '_>, name: Symbol, - layout: Layout<'a>, + layout: RawFunctionLayout<'a>, ) -> Proc<'a> { - let (arg_layouts, ret_layout) = match layout { - Layout::FunctionPointer(a, r) => (a, *r), - _ => (&[] as &[_], layout), - }; - - let mut args = Vec::with_capacity_in(arg_layouts.len(), env.arena); - - for arg in arg_layouts { - args.push((*arg, env.unique_symbol())); - } - let mut msg = bumpalo::collections::string::String::with_capacity_in(80, env.arena); use std::fmt::Write; write!( @@ -1909,9 +1911,24 @@ fn generate_runtime_error_function<'a>( let runtime_error = Stmt::RuntimeError(msg.into_bump_str()); + let (args, ret_layout) = match layout { + RawFunctionLayout::Function(arg_layouts, lambda_set, ret_layout) => { + let mut args = Vec::with_capacity_in(arg_layouts.len(), env.arena); + + for arg in arg_layouts { + args.push((*arg, env.unique_symbol())); + } + + args.push((lambda_set.runtime_representation(), Symbol::ARG_CLOSURE)); + + (args.into_bump_slice(), *ret_layout) + } + RawFunctionLayout::ZeroArgumentThunk(ret_layout) => (&[] as &[_], ret_layout), + }; + Proc { name, - args: args.into_bump_slice(), + args, body: runtime_error, closure_data_layout: None, ret_layout, @@ -1970,13 +1987,13 @@ fn specialize_external<'a>( for (symbol, variable) in host_exposed_variables { let layout = layout_cache - .from_var(env.arena, *variable, env.subs) + .raw_from_var(env.arena, *variable, env.subs) .unwrap(); let name = env.unique_symbol(); match layout { - Layout::Closure(argument_layouts, lambda_set, return_layout) => { + RawFunctionLayout::Function(argument_layouts, lambda_set, return_layout) => { let assigned = env.unique_symbol(); let unit = env.unique_symbol(); @@ -2008,10 +2025,11 @@ fn specialize_external<'a>( host_exposed_layouts: HostExposedLayouts::NotHostExposed, }; - let top_level = TopLevelFunctionLayout { - arguments: env.arena.alloc([lambda_set.runtime_representation()]), - result: *return_layout, - }; + let top_level = ProcLayout::new( + env.arena, + env.arena.alloc([lambda_set.runtime_representation()]), + *return_layout, + ); procs .specialized @@ -2019,7 +2037,7 @@ fn specialize_external<'a>( aliases.insert(*symbol, (name, top_level, layout)); } - _ => todo!(), + RawFunctionLayout::ZeroArgumentThunk(_) => unreachable!("so far"), } } @@ -2223,11 +2241,8 @@ fn build_specialized_proc_from_var<'a>( pattern_symbols: &[Symbol], fn_var: Variable, ) -> Result, LayoutProblem> { - match layout_cache.from_var(env.arena, fn_var, env.subs) { - Ok(Layout::FunctionPointer(_, _)) => { - unreachable!(r"layout generated by from_var should never by a function pointer") - } - Ok(Layout::Closure(pattern_layouts, closure_layout, ret_layout)) => { + match layout_cache.raw_from_var(env.arena, fn_var, env.subs)? { + RawFunctionLayout::Function(pattern_layouts, closure_layout, ret_layout) => { let mut pattern_layouts_vec = Vec::with_capacity_in(pattern_layouts.len(), env.arena); pattern_layouts_vec.extend_from_slice(pattern_layouts); @@ -2240,72 +2255,19 @@ fn build_specialized_proc_from_var<'a>( *ret_layout, ) } - _ => { - match env.subs.get_without_compacting(fn_var).content { - Content::Structure(FlatType::Func(pattern_vars, closure_var, ret_var)) => { - let closure_layout = LambdaSet::from_var(env.arena, env.subs, closure_var)?; - build_specialized_proc_adapter( - env, - layout_cache, - proc_name, - pattern_symbols, - &pattern_vars, - Some(closure_layout), - ret_var, - ) - } - Content::Alias(_, _, actual) => build_specialized_proc_from_var( - env, - layout_cache, - proc_name, - pattern_symbols, - actual, - ), - _ => { - // a top-level constant 0-argument thunk - build_specialized_proc_adapter( - env, - layout_cache, - proc_name, - pattern_symbols, - &[], - None, - fn_var, - ) - } - } + RawFunctionLayout::ZeroArgumentThunk(ret_layout) => { + // a top-level constant 0-argument thunk + build_specialized_proc( + env.arena, + proc_name, + pattern_symbols, + Vec::new_in(env.arena), + None, + ret_layout, + ) } } } -#[allow(clippy::type_complexity)] -fn build_specialized_proc_adapter<'a>( - env: &mut Env<'a, '_>, - layout_cache: &mut LayoutCache<'a>, - proc_name: Symbol, - pattern_symbols: &[Symbol], - pattern_vars: &[Variable], - closure_layout: Option>, - ret_var: Variable, -) -> Result, LayoutProblem> { - let mut arg_layouts = Vec::with_capacity_in(pattern_vars.len(), &env.arena); - - for arg_var in pattern_vars { - let layout = layout_cache.from_var(&env.arena, *arg_var, env.subs)?; - - arg_layouts.push(layout); - } - - let ret_layout = layout_cache.from_var(&env.arena, ret_var, env.subs)?; - - build_specialized_proc( - env.arena, - proc_name, - pattern_symbols, - arg_layouts, - closure_layout, - ret_layout, - ) -} #[allow(clippy::type_complexity)] fn build_specialized_proc<'a>( @@ -2450,11 +2412,13 @@ fn build_specialized_proc<'a>( #[derive(Debug)] struct SpecializeFailure<'a> { /// The layout we attempted to create - attempted_layout: Layout<'a>, + attempted_layout: RawFunctionLayout<'a>, /// The problem we ran into while creating it problem: LayoutProblem, } +type SpecializeSuccess<'a> = (Proc<'a>, RawFunctionLayout<'a>); + fn specialize<'a>( env: &mut Env<'a, '_>, procs: &mut Procs<'a>, @@ -2462,7 +2426,7 @@ fn specialize<'a>( layout_cache: &mut LayoutCache<'a>, pending: PendingSpecialization, partial_proc: PartialProc<'a>, -) -> Result<(Proc<'a>, Layout<'a>), SpecializeFailure<'a>> { +) -> Result, SpecializeFailure<'a>> { let PendingSpecialization { solved_type, host_exposed_aliases, @@ -2507,7 +2471,7 @@ fn specialize_solved_type<'a>( solved_type: SolvedType, host_exposed_aliases: BumpMap, partial_proc: PartialProc<'a>, -) -> Result<(Proc<'a>, Layout<'a>), SpecializeFailure<'a>> { +) -> Result, SpecializeFailure<'a>> { // add the specializations that other modules require of us use roc_solve::solve::instantiate_rigids; @@ -2516,10 +2480,22 @@ fn specialize_solved_type<'a>( let fn_var = introduce_solved_type_to_subs(env, &solved_type); + // for debugging only let attempted_layout = layout_cache .from_var(&env.arena, fn_var, env.subs) .unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err)); + let raw = match attempted_layout { + Layout::Closure(a, lambda_set, c) => { + if procs.module_thunks.contains(&proc_name) { + RawFunctionLayout::ZeroArgumentThunk(lambda_set.runtime_representation()) + } else { + RawFunctionLayout::Function(a, lambda_set, c) + } + } + _ => RawFunctionLayout::ZeroArgumentThunk(attempted_layout), + }; + // make sure rigid variables in the annotation are converted to flex variables instantiate_rigids(env.subs, partial_proc.annotation); @@ -2554,10 +2530,7 @@ fn specialize_solved_type<'a>( env.subs.rollback_to(snapshot); layout_cache.rollback_to(cache_snapshot); - Ok(( - proc, - cleanup_attempted_type(env, procs, proc_name, attempted_layout), - )) + Ok((proc, raw)) } Err(error) => { env.subs.rollback_to(snapshot); @@ -2565,32 +2538,19 @@ fn specialize_solved_type<'a>( Err(SpecializeFailure { problem: error, - attempted_layout: cleanup_attempted_type(env, procs, proc_name, attempted_layout), + attempted_layout: raw, }) } } } -fn cleanup_attempted_type<'a>( - env: &mut Env<'a, '_>, - procs: &mut Procs<'a>, - proc_name: Symbol, - layout: Layout<'a>, -) -> Layout<'a> { - if procs.module_thunks.contains(&proc_name) { - Layout::FunctionPointer(&[], env.arena.alloc(layout)) - } else { - layout - } -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct TopLevelFunctionLayout<'a> { +pub struct ProcLayout<'a> { pub arguments: &'a [Layout<'a>], pub result: Layout<'a>, } -impl<'a> TopLevelFunctionLayout<'a> { +impl<'a> ProcLayout<'a> { pub fn new(arena: &'a Bump, old_arguments: &'a [Layout<'a>], result: Layout<'a>) -> Self { let mut arguments = Vec::with_capacity_in(old_arguments.len(), arena); @@ -2604,26 +2564,38 @@ impl<'a> TopLevelFunctionLayout<'a> { } } - TopLevelFunctionLayout { + let new_result = match result { + Layout::Closure(_, lambda_set, _) => lambda_set.runtime_representation(), + other => other, + }; + + ProcLayout { arguments: arguments.into_bump_slice(), - result, + result: new_result, } } pub fn from_layout(arena: &'a Bump, layout: Layout<'a>) -> Self { match layout { - Layout::FunctionPointer(old_arguments, result) => { - Self::new(arena, old_arguments, *result) - } Layout::Closure(arguments, lambda_set, result) => { - let full = lambda_set.extend_function_layout(arena, arguments, result); - TopLevelFunctionLayout::from_layout(arena, full) + let arguments = lambda_set.extend_argument_list(arena, arguments); + ProcLayout::new(arena, arguments, *result) } - _ => TopLevelFunctionLayout { + _ => ProcLayout { arguments: &[], result: layout, }, } } + + fn from_raw(arena: &'a Bump, raw: RawFunctionLayout<'a>) -> Self { + match raw { + RawFunctionLayout::Function(arguments, lambda_set, result) => { + let arguments = lambda_set.extend_argument_list(arena, arguments); + ProcLayout::new(arena, arguments, *result) + } + RawFunctionLayout::ZeroArgumentThunk(result) => ProcLayout::new(arena, &[], result), + } + } } fn specialize_naked_symbol<'a>( @@ -2655,9 +2627,6 @@ fn specialize_naked_symbol<'a>( } else if env.is_imported_symbol(symbol) { match layout_cache.from_var(env.arena, variable, env.subs) { Err(e) => panic!("invalid layout {:?}", e), - Ok(Layout::FunctionPointer(_, _)) => { - unreachable!(r"layout generated by from_var should never by a function pointer") - } Ok(_) => { // this is a 0-arity thunk let result = call_by_name( @@ -2701,10 +2670,10 @@ macro_rules! match_on_closure_argument { ($env:expr, $procs:expr, $layout_cache:expr, $closure_data_symbol:expr, $closure_data_var:expr, $op:expr, [$($x:expr),* $(,)?], $layout: expr, $assigned:expr, $hole:expr) => {{ let closure_data_layout = return_on_layout_error!( $env, - $layout_cache.from_var($env.arena, $closure_data_var, $env.subs) + $layout_cache.raw_from_var($env.arena, $closure_data_var, $env.subs) ); - let top_level = TopLevelFunctionLayout::from_layout($env.arena, closure_data_layout); + let top_level = ProcLayout::from_raw($env.arena, closure_data_layout); let arena = $env.arena; @@ -2712,7 +2681,7 @@ macro_rules! match_on_closure_argument { let ret_layout = top_level.result; match closure_data_layout { - Layout::Closure(_, lambda_set, _) => { + RawFunctionLayout::Function(_, lambda_set, _) => { lowlevel_match_on_lambda_set( $env, lambda_set, @@ -2733,7 +2702,7 @@ macro_rules! match_on_closure_argument { $hole, ) } - _ => unreachable!(), + RawFunctionLayout::ZeroArgumentThunk(_) => unreachable!(), } }}; } @@ -3555,16 +3524,16 @@ pub fn with_hole<'a>( layout_cache, ) { Ok(_) => { - let full_layout = return_on_layout_error!( + let raw_layout = return_on_layout_error!( env, - layout_cache.from_var(env.arena, function_var, env.subs) + layout_cache.raw_from_var(env.arena, function_var, env.subs) ); - match full_layout { - Layout::Closure(_, lambda_set, _) => { + match raw_layout { + RawFunctionLayout::Function(_, lambda_set, _) => { construct_closure_data(env, lambda_set, name, &[], assigned, hole) } - _ => unreachable!(), + RawFunctionLayout::ZeroArgumentThunk(_) => unreachable!(), } } @@ -3694,9 +3663,13 @@ pub fn with_hole<'a>( } => { let loc_body = *boxed_body; - 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 raw = layout_cache.raw_from_var(env.arena, function_type, env.subs); + + match return_on_layout_error!(env, raw) { + RawFunctionLayout::ZeroArgumentThunk(_) => { + unreachable!("a closure syntactically always must have at least one argument") + } + RawFunctionLayout::Function(_argument_layouts, lambda_set, _ret_layout) => { let mut captured_symbols = Vec::from_iter_in(captured_symbols, env.arena); captured_symbols.sort(); let captured_symbols = captured_symbols.into_bump_slice(); @@ -3731,12 +3704,11 @@ pub fn with_hole<'a>( construct_closure_data(env, lambda_set, name, symbols, assigned, hole) } - Ok(_) => unreachable!(), } } Call(boxed, loc_args, _) => { - let (fn_var, loc_expr, _lambda_set_var, ret_var) = *boxed; + let (fn_var, loc_expr, _lambda_set_var, _ret_var) = *boxed; // even if a call looks like it's by name, it may in fact be by-pointer. // E.g. in `(\f, x -> f x)` the call is in fact by pointer. @@ -3792,16 +3764,6 @@ pub fn with_hole<'a>( layout_cache.raw_from_var(env.arena, fn_var, env.subs) ); - let arg_layouts = match full_layout { - Layout::Closure(args, _, _) => args, - _ => unreachable!("function has layout that is not function pointer"), - }; - - let ret_layout = return_on_layout_error!( - env, - layout_cache.from_var(env.arena, ret_var, env.subs) - ); - // if the function expression (loc_expr) is already a symbol, // re-use that symbol, and don't define its value again let mut result; @@ -3813,8 +3775,8 @@ pub fn with_hole<'a>( Imported(_) => { unreachable!("an imported value is never an anonymous function") } - Value(function_symbol) => { - if let Layout::Closure(_, lambda_set, _) = full_layout { + Value(function_symbol) => match full_layout { + RawFunctionLayout::Function(arg_layouts, lambda_set, ret_layout) => { let closure_data_symbol = function_symbol; result = match_on_lambda_set( @@ -3823,20 +3785,25 @@ pub fn with_hole<'a>( closure_data_symbol, arg_symbols, arg_layouts, - ret_layout, + *ret_layout, assigned, hole, ); - } else { + } + RawFunctionLayout::ZeroArgumentThunk(_) => { unreachable!("calling a non-closure layout") } - } + }, NotASymbol => { // the expression is not a symbol. That means it's an expression // evaluating to a function value. match full_layout { - Layout::Closure(_, lambda_set, _) => { + RawFunctionLayout::Function( + arg_layouts, + lambda_set, + ret_layout, + ) => { let closure_data_symbol = env.unique_symbol(); result = match_on_lambda_set( @@ -3845,7 +3812,7 @@ pub fn with_hole<'a>( closure_data_symbol, arg_symbols, arg_layouts, - ret_layout, + *ret_layout, assigned, hole, ); @@ -3860,8 +3827,11 @@ pub fn with_hole<'a>( env.arena.alloc(result), ); } - _ => { - todo!("{:?}", full_layout) + RawFunctionLayout::ZeroArgumentThunk(_) => { + unreachable!( + "{:?} cannot be called in the source language", + full_layout + ) } } } @@ -4479,14 +4449,16 @@ fn tag_union_to_function<'a>( match inserted { Ok(_layout) => { // only need to construct closure data - let full_layout = - return_on_layout_error!(env, layout_cache.from_var(env.arena, whole_var, env.subs)); + let raw_layout = return_on_layout_error!( + env, + layout_cache.raw_from_var(env.arena, whole_var, env.subs) + ); - match full_layout { - Layout::Closure(_, lambda_set, _) => { + match raw_layout { + RawFunctionLayout::Function(_, lambda_set, _) => { construct_closure_data(env, lambda_set, proc_symbol, &[], assigned, hole) } - _ => unreachable!(), + RawFunctionLayout::ZeroArgumentThunk(_) => unreachable!(), } } @@ -4730,28 +4702,36 @@ pub fn from_can<'a>( // does this function capture any local values? let function_layout = - layout_cache.from_var(env.arena, function_type, env.subs); + layout_cache.raw_from_var(env.arena, function_type, env.subs); - let captured_symbols = if let Ok(Layout::Closure(_, lambda_set, _)) = - &function_layout - { - if let Layout::Struct(&[]) = lambda_set.runtime_representation() { - CapturedSymbols::None - } else { - let mut temp = Vec::from_iter_in(captured_symbols, env.arena); - temp.sort(); - CapturedSymbols::Captured(temp.into_bump_slice()) + let captured_symbols = match function_layout { + Ok(RawFunctionLayout::Function(_, lambda_set, _)) => { + if let Layout::Struct(&[]) = lambda_set.runtime_representation() + { + CapturedSymbols::None + } else { + let mut temp = + Vec::from_iter_in(captured_symbols, env.arena); + temp.sort(); + CapturedSymbols::Captured(temp.into_bump_slice()) + } + } + Ok(RawFunctionLayout::ZeroArgumentThunk(_)) => { + // top-level thunks cannot capture any variables + debug_assert!( + captured_symbols.is_empty(), + "{:?} with layout {:?} {:?} {:?}", + &captured_symbols, + function_layout, + env.subs, + (function_type, closure_type, closure_ext_var), + ); + CapturedSymbols::None + } + Err(_) => { + debug_assert!(captured_symbols.is_empty()); + CapturedSymbols::None } - } else { - debug_assert!( - captured_symbols.is_empty(), - "{:?} with layout {:?} {:?} {:?}", - &captured_symbols, - function_layout, - env.subs, - (function_type, closure_type, closure_ext_var), - ); - CapturedSymbols::None }; procs.insert_named( @@ -5887,7 +5867,7 @@ fn reuse_function_symbol<'a>( .expect("creating layout does not fail"); if procs.imported_module_thunks.contains(&original) { - let top_level = TopLevelFunctionLayout::new(env.arena, &[], layout); + let top_level = ProcLayout::new(env.arena, &[], layout); procs.insert_passed_by_name( env, arg_var, @@ -5898,7 +5878,7 @@ fn reuse_function_symbol<'a>( force_thunk(env, original, layout, symbol, env.arena.alloc(result)) } else { - let top_level = TopLevelFunctionLayout::from_layout(env.arena, layout); + let top_level = ProcLayout::from_layout(env.arena, layout); procs.insert_passed_by_name( env, arg_var, @@ -5929,7 +5909,10 @@ fn reuse_function_symbol<'a>( // this symbol is a function, that is used by-name (e.g. as an argument to another // function). Register it with the current variable, then create a function pointer // to it in the IR. - let res_layout = layout_cache.from_var(env.arena, arg_var, env.subs); + let res_layout = return_on_layout_error!( + env, + layout_cache.raw_from_var(env.arena, arg_var, env.subs) + ); // we have three kinds of functions really. Plain functions, closures by capture, // and closures by unification. Here we record whether this function captures @@ -5938,10 +5921,9 @@ fn reuse_function_symbol<'a>( let captured = partial_proc.captured_symbols.clone(); match res_layout { - Ok(Layout::Closure(argument_layouts, lambda_set, ret_layout)) => { + RawFunctionLayout::Function(argument_layouts, lambda_set, ret_layout) => { // define the function pointer - let function_ptr_layout = - TopLevelFunctionLayout::from_layout(env.arena, res_layout.unwrap()); + let function_ptr_layout = ProcLayout::from_raw(env.arena, res_layout); if captures { // this is a closure by capture, meaning it itself captures local variables. @@ -5974,7 +5956,7 @@ fn reuse_function_symbol<'a>( } else if procs.module_thunks.contains(&original) { // this is a 0-argument thunk let layout = Layout::Closure(argument_layouts, lambda_set, ret_layout); - let top_level = TopLevelFunctionLayout::new(env.arena, &[], layout); + let top_level = ProcLayout::new(env.arena, &[], layout); procs.insert_passed_by_name( env, arg_var, @@ -5998,23 +5980,12 @@ fn reuse_function_symbol<'a>( return let_empty_struct(symbol, env.arena.alloc(result)); } } - Ok(layout) => { + RawFunctionLayout::ZeroArgumentThunk(ret_layout) => { // this is a 0-argument thunk - let top_level = TopLevelFunctionLayout::new(env.arena, &[], layout); + let top_level = ProcLayout::new(env.arena, &[], ret_layout); procs.insert_passed_by_name(env, arg_var, original, top_level, layout_cache); - force_thunk(env, original, layout, symbol, env.arena.alloc(result)) - } - Err(LayoutProblem::Erroneous) => { - let message = format!("The {:?} symbol has an erroneous type", symbol); - Stmt::RuntimeError(env.arena.alloc(message)) - } - Err(LayoutProblem::UnresolvedTypeVar(v)) => { - let message = format!( - "The {:?} symbol contains a unresolved type var {:?}", - symbol, v - ); - Stmt::RuntimeError(env.arena.alloc(message)) + force_thunk(env, original, ret_layout, symbol, env.arena.alloc(result)) } } } @@ -6141,7 +6112,7 @@ fn build_call<'a>( env: &mut Env<'a, '_>, call: Call<'a>, assigned: Symbol, - layout: Layout<'a>, + return_layout: Layout<'a>, hole: &'a Stmt<'a>, ) -> Stmt<'a> { if can_throw_exception(&call) { @@ -6150,13 +6121,13 @@ fn build_call<'a>( Stmt::Invoke { symbol: assigned, call, - layout, + layout: return_layout, fail, pass: hole, exception_id: id, } } else { - Stmt::Let(assigned, Expr::Call(call), layout, hole) + Stmt::Let(assigned, Expr::Call(call), return_layout, hole) } } @@ -6172,7 +6143,7 @@ fn call_by_name<'a>( hole: &'a Stmt<'a>, ) -> Stmt<'a> { // Register a pending_specialization for this function - match layout_cache.from_var(env.arena, fn_var, env.subs) { + match layout_cache.raw_from_var(env.arena, fn_var, env.subs) { Err(LayoutProblem::UnresolvedTypeVar(var)) => { let msg = format!( "Hit an unresolved type variable {:?} when creating a layout for {:?} (var {:?})", @@ -6187,110 +6158,105 @@ fn call_by_name<'a>( ); Stmt::RuntimeError(env.arena.alloc(msg)) } - Ok(layout) if procs.module_thunks.contains(&proc_name) => { - // here we turn a call to a module thunk into forcing of that thunk - if loc_args.is_empty() { - call_by_name_module_thunk( - env, - procs, - fn_var, - proc_name, - env.arena.alloc(layout), - layout_cache, - assigned, - hole, - ) - } else if let Layout::Closure(arg_layouts, lambda_set, ret_layout) = layout { - // here we turn a call to a module thunk into forcing of that thunk - // the thunk represents the closure environment for the body, so we then match - // on the closure environment to perform the call that the body represents. - // - // Example: - // - // > main = parseA "foo" "bar" - // > parseA = Str.concat + Ok(RawFunctionLayout::Function(arg_layouts, lambda_set, ret_layout)) => { + if procs.module_thunks.contains(&proc_name) { + if loc_args.is_empty() { + call_by_name_module_thunk( + env, + procs, + fn_var, + proc_name, + env.arena.alloc(lambda_set.runtime_representation()), + layout_cache, + assigned, + hole, + ) + } else { + // here we turn a call to a module thunk into forcing of that thunk + // the thunk represents the closure environment for the body, so we then match + // on the closure environment to perform the call that the body represents. + // + // Example: + // + // > main = parseA "foo" "bar" + // > parseA = Str.concat - let closure_data_symbol = env.unique_symbol(); + let closure_data_symbol = env.unique_symbol(); - let arena = env.arena; - let arg_symbols = Vec::from_iter_in( - loc_args - .iter() - .map(|(_, arg_expr)| possible_reuse_symbol(env, procs, &arg_expr.value)), - arena, - ) - .into_bump_slice(); + let arena = env.arena; + let arg_symbols = Vec::from_iter_in( + loc_args.iter().map(|(_, arg_expr)| { + possible_reuse_symbol(env, procs, &arg_expr.value) + }), + arena, + ) + .into_bump_slice(); - let result = match_on_lambda_set( - env, - lambda_set, - closure_data_symbol, - arg_symbols, - arg_layouts, - *ret_layout, - assigned, - hole, - ); + debug_assert_eq!(arg_symbols.len(), arg_layouts.len()); - let result = call_by_name_module_thunk( - env, - procs, - fn_var, - proc_name, - env.arena.alloc(layout), - layout_cache, - closure_data_symbol, - env.arena.alloc(result), - ); + let result = match_on_lambda_set( + env, + lambda_set, + closure_data_symbol, + arg_symbols, + arg_layouts, + *ret_layout, + assigned, + hole, + ); - let iter = loc_args.into_iter().rev().zip(arg_symbols.iter().rev()); - assign_to_symbols(env, procs, layout_cache, iter, result) + let result = call_by_name_module_thunk( + env, + procs, + fn_var, + proc_name, + env.arena.alloc(lambda_set.runtime_representation()), + layout_cache, + closure_data_symbol, + env.arena.alloc(result), + ); + + let iter = loc_args.into_iter().rev().zip(arg_symbols.iter().rev()); + assign_to_symbols(env, procs, layout_cache, iter, result) + } } else { - unreachable!("calling a non-closure layout") - } - } - Ok(Layout::FunctionPointer(argument_layouts, ret_layout)) => call_by_name_help( - env, - procs, - fn_var, - proc_name, - loc_args, - Layout::FunctionPointer(argument_layouts, ret_layout), - argument_layouts, - ret_layout, - layout_cache, - assigned, - hole, - ), - Ok(Layout::Closure(c_argument_layouts, lambda_set, c_ret_layout)) => { - match lambda_set.extend_function_layout(env.arena, c_argument_layouts, c_ret_layout) { - Layout::FunctionPointer(argument_layouts, ret_layout) => call_by_name_help( + let argument_layouts = lambda_set.extend_argument_list(env.arena, arg_layouts); + + call_by_name_help( env, procs, fn_var, proc_name, loc_args, - Layout::Closure(c_argument_layouts, lambda_set, c_ret_layout), + lambda_set, argument_layouts, ret_layout, layout_cache, assigned, hole, - ), - _ => unreachable!(), + ) } } - Ok(other) if loc_args.is_empty() => { - // this is a 0-argument thunk - if env.is_imported_symbol(proc_name) { + Ok(RawFunctionLayout::ZeroArgumentThunk(ret_layout)) => { + if procs.module_thunks.contains(&proc_name) { + // here we turn a call to a module thunk into forcing of that thunk + call_by_name_module_thunk( + env, + procs, + fn_var, + proc_name, + env.arena.alloc(ret_layout), + layout_cache, + assigned, + hole, + ) + } else if env.is_imported_symbol(proc_name) { add_needed_external(procs, env, fn_var, proc_name); + force_thunk(env, proc_name, ret_layout, assigned, hole) + } else { + panic!("most likely we're trying to call something that is not a function"); } - force_thunk(env, proc_name, other, assigned, hole) } - other => panic!( - "calling {:?}, which is not a function but received arguments, and is a {:?}", - proc_name, other, - ), } } @@ -6301,7 +6267,7 @@ fn call_by_name_help<'a>( fn_var: Variable, proc_name: Symbol, loc_args: std::vec::Vec<(Variable, Located)>, - maybe_closure_layout: Layout<'a>, + lambda_set: LambdaSet<'a>, argument_layouts: &'a [Layout<'a>], ret_layout: &'a Layout<'a>, layout_cache: &mut LayoutCache<'a>, @@ -6313,7 +6279,7 @@ 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 top_level_layout = ProcLayout::new(env.arena, argument_layouts, *ret_layout); // the arguments given to the function, stored in symbols let field_symbols = Vec::from_iter_in( @@ -6370,7 +6336,13 @@ fn call_by_name_help<'a>( debug_assert_ne!(proc_name.module_id(), ModuleId::ATTR); if procs.imported_module_thunks.contains(&proc_name) { - force_thunk(env, proc_name, maybe_closure_layout, assigned, hole) + force_thunk( + env, + proc_name, + lambda_set.runtime_representation(), + assigned, + hole, + ) } else { debug_assert!( !field_symbols.is_empty(), @@ -6467,28 +6439,18 @@ fn call_by_name_help<'a>( match specialize(env, procs, proc_name, layout_cache, pending, partial_proc) { - Ok((proc, layout)) => { - // NOTE we cannot make the below assertion any more; figure out why - - debug_assert_eq!( - &maybe_closure_layout, &layout, - "\nProcedure {:?}\n\n{:?}\n\n{:?}", - proc_name, maybe_closure_layout, layout - ); - - call_specialized_proc( - env, - procs, - proc_name, - proc, - layout, - field_symbols, - loc_args, - layout_cache, - assigned, - hole, - ) - } + Ok((proc, layout)) => call_specialized_proc( + env, + procs, + proc_name, + proc, + layout, + field_symbols, + loc_args, + layout_cache, + assigned, + hole, + ), Err(SpecializeFailure { attempted_layout, problem: _, @@ -6539,14 +6501,10 @@ fn call_by_name_module_thunk<'a>( // debug_assert!(!procs.module_thunks.contains(&proc_name), "{:?}", proc_name); - let top_level_layout = TopLevelFunctionLayout::new(env.arena, &[], *ret_layout); + let top_level_layout = ProcLayout::new(env.arena, &[], *ret_layout); - // the layout without the `FunctionPointer(&[], ...)` wrapper let inner_layout = *ret_layout; - // the layout with the wrapper - let module_thunk_layout = Layout::FunctionPointer(&[], ret_layout); - // If we've already specialized this one, no further work is needed. if procs .specialized @@ -6603,8 +6561,7 @@ fn call_by_name_module_thunk<'a>( match specialize(env, procs, proc_name, layout_cache, pending, partial_proc) { Ok((proc, layout)) => { - // NOTE we cannot make the below assertion any more; figure out why - debug_assert_eq!(layout, module_thunk_layout); + debug_assert!(layout.is_zero_argument_thunk()); let was_present = procs.specialized.remove(&(proc_name, top_level_layout)); @@ -6620,12 +6577,10 @@ fn call_by_name_module_thunk<'a>( attempted_layout, problem: _, }) => { - debug_assert_eq!(attempted_layout, module_thunk_layout); - let proc = generate_runtime_error_function( env, proc_name, - module_thunk_layout, + attempted_layout, ); let was_present = @@ -6656,22 +6611,20 @@ fn call_specialized_proc<'a>( procs: &mut Procs<'a>, proc_name: Symbol, proc: Proc<'a>, - layout: Layout<'a>, + layout: RawFunctionLayout<'a>, field_symbols: &'a [Symbol], loc_args: std::vec::Vec<(Variable, Located)>, layout_cache: &mut LayoutCache<'a>, assigned: Symbol, hole: &'a Stmt<'a>, ) -> Stmt<'a> { - let function_layout = env - .arena - .alloc(TopLevelFunctionLayout::from_layout(env.arena, layout)); + let function_layout = ProcLayout::from_raw(env.arena, layout); - procs.specialized.remove(&(proc_name, *function_layout)); + procs.specialized.remove(&(proc_name, function_layout)); procs .specialized - .insert((proc_name, *function_layout), Done(proc)); + .insert((proc_name, function_layout), Done(proc)); if field_symbols.is_empty() { debug_assert!(loc_args.is_empty()); @@ -6684,7 +6637,8 @@ fn call_specialized_proc<'a>( // there are no arguments. This confuses our IR, // and we have to fix it here. match layout { - Layout::Closure(_, closure_layout, _) => { + RawFunctionLayout::Function(_, lambda_set, _) => { + // when the body is a closure, the function will return the closure environment let call = self::Call { call_type: CallType::ByName { name: proc_name, @@ -6699,22 +6653,12 @@ fn call_specialized_proc<'a>( env, call, assigned, - closure_layout.runtime_representation(), + lambda_set.runtime_representation(), hole, ) } - _ => { - let call = self::Call { - call_type: CallType::ByName { - name: proc_name, - ret_layout: function_layout.result, - arg_layouts: function_layout.arguments, - specialization_id: env.next_call_specialization_id(), - }, - arguments: field_symbols, - }; - - build_call(env, call, assigned, function_layout.result, hole) + RawFunctionLayout::ZeroArgumentThunk(_) => { + unreachable!() } } } else { diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 953f41ff71..582fcec6c9 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -20,19 +20,24 @@ impl Layout<'_> { pub const TAG_SIZE: Layout<'static> = Layout::Builtin(Builtin::Int64); } -#[derive(Copy, Clone)] -#[repr(u8)] -pub enum InPlace { - InPlace, - Clone, -} - #[derive(Debug, Clone)] pub enum LayoutProblem { UnresolvedTypeVar(Variable), Erroneous, } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum RawFunctionLayout<'a> { + Function(&'a [Layout<'a>], LambdaSet<'a>, &'a Layout<'a>), + ZeroArgumentThunk(Layout<'a>), +} + +impl RawFunctionLayout<'_> { + pub fn is_zero_argument_thunk(&self) -> bool { + matches!(self, RawFunctionLayout::ZeroArgumentThunk(_)) + } +} + /// Types for code gen must be monomorphic. No type variables allowed! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Layout<'a> { @@ -45,23 +50,9 @@ pub enum Layout<'a> { RecursivePointer, /// A function. The types of its arguments, then the type of its return value. - FunctionPointer(&'a [Layout<'a>], &'a Layout<'a>), Closure(&'a [Layout<'a>], LambdaSet<'a>, &'a Layout<'a>), } -impl<'a> Layout<'a> { - pub fn in_place(&self) -> InPlace { - match self { - Layout::Builtin(Builtin::EmptyList) => InPlace::InPlace, - Layout::Builtin(Builtin::List(_)) => InPlace::Clone, - Layout::Builtin(Builtin::EmptyStr) => InPlace::InPlace, - Layout::Builtin(Builtin::Str) => InPlace::Clone, - Layout::Builtin(Builtin::Int1) => InPlace::Clone, - _ => unreachable!("Layout {:?} does not have an inplace", self), - } - } -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum UnionLayout<'a> { /// A non-recursive tag union @@ -89,9 +80,9 @@ pub enum UnionLayout<'a> { } impl<'a> UnionLayout<'a> { - pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, _parens: Parens) -> DocBuilder<'b, D, A> + pub fn to_doc(self, alloc: &'a D, _parens: Parens) -> DocBuilder<'a, D, A> where - D: DocAllocator<'b, A>, + D: DocAllocator<'a, A>, D::Doc: Clone, A: Clone, { @@ -192,32 +183,31 @@ impl<'a> LambdaSet<'a> { } } - pub fn extend_function_layout( + pub fn extend_argument_list( &self, arena: &'a Bump, argument_layouts: &'a [Layout<'a>], - ret_layout: &'a Layout<'a>, - ) -> Layout<'a> { + ) -> &'a [Layout<'a>] { if let [] = self.set { // TERRIBLE HACK for builting functions - Layout::FunctionPointer(argument_layouts, ret_layout) + argument_layouts } else { match self.representation { Layout::Struct(&[]) => { // this function does not have anything in its closure, and the lambda set is a // singleton, so we pass no extra argument - Layout::FunctionPointer(argument_layouts, ret_layout) + argument_layouts } Layout::Builtin(Builtin::Int1) | Layout::Builtin(Builtin::Int8) => { // we don't pass this along either - Layout::FunctionPointer(argument_layouts, ret_layout) + argument_layouts } _ => { let mut arguments = Vec::with_capacity_in(argument_layouts.len() + 1, arena); arguments.extend(argument_layouts); arguments.push(self.runtime_representation()); - Layout::FunctionPointer(arguments.into_bump_slice(), ret_layout) + arguments.into_bump_slice() } } } @@ -503,10 +493,6 @@ impl<'a> Layout<'a> { } } } - FunctionPointer(_, _) => { - // Function pointers are immutable and can always be safely copied - true - } Closure(_, closure_layout, _) => closure_layout.safe_to_memcpy(), RecursivePointer => { // We cannot memcpy pointers, because then we would have the same pointer in multiple places! @@ -558,7 +544,6 @@ impl<'a> Layout<'a> { } } Closure(_, lambda_set, _) => lambda_set.stack_size(pointer_size), - FunctionPointer(_, _) => pointer_size, RecursivePointer => pointer_size, } } @@ -590,7 +575,6 @@ impl<'a> Layout<'a> { } Layout::Builtin(builtin) => builtin.alignment_bytes(pointer_size), Layout::RecursivePointer => pointer_size, - Layout::FunctionPointer(_, _) => pointer_size, Layout::Closure(_, captured, _) => { pointer_size.max(captured.alignment_bytes(pointer_size)) } @@ -645,13 +629,12 @@ impl<'a> Layout<'a> { } RecursivePointer => true, Closure(_, closure_layout, _) => closure_layout.contains_refcounted(), - FunctionPointer(_, _) => false, } } - pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, parens: Parens) -> DocBuilder<'b, D, A> + pub fn to_doc(self, alloc: &'a D, parens: Parens) -> DocBuilder<'a, D, A> where - D: DocAllocator<'b, A>, + D: DocAllocator<'a, A>, D::Doc: Clone, A: Clone, { @@ -669,14 +652,6 @@ impl<'a> Layout<'a> { } Union(union_layout) => union_layout.to_doc(alloc, parens), RecursivePointer => alloc.text("*self"), - FunctionPointer(args, result) => { - let args_doc = args.iter().map(|x| x.to_doc(alloc, Parens::InFunction)); - - alloc - .intersperse(args_doc, ", ") - .append(alloc.text(" -> ")) - .append(result.to_doc(alloc, Parens::InFunction)) - } Closure(args, closure_layout, result) => { let args_doc = args.iter().map(|x| x.to_doc(alloc, Parens::InFunction)); @@ -725,8 +700,6 @@ impl<'a> CachedVariable<'a> { } } -// use ven_ena::unify::{InPlace, Snapshot, UnificationTable, UnifyKey}; - impl<'a> ven_ena::unify::UnifyKey for CachedVariable<'a> { type Value = CachedLayout<'a>; @@ -796,7 +769,7 @@ impl<'a> LayoutCache<'a> { arena: &'a Bump, var: Variable, subs: &Subs, - ) -> Result, LayoutProblem> { + ) -> Result, LayoutProblem> { // Store things according to the root Variable, to avoid duplicate work. let var = subs.get_root_key_without_compacting(var); @@ -806,31 +779,18 @@ impl<'a> LayoutCache<'a> { use CachedLayout::*; match self.layouts.probe_value(cached_var) { - Cached(result) => Ok(result), Problem(problem) => Err(problem), - NotCached => { + Cached(_) | 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 + Layout::from_var(&mut env, var).map(|l| match l { + Layout::Closure(a, b, c) => RawFunctionLayout::Function(a, b, c), + other => RawFunctionLayout::ZeroArgumentThunk(other), + }) } } } @@ -959,9 +919,9 @@ impl<'a> Builtin<'a> { } } - pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, _parens: Parens) -> DocBuilder<'b, D, A> + pub fn to_doc(self, alloc: &'a D, _parens: Parens) -> DocBuilder<'a, D, A> where - D: DocAllocator<'b, A>, + D: DocAllocator<'a, A>, D::Doc: Clone, A: Clone, { @@ -1953,7 +1913,7 @@ impl LayoutId { struct IdsByLayout<'a> { by_id: MutMap, u32>, - toplevels_by_id: MutMap, u32>, + toplevels_by_id: MutMap, u32>, next_id: u32, } @@ -1993,7 +1953,7 @@ impl<'a> LayoutIds<'a> { pub fn get_toplevel<'b>( &mut self, symbol: Symbol, - layout: &'b crate::ir::TopLevelFunctionLayout<'a>, + layout: &'b crate::ir::ProcLayout<'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. diff --git a/compiler/test_mono/src/lib.rs b/compiler/test_mono/src/lib.rs index efe0f54ecb..222dda0c5d 100644 --- a/compiler/test_mono/src/lib.rs +++ b/compiler/test_mono/src/lib.rs @@ -23,7 +23,7 @@ use roc_collections::all::MutMap; use roc_module::symbol::Symbol; use roc_mono::ir::Proc; -use roc_mono::ir::TopLevelFunctionLayout; +use roc_mono::ir::ProcLayout; /// Without this, some tests pass in `cargo test --release` but fail without /// the --release flag because they run out of stack space. This increases @@ -146,7 +146,7 @@ fn compiles_to_ir(test_name: &str, src: &str) { #[cfg(debug_assertions)] fn verify_procedures( test_name: &str, - procedures: MutMap<(Symbol, TopLevelFunctionLayout<'_>), Proc<'_>>, + procedures: MutMap<(Symbol, ProcLayout<'_>), Proc<'_>>, main_fn_symbol: Symbol, ) { let index = procedures @@ -205,7 +205,7 @@ fn verify_procedures( #[cfg(not(debug_assertions))] fn verify_procedures( _expected: &str, - _procedures: MutMap<(Symbol, TopLevelFunctionLayout<'_>), Proc<'_>>, + _procedures: MutMap<(Symbol, ProcLayout<'_>), Proc<'_>>, _main_fn_symbol: Symbol, ) { // Do nothing