diff --git a/compiler/builtins/docs/Defaults.roc b/compiler/builtins/docs/Defaults.roc index 611ef249a1..046ba7dc3f 100644 --- a/compiler/builtins/docs/Defaults.roc +++ b/compiler/builtins/docs/Defaults.roc @@ -1,7 +1,7 @@ interface Defaults exposes [] imports [ - Map.{ Map }, + Dict.{ Dict }, Set.{ Set }, Num.{ Num, Int, Float } ] diff --git a/compiler/builtins/docs/Map.roc b/compiler/builtins/docs/Dict.roc similarity index 56% rename from compiler/builtins/docs/Map.roc rename to compiler/builtins/docs/Dict.roc index 0a25daae4d..36056e81e5 100644 --- a/compiler/builtins/docs/Map.roc +++ b/compiler/builtins/docs/Dict.roc @@ -1,15 +1,15 @@ -interface Map2 +interface Dict2 exposes [ isEmpty, map ] imports [] -isEmpty : Map * * -> Bool +isEmpty : Dict * * -> Bool -## Convert each key and value in the #Map to something new, by calling a conversion +## Convert each key and value in the #Dict to something new, by calling a conversion ## function on each of them. Then return a new #Map of the converted keys and values. ## -## >>> Map.map {{ 3.14 => "pi", 1.0 => "one" }} \{ key, value } -> { key: +## >>> Dict.map {{ 3.14 => "pi", 1.0 => "one" }} \{ key, value } -> { key: ## -## >>> Map.map {[ "", "a", "bc" ]} Str.isEmpty +## >>> Dict.map {[ "", "a", "bc" ]} Str.isEmpty ## ## `map` functions like this are common in Roc, and they all work similarly. ## See for example #Result.map, #List.map, and #Set.map. diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 120e78dc58..97e8b2581a 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -3,7 +3,7 @@ use roc_module::ident::TagName; use roc_module::symbol::Symbol; use roc_region::all::Region; use roc_types::builtin_aliases::{ - bool_type, float_type, int_type, list_type, map_type, num_type, ordering_type, result_type, + bool_type, dict_type, float_type, int_type, list_type, num_type, ordering_type, result_type, set_type, str_type, }; use roc_types::solved_types::SolvedType; @@ -30,7 +30,7 @@ pub fn standard_stdlib() -> StdLib { applies: vec![ Symbol::LIST_LIST, Symbol::SET_SET, - Symbol::MAP_MAP, + Symbol::DICT_DICT, Symbol::STR_STR, ] .into_iter() @@ -614,39 +614,43 @@ pub fn types() -> MutMap { top_level_function(vec![list_type(flex(TVAR1))], Box::new(bool_type())), ); - // Map module + // Dict module - // empty : Map k v - add_type(Symbol::MAP_EMPTY, map_type(flex(TVAR1), flex(TVAR2))); + // empty : Dict k v + add_type(Symbol::DICT_EMPTY, dict_type(flex(TVAR1), flex(TVAR2))); - // singleton : k, v -> Map k v + // singleton : k, v -> Dict k v add_type( - Symbol::MAP_SINGLETON, + Symbol::DICT_SINGLETON, top_level_function( vec![flex(TVAR1), flex(TVAR2)], - Box::new(map_type(flex(TVAR1), flex(TVAR2))), + Box::new(dict_type(flex(TVAR1), flex(TVAR2))), ), ); - // get : Map k v, k -> Result v [ KeyNotFound ]* + // get : Dict k v, k -> Result v [ KeyNotFound ]* let key_not_found = SolvedType::TagUnion( vec![(TagName::Global("KeyNotFound".into()), vec![])], Box::new(SolvedType::Wildcard), ); add_type( - Symbol::MAP_GET, + Symbol::DICT_GET, top_level_function( - vec![map_type(flex(TVAR1), flex(TVAR2)), flex(TVAR1)], + vec![dict_type(flex(TVAR1), flex(TVAR2)), flex(TVAR1)], Box::new(result_type(flex(TVAR2), key_not_found)), ), ); add_type( - Symbol::MAP_INSERT, + Symbol::DICT_INSERT, top_level_function( - vec![map_type(flex(TVAR1), flex(TVAR2)), flex(TVAR1), flex(TVAR2)], - Box::new(map_type(flex(TVAR1), flex(TVAR2))), + vec![ + dict_type(flex(TVAR1), flex(TVAR2)), + flex(TVAR1), + flex(TVAR2), + ], + Box::new(dict_type(flex(TVAR1), flex(TVAR2))), ), ); diff --git a/compiler/builtins/src/unique.rs b/compiler/builtins/src/unique.rs index 43cddc7461..b608f699b7 100644 --- a/compiler/builtins/src/unique.rs +++ b/compiler/builtins/src/unique.rs @@ -107,7 +107,7 @@ pub fn uniq_stdlib() -> StdLib { Symbol::ATTR_ATTR, Symbol::LIST_LIST, Symbol::SET_SET, - Symbol::MAP_MAP, + Symbol::DICT_DICT, Symbol::STR_STR, ] .into_iter() @@ -831,18 +831,18 @@ pub fn types() -> MutMap { ) }); - // Map module + // Dict module - // empty : Attr * (Map k v) - add_type(Symbol::MAP_EMPTY, { + // empty : Attr * (Dict k v) + add_type(Symbol::DICT_EMPTY, { let_tvars! { star, k , v }; - map_type(star, k, v) + dict_type(star, k, v) }); - // singleton : k, v -> Attr * (Map k v) - add_type(Symbol::MAP_SINGLETON, { + // singleton : k, v -> Attr * (Dict k v) + add_type(Symbol::DICT_SINGLETON, { let_tvars! { star, k , v }; - unique_function(vec![flex(k), flex(v)], map_type(star, k, v)) + unique_function(vec![flex(k), flex(v)], dict_type(star, k, v)) }); let key_not_found = SolvedType::Apply( @@ -856,10 +856,10 @@ pub fn types() -> MutMap { ], ); - // get : Attr (* | u) (Map (Attr * key) (Attr u val)) + // get : Attr (* | u) (Dict (Attr * key) (Attr u val)) // , Attr * key // -> Attr * (Result (Attr u val) [ KeyNotFound ]*) - add_type(Symbol::MAP_GET, { + add_type(Symbol::DICT_GET, { let_tvars! { u, key, val, star1, star2, star3, star4 }; unique_function( @@ -869,7 +869,7 @@ pub fn types() -> MutMap { vec![ container(star1, vec![u]), SolvedType::Apply( - Symbol::MAP_MAP, + Symbol::DICT_DICT, vec![attr_type(star2, key), attr_type(u, val)], ), ], @@ -889,11 +889,11 @@ pub fn types() -> MutMap { ) }); - // insert : Attr * (Map key value) + // insert : Attr * (Dict key value) // , key // , value - // , Attr * (Map key value) - add_type(Symbol::MAP_INSERT, { + // , Attr * (Dict key value) + add_type(Symbol::DICT_INSERT, { let_tvars! { star1, star2, key, value }; unique_function( @@ -902,7 +902,7 @@ pub fn types() -> MutMap { Symbol::ATTR_ATTR, vec![ flex(star1), - SolvedType::Apply(Symbol::MAP_MAP, vec![flex(key), flex(value)]), + SolvedType::Apply(Symbol::DICT_DICT, vec![flex(key), flex(value)]), ], ), flex(key), @@ -912,7 +912,7 @@ pub fn types() -> MutMap { Symbol::ATTR_ATTR, vec![ flex(star2), - SolvedType::Apply(Symbol::MAP_MAP, vec![flex(key), flex(value)]), + SolvedType::Apply(Symbol::DICT_DICT, vec![flex(key), flex(value)]), ], ), ) @@ -1267,12 +1267,12 @@ fn set_type(u: VarId, a: VarId) -> SolvedType { } #[inline(always)] -fn map_type(u: VarId, key: VarId, value: VarId) -> SolvedType { +fn dict_type(u: VarId, key: VarId, value: VarId) -> SolvedType { SolvedType::Apply( Symbol::ATTR_ATTR, vec![ flex(u), - SolvedType::Apply(Symbol::MAP_MAP, vec![flex(key), flex(value)]), + SolvedType::Apply(Symbol::DICT_DICT, vec![flex(key), flex(value)]), ], ) } diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index a32b2a1bc3..335eb91c1e 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -477,17 +477,16 @@ pub fn build_exp_literal<'a, 'ctx, 'env>( } else { let ctx = env.context; let builder = env.builder; - let len_u64 = str_literal.len() as u64; - let elem_bytes = CHAR_LAYOUT.stack_size(env.ptr_bytes) as u64; + let number_of_chars = str_literal.len() as u64; let ptr_bytes = env.ptr_bytes; let populate_str = |ptr| { // Copy the elements from the list literal into the array - for (index, char) in str_literal.as_bytes().iter().enumerate() { + for (index, character) in str_literal.as_bytes().iter().enumerate() { let val = env .context .i8_type() - .const_int(*char as u64, false) + .const_int(*character as u64, false) .as_basic_value_enum(); let index_val = ctx.i64_type().const_int(index as u64, false); let elem_ptr = @@ -554,14 +553,14 @@ pub fn build_exp_literal<'a, 'ctx, 'env>( "small_str_array", ) } else { - let bytes_len = elem_bytes * len_u64; - let len_type = env.ptr_int(); - let len = len_type.const_int(bytes_len, false); + let number_of_elements = env.ptr_int().const_int(number_of_chars, false); // NOTE we rely on CHAR_LAYOUT turning into a `i8` - let ptr = allocate_list(env, InPlace::Clone, &CHAR_LAYOUT, len); + let ptr = allocate_list(env, InPlace::Clone, &CHAR_LAYOUT, number_of_elements); let struct_type = collection(ctx, ptr_bytes); + populate_str(ptr); + let mut struct_val; // Store the pointer @@ -576,11 +575,14 @@ pub fn build_exp_literal<'a, 'ctx, 'env>( // Store the length struct_val = builder - .build_insert_value(struct_val, len, Builtin::WRAPPER_LEN, "insert_len") + .build_insert_value( + struct_val, + number_of_elements, + Builtin::WRAPPER_LEN, + "insert_len", + ) .unwrap(); - populate_str(ptr); - builder.build_bitcast( struct_val.into_struct_value(), collection(ctx, ptr_bytes), @@ -2170,15 +2172,24 @@ pub fn build_proc_header<'a, 'ctx, 'env>( for (name, layout) in aliases { match layout { Layout::Closure(arguments, closure, result) => { + // define closure size and return value size, e.g. + // + // * roc__mainForHost_1_Update_size() -> i64 + // * roc__mainForHost_1_Update_result_size() -> i64 build_closure_caller(env, &fn_name, *name, arguments, closure, result) } - Layout::FunctionPointer(_arguments, _result) => { - // TODO should this be considered a closure of size 0? - // or do we let the host call it directly? - // then we have no RocCallResult wrapping though + 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) } _ => { - // TODO + // for anything else we only define the size symbol, e.g. + // + // * roc__mainForHost_1_Model_size() -> i64 + build_host_exposed_alias_size(env, &fn_name, *name, layout) } } } @@ -2298,23 +2309,187 @@ pub fn build_closure_caller<'a, 'ctx, 'env>( let closure_data = builder.build_load(closure_data_ptr, "load_closure_data"); - let mut arguments = parameters; - arguments.push(closure_data); + let mut parameters = parameters; + parameters.push(closure_data); - let result = invoke_and_catch(env, function_value, function_ptr, &arguments, result_type); + let call_result = invoke_and_catch(env, function_value, function_ptr, ¶meters, result_type); - builder.build_store(output, result); + builder.build_store(output, call_result); builder.build_return(None); // STEP 3: build a {} -> u64 function that gives the size of the return type - let size_function_type = env.context.i64_type().fn_type(&[], false); - let size_function_name: String = format!( - "roc_{}_{}_size", + 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 closure + let layout = Layout::Closure(arguments, closure.clone(), result); + build_host_exposed_alias_size(env, def_name, alias_symbol, &layout); +} + +pub 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>, +) { + use inkwell::types::BasicType; + + let arena = env.arena; + 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 { + argument_types.push(basic_type_from_layout( + arena, + context, + layout, + env.ptr_bytes, + )); + } + + 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(&[])); + + let function_layout = Layout::FunctionPointer(&args, result); + + // this is already a (function) pointer type + basic_type_from_layout(arena, context, &function_layout, env.ptr_bytes) + }; + argument_types.push(function_pointer_type); + + let closure_argument_type = { + let basic_type = + basic_type_from_layout(arena, context, &Layout::Struct(&[]), env.ptr_bytes); + + basic_type.ptr_type(AddressSpace::Generic) + }; + argument_types.push(closure_argument_type.into()); + + let result_type = basic_type_from_layout(arena, context, result, env.ptr_bytes); + + 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 = env.module.add_function( + function_name.as_str(), + function_type, + Some(Linkage::External), + ); + + function_value.set_call_conventions(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 closure_data = context.struct_type(&[], false).const_zero().into(); + + let actual_function_type = basic_type_from_layout( + arena, + context, + &Layout::FunctionPointer(arguments, result), + env.ptr_bytes, + ); + + let function_ptr = builder + .build_bitcast(function_ptr, actual_function_type, "cast") + .into_pointer_value(); + + let call_result = invoke_and_catch(env, function_value, function_ptr, ¶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::FunctionPointer(arguments, result); + 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>, +) { + build_host_exposed_alias_size_help( + env, + def_name, + alias_symbol, + None, + basic_type_from_layout(env.arena, env.context, layout, env.ptr_bytes), + ) +} + +fn build_host_exposed_alias_size_help<'a, 'ctx, 'env>( + env: &'a Env<'a, 'ctx, 'env>, + def_name: &str, + alias_symbol: Symbol, + opt_label: Option<&str>, + basic_type: BasicTypeEnum<'ctx>, +) { + let builder = env.builder; + let context = env.context; + + let size_function_type = env.context.i64_type().fn_type(&[], false); + let size_function_name: String = if let Some(label) = opt_label { + format!( + "roc_{}_{}_{}_size", + def_name, + alias_symbol.ident_string(&env.interns), + label + ) + } else { + format!( + "roc_{}_{}_size", + def_name, + alias_symbol.ident_string(&env.interns) + ) + }; + let size_function = env.module.add_function( size_function_name.as_str(), size_function_type, @@ -2325,7 +2500,8 @@ pub fn build_closure_caller<'a, 'ctx, 'env>( builder.position_at_end(entry); - let size: BasicValueEnum = roc_call_result_type.size_of().unwrap().into(); + use inkwell::types::BasicType; + let size: BasicValueEnum = basic_type.size_of().unwrap().into(); builder.build_return(Some(&size)); } diff --git a/compiler/gen/src/llvm/build_list.rs b/compiler/gen/src/llvm/build_list.rs index 4049f38e05..6b7b3e99e1 100644 --- a/compiler/gen/src/llvm/build_list.rs +++ b/compiler/gen/src/llvm/build_list.rs @@ -2067,7 +2067,7 @@ pub fn allocate_list<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, inplace: InPlace, elem_layout: &Layout<'a>, - length: IntValue<'ctx>, + number_of_elements: IntValue<'ctx>, ) -> PointerValue<'ctx> { let builder = env.builder; let ctx = env.context; @@ -2075,10 +2075,11 @@ pub fn allocate_list<'a, 'ctx, 'env>( let len_type = env.ptr_int(); let elem_bytes = elem_layout.stack_size(env.ptr_bytes) as u64; let bytes_per_element = len_type.const_int(elem_bytes, false); - let number_of_data_bytes = builder.build_int_mul(bytes_per_element, length, "data_length"); + let number_of_data_bytes = + builder.build_int_mul(bytes_per_element, number_of_elements, "data_length"); let rc1 = match inplace { - InPlace::InPlace => length, + 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) diff --git a/compiler/gen/src/llvm/convert.rs b/compiler/gen/src/llvm/convert.rs index cb7842b859..97d23fd622 100644 --- a/compiler/gen/src/llvm/convert.rs +++ b/compiler/gen/src/llvm/convert.rs @@ -158,7 +158,7 @@ pub fn basic_type_from_layout<'ctx>( Float64 => context.f64_type().as_basic_type_enum(), Float32 => context.f32_type().as_basic_type_enum(), Float16 => context.f16_type().as_basic_type_enum(), - Map(_, _) | EmptyMap => panic!("TODO layout_to_basic_type for Builtin::Map"), + Dict(_, _) | EmptyDict => panic!("TODO layout_to_basic_type for Builtin::Dict"), Set(_) | EmptySet => panic!("TODO layout_to_basic_type for Builtin::Set"), List(_, _) | Str | EmptyStr => collection(context, ptr_bytes).into(), EmptyList => BasicTypeEnum::StructType(collection(context, ptr_bytes)), diff --git a/compiler/gen/src/llvm/refcounting.rs b/compiler/gen/src/llvm/refcounting.rs index 0ef67b4960..8729439750 100644 --- a/compiler/gen/src/llvm/refcounting.rs +++ b/compiler/gen/src/llvm/refcounting.rs @@ -59,13 +59,10 @@ impl<'ctx> PointerToRefcount<'ctx> { let builder = env.builder; // pointer to usize let refcount_type = ptr_int(env.context, env.ptr_bytes); + let refcount_ptr_type = refcount_type.ptr_type(AddressSpace::Generic); - let ptr_as_usize_ptr = cast_basic_basic( - builder, - data_ptr.into(), - refcount_type.ptr_type(AddressSpace::Generic).into(), - ) - .into_pointer_value(); + let ptr_as_usize_ptr = cast_basic_basic(builder, data_ptr.into(), refcount_ptr_type.into()) + .into_pointer_value(); // get a pointer to index -1 let index_intvalue = refcount_type.const_int((-1 as i64) as u64, false); @@ -400,7 +397,7 @@ fn decrement_refcount_builtin<'a, 'ctx, 'env>( } todo!(); } - Map(key_layout, value_layout) => { + Dict(key_layout, value_layout) => { if key_layout.contains_refcounted() || value_layout.contains_refcounted() { // TODO decrement all values } @@ -431,6 +428,24 @@ pub fn increment_refcount_layout<'a, 'ctx, 'env>( RecursiveUnion(tags) => { build_inc_union(env, layout_ids, tags, value); } + Closure(_, closure_layout, _) => { + if closure_layout.contains_refcounted() { + let wrapper_struct = value.into_struct_value(); + + let field_ptr = env + .builder + .build_extract_value(wrapper_struct, 1, "increment_closure_data") + .unwrap(); + + increment_refcount_layout( + env, + parent, + layout_ids, + field_ptr, + &closure_layout.as_block_of_memory_layout(), + ) + } + } _ => {} } } @@ -483,7 +498,7 @@ fn increment_refcount_builtin<'a, 'ctx, 'env>( } todo!(); } - Map(key_layout, value_layout) => { + Dict(key_layout, value_layout) => { if key_layout.contains_refcounted() || value_layout.contains_refcounted() { // TODO decrement all values } diff --git a/compiler/gen/tests/gen_primitives.rs b/compiler/gen/tests/gen_primitives.rs index aacf0715fa..865068f2f4 100644 --- a/compiler/gen/tests/gen_primitives.rs +++ b/compiler/gen/tests/gen_primitives.rs @@ -1206,11 +1206,11 @@ mod gen_primitives { NodeColor : [ Red, Black ] - Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ] + RedBlackTree k v : [ Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty ] Key k : Num k - insert : Key k, v, Dict (Key k) v -> Dict (Key k) v + insert : Key k, v, RedBlackTree (Key k) v -> RedBlackTree (Key k) v insert = \key, value, dict -> when insertHelp key value dict is Node Red k v l r -> @@ -1219,7 +1219,7 @@ mod gen_primitives { x -> x - insertHelp : (Key k), v, Dict (Key k) v -> Dict (Key k) v + insertHelp : (Key k), v, RedBlackTree (Key k) v -> RedBlackTree (Key k) v insertHelp = \key, value, dict -> when dict is Empty -> @@ -1238,7 +1238,7 @@ mod gen_primitives { GT -> balance nColor nKey nValue nLeft (insertHelp key value nRight) - balance : NodeColor, k, v, Dict k v, Dict k v -> Dict k v + balance : NodeColor, k, v, RedBlackTree k v, RedBlackTree k v -> RedBlackTree k v balance = \color, key, value, left, right -> when right is Node Red rK rV rLeft rRight -> @@ -1267,7 +1267,7 @@ mod gen_primitives { _ -> Node color key value left right - main : Dict I64 {} + main : RedBlackTree I64 {} main = insert 0 {} Empty "# @@ -1288,9 +1288,9 @@ mod gen_primitives { NodeColor : [ Red, Black ] - Dict k : [ Node NodeColor k (Dict k) (Dict k), Empty ] + RedBlackTree k : [ Node NodeColor k (RedBlackTree k) (RedBlackTree k), Empty ] - # balance : NodeColor, k, Dict k, Dict k -> Dict k + # balance : NodeColor, k, RedBlackTree k, RedBlackTree k -> RedBlackTree k balance = \color, key, left, right -> when right is Node Red rK rLeft rRight -> @@ -1308,7 +1308,7 @@ mod gen_primitives { _ -> Empty - main : Dict I64 + main : RedBlackTree I64 main = balance Red 0 Empty Empty "# @@ -1325,13 +1325,13 @@ mod gen_primitives { r#" app "test" provides [ main ] to "./platform" - Dict k : [ Node k (Dict k) (Dict k), Empty ] + RedBlackTree k : [ Node k (RedBlackTree k) (RedBlackTree k), Empty ] - balance : k, Dict k -> Dict k + balance : k, RedBlackTree k -> RedBlackTree k balance = \key, left -> Node key left Empty - main : Dict I64 + main : RedBlackTree I64 main = balance 0 Empty "# @@ -1357,9 +1357,9 @@ mod gen_primitives { NodeColor : [ Red, Black ] - Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ] + RedBlackTree k v : [ Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty ] - # balance : NodeColor, k, v, Dict k v, Dict k v -> Dict k v + # balance : NodeColor, k, v, RedBlackTree k v, RedBlackTree k v -> RedBlackTree k v balance = \color, key, value, left, right -> when right is Node Red rK rV rLeft rRight -> @@ -1378,7 +1378,7 @@ mod gen_primitives { _ -> Empty - main : Dict I64 I64 + main : RedBlackTree I64 I64 main = balance Red 0 0 Empty Empty "# @@ -1397,9 +1397,9 @@ mod gen_primitives { NodeColor : [ Red, Black ] - Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ] + RedBlackTree k v : [ Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty ] - balance : NodeColor, k, v, Dict k v, Dict k v -> Dict k v + balance : NodeColor, k, v, RedBlackTree k v, RedBlackTree k v -> RedBlackTree k v balance = \color, key, value, left, right -> when right is Node Red rK rV rLeft rRight -> @@ -1428,7 +1428,7 @@ mod gen_primitives { _ -> Node color key value left right - main : Dict I64 I64 + main : RedBlackTree I64 I64 main = balance Red 0 0 Empty Empty "# diff --git a/compiler/load/tests/fixtures/build/interface_with_deps/AStar.roc b/compiler/load/tests/fixtures/build/interface_with_deps/AStar.roc index b93c6937f3..4ddbb5946b 100644 --- a/compiler/load/tests/fixtures/build/interface_with_deps/AStar.roc +++ b/compiler/load/tests/fixtures/build/interface_with_deps/AStar.roc @@ -8,8 +8,8 @@ interface AStar Model position : { evaluated : Set position , openSet : Set position - , costs : Map.Map position F64 - , cameFrom : Map.Map position position + , costs : Dict.Dict position F64 + , cameFrom : Dict.Dict position position } @@ -17,8 +17,8 @@ initialModel : position -> Model position initialModel = \start -> { evaluated : Set.empty , openSet : Set.singleton start - , costs : Map.singleton start 0.0 - , cameFrom : Map.empty + , costs : Dict.singleton start 0.0 + , cameFrom : Dict.empty } @@ -26,7 +26,7 @@ cheapestOpen : (position -> F64), Model position -> Result position [ KeyNotFoun cheapestOpen = \costFunction, model -> folder = \position, resSmallestSoFar -> - when Map.get model.costs position is + when Dict.get model.costs position is Err e -> Err e @@ -47,9 +47,9 @@ cheapestOpen = \costFunction, model -> -reconstructPath : Map position position, position -> List position +reconstructPath : Dict position position, position -> List position reconstructPath = \cameFrom, goal -> - when Map.get cameFrom goal is + when Dict.get cameFrom goal is Err KeyNotFound -> [] @@ -58,9 +58,9 @@ reconstructPath = \cameFrom, goal -> updateCost : position, position, Model position -> Model position updateCost = \current, neighbour, model -> - newCameFrom = Map.insert model.cameFrom neighbour current + newCameFrom = Dict.insert model.cameFrom neighbour current - newCosts = Map.insert model.costs neighbour distanceTo + newCosts = Dict.insert model.costs neighbour distanceTo distanceTo = reconstructPath newCameFrom neighbour |> List.len @@ -68,7 +68,7 @@ updateCost = \current, neighbour, model -> newModel = { model & costs : newCosts , cameFrom : newCameFrom } - when Map.get model.costs neighbour is + when Dict.get model.costs neighbour is Err KeyNotFound -> newModel diff --git a/compiler/load/tests/test_load.rs b/compiler/load/tests/test_load.rs index 5d57bfa89a..b5be664eb6 100644 --- a/compiler/load/tests/test_load.rs +++ b/compiler/load/tests/test_load.rs @@ -242,15 +242,15 @@ mod test_load { "RBTree", indoc!( r#" - interface RBTree exposes [ Dict, empty ] imports [] + interface RBTree exposes [ RedBlackTree, empty ] imports [] # The color of a node. Leaves are considered Black. NodeColor : [ Red, Black ] - Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ] + RedBlackTree k v : [ Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty ] # Create an empty dictionary. - empty : Dict k v + empty : RedBlackTree k v empty = Empty "# @@ -265,7 +265,7 @@ mod test_load { imports [ RBTree ] provides [ main ] to blah - empty : RBTree.Dict I64 I64 + empty : RBTree.RedBlackTree I64 I64 empty = RBTree.empty main = empty @@ -424,7 +424,7 @@ mod test_load { hashmap! { "findPath" => "{ costFunction : position, position -> F64, end : position, moveFunction : position -> Set position, start : position } -> Result (List position) [ KeyNotFound ]*", "initialModel" => "position -> Model position", - "reconstructPath" => "Map position position, position -> List position", + "reconstructPath" => "Dict position position, position -> List position", "updateCost" => "position, position, Model position -> Model position", "cheapestOpen" => "(position -> F64), Model position -> Result position [ KeyNotFound ]*", "astar" => "(position, position -> F64), (position -> Set position), position, Model position -> [ Err [ KeyNotFound ]*, Ok (List position) ]*", diff --git a/compiler/module/src/ident.rs b/compiler/module/src/ident.rs index 438fa88060..409600f226 100644 --- a/compiler/module/src/ident.rs +++ b/compiler/module/src/ident.rs @@ -69,7 +69,7 @@ impl ModuleName { pub const STR: &'static str = "Str"; pub const NUM: &'static str = "Num"; pub const LIST: &'static str = "List"; - pub const MAP: &'static str = "Map"; + pub const DICT: &'static str = "Dict"; pub const SET: &'static str = "Set"; pub const RESULT: &'static str = "Result"; diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 2b3c2ca38f..3c6395c651 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -845,13 +845,13 @@ define_builtins! { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias 1 RESULT_MAP: "map" } - 6 MAP: "Map" => { - 0 MAP_MAP: "Map" imported // the Map.Map type alias - 1 MAP_AT_MAP: "@Map" // the Map.@Map private tag - 2 MAP_EMPTY: "empty" - 3 MAP_SINGLETON: "singleton" - 4 MAP_GET: "get" - 5 MAP_INSERT: "insert" + 6 DICT: "Dict" => { + 0 DICT_DICT: "Dict" imported // the Dict.Dict type alias + 1 DICT_AT_DICT: "@Dict" // the Dict.@Dict private tag + 2 DICT_EMPTY: "empty" + 3 DICT_SINGLETON: "singleton" + 4 DICT_GET: "get" + 5 DICT_INSERT: "insert" } 7 SET: "Set" => { 0 SET_SET: "Set" imported // the Set.Set type alias diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 9e471d41d1..dbacb9fe64 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -587,7 +587,10 @@ impl<'a> Procs<'a> { let symbol = name; // TODO should pending_procs hold a Rc? - let partial_proc = self.partial_procs.get(&symbol).unwrap().clone(); + let partial_proc = match self.partial_procs.get(&symbol) { + Some(p) => p.clone(), + None => panic!("no partial_proc for {:?}", symbol), + }; // Mark this proc as in-progress, so if we're dealing with // mutually recursive functions, we don't loop forever. diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index ce36477333..4b74489946 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -317,12 +317,12 @@ pub enum Builtin<'a> { Float32, Float16, Str, - Map(&'a Layout<'a>, &'a Layout<'a>), + Dict(&'a Layout<'a>, &'a Layout<'a>), Set(&'a Layout<'a>), List(MemoryMode, &'a Layout<'a>), EmptyStr, EmptyList, - EmptyMap, + EmptyDict, EmptySet, } @@ -667,8 +667,8 @@ impl<'a> Builtin<'a> { /// Number of machine words in an empty one of these pub const STR_WORDS: u32 = 2; - pub const MAP_WORDS: u32 = 6; - pub const SET_WORDS: u32 = Builtin::MAP_WORDS; // Set is an alias for Map with {} for value + pub const DICT_WORDS: u32 = 6; + pub const SET_WORDS: u32 = Builtin::DICT_WORDS; // Set is an alias for Dict with {} for value pub const LIST_WORDS: u32 = 2; /// Layout of collection wrapper for List and Str - a struct of (pointer, length). @@ -693,7 +693,7 @@ impl<'a> Builtin<'a> { Float32 => Builtin::F32_SIZE, Float16 => Builtin::F16_SIZE, Str | EmptyStr => Builtin::STR_WORDS * pointer_size, - Map(_, _) | EmptyMap => Builtin::MAP_WORDS * pointer_size, + Dict(_, _) | EmptyDict => Builtin::DICT_WORDS * pointer_size, Set(_) | EmptySet => Builtin::SET_WORDS * pointer_size, List(_, _) | EmptyList => Builtin::LIST_WORDS * pointer_size, } @@ -718,7 +718,7 @@ impl<'a> Builtin<'a> { Float32 => align_of::() as u32, Float16 => align_of::() as u32, Str | EmptyStr => pointer_size, - Map(_, _) | EmptyMap => pointer_size, + Dict(_, _) | EmptyDict => pointer_size, Set(_) | EmptySet => pointer_size, List(_, _) | EmptyList => pointer_size, } @@ -729,8 +729,8 @@ impl<'a> Builtin<'a> { match self { Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Float128 | Float64 | Float32 - | Float16 | EmptyStr | EmptyMap | EmptyList | EmptySet => true, - Str | Map(_, _) | Set(_) | List(_, _) => false, + | Float16 | EmptyStr | EmptyDict | EmptyList | EmptySet => true, + Str | Dict(_, _) | Set(_) | List(_, _) => false, } } @@ -740,13 +740,13 @@ impl<'a> Builtin<'a> { match self { Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Float128 | Float64 | Float32 - | Float16 | EmptyStr | EmptyMap | EmptyList | EmptySet => false, + | Float16 | EmptyStr | EmptyDict | EmptyList | EmptySet => false, List(mode, element_layout) => match mode { MemoryMode::Refcounted => true, MemoryMode::Unique => element_layout.contains_refcounted(), }, - Str | Map(_, _) | Set(_) => true, + Str | Dict(_, _) | Set(_) => true, } } } diff --git a/compiler/mono/tests/test_mono.rs b/compiler/mono/tests/test_mono.rs index 03cc907d56..be4bdc2950 100644 --- a/compiler/mono/tests/test_mono.rs +++ b/compiler/mono/tests/test_mono.rs @@ -269,14 +269,14 @@ mod test_mono { "#, indoc!( r#" - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.4 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.4; procedure Test.0 (): let Test.2 = 1i64; let Test.3 = 2i64; - let Test.1 = CallByName Num.14 Test.2 Test.3; + let Test.1 = CallByName Num.24 Test.2 Test.3; ret Test.1; "# ), @@ -291,13 +291,13 @@ mod test_mono { "#, indoc!( r#" - procedure Num.36 (#Attr.2): + procedure Num.46 (#Attr.2): let Test.3 = lowlevel NumRound #Attr.2; ret Test.3; procedure Test.0 (): let Test.2 = 3.6f64; - let Test.1 = CallByName Num.36 Test.2; + let Test.1 = CallByName Num.46 Test.2; ret Test.1; "# ), @@ -314,7 +314,7 @@ mod test_mono { "#, indoc!( r#" - procedure Num.32 (#Attr.2, #Attr.3): + procedure Num.42 (#Attr.2, #Attr.3): let Test.17 = 0i64; let Test.13 = lowlevel NotEq #Attr.3 Test.17; if Test.13 then @@ -331,7 +331,7 @@ mod test_mono { procedure Test.0 (): let Test.8 = 1000i64; let Test.9 = 10i64; - let Test.2 = CallByName Num.32 Test.8 Test.9; + let Test.2 = CallByName Num.42 Test.8 Test.9; let Test.5 = 1i64; let Test.6 = Index 0 Test.2; let Test.7 = lowlevel Eq Test.5 Test.6; @@ -357,14 +357,14 @@ mod test_mono { "#, indoc!( r#" - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.4 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.4; procedure Test.0 (): let Test.1 = 3i64; let Test.2 = 4i64; - let Test.3 = CallByName Num.14 Test.1 Test.2; + let Test.3 = CallByName Num.24 Test.1 Test.2; ret Test.3; "# ), @@ -384,7 +384,7 @@ mod test_mono { "#, indoc!( r#" - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.5 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.5; @@ -398,7 +398,7 @@ mod test_mono { if Test.9 then let Test.2 = Index 1 Test.1; let Test.4 = 1i64; - let Test.3 = CallByName Num.14 Test.2 Test.4; + let Test.3 = CallByName Num.24 Test.2 Test.4; ret Test.3; else let Test.6 = 1i64; @@ -480,7 +480,7 @@ mod test_mono { "#, indoc!( r#" - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.5 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.5; @@ -489,7 +489,7 @@ mod test_mono { let Test.2 = Struct {Test.6}; let Test.1 = Index 0 Test.2; let Test.4 = 3i64; - let Test.3 = CallByName Num.14 Test.1 Test.4; + let Test.3 = CallByName Num.24 Test.1 Test.4; ret Test.3; "# ), @@ -511,7 +511,7 @@ mod test_mono { "#, indoc!( r#" - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.6; @@ -537,7 +537,7 @@ mod test_mono { let Test.7 = Index 1 Test.2; let Test.3 = Index 1 Test.7; let Test.5 = 1i64; - let Test.4 = CallByName Num.14 Test.3 Test.5; + let Test.4 = CallByName Num.24 Test.3 Test.5; ret Test.4; else jump Test.14; @@ -558,7 +558,7 @@ mod test_mono { "#, indoc!( r#" - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.6; @@ -569,7 +569,7 @@ mod test_mono { joinpoint Test.11: let Test.1 = Index 0 Test.3; let Test.2 = Index 1 Test.3; - let Test.5 = CallByName Num.14 Test.1 Test.2; + let Test.5 = CallByName Num.24 Test.1 Test.2; ret Test.5; in let Test.9 = Index 1 Test.3; @@ -665,7 +665,7 @@ mod test_mono { let Test.8 = lowlevel ListLen #Attr.2; ret Test.8; - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.6; @@ -680,7 +680,7 @@ mod test_mono { dec Test.1; let Test.5 = CallByName List.7 Test.2; dec Test.2; - let Test.3 = CallByName Num.14 Test.4 Test.5; + let Test.3 = CallByName Num.24 Test.4 Test.5; ret Test.3; "# ), @@ -1055,14 +1055,14 @@ mod test_mono { ), indoc!( r#" - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.8 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.8; procedure Test.1 (Test.2): let Test.3 = Index 0 Test.2; let Test.4 = Index 1 Test.2; - let Test.7 = CallByName Num.14 Test.3 Test.4; + let Test.7 = CallByName Num.24 Test.3 Test.4; ret Test.7; procedure Test.0 (): @@ -1091,14 +1091,14 @@ mod test_mono { ), indoc!( r#" - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.8 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.8; procedure Test.1 (Test.2): let Test.3 = 10i64; let Test.4 = Index 1 Test.2; - let Test.7 = CallByName Num.14 Test.3 Test.4; + let Test.7 = CallByName Num.24 Test.3 Test.4; ret Test.7; procedure Test.0 (): @@ -1124,14 +1124,14 @@ mod test_mono { ), indoc!( r#" - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.8 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.8; procedure Test.1 (Test.4): let Test.2 = Index 0 Test.4; let Test.3 = Index 1 Test.4; - let Test.7 = CallByName Num.14 Test.2 Test.3; + let Test.7 = CallByName Num.24 Test.2 Test.3; ret Test.7; procedure Test.0 (): @@ -1158,14 +1158,14 @@ mod test_mono { ), indoc!( r#" - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.8 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.8; procedure Test.1 (Test.4): let Test.2 = 10i64; let Test.3 = Index 1 Test.4; - let Test.7 = CallByName Num.14 Test.2 Test.3; + let Test.7 = CallByName Num.24 Test.2 Test.3; ret Test.7; procedure Test.0 (): @@ -1496,11 +1496,11 @@ mod test_mono { "#, indoc!( r#" - procedure Num.15 (#Attr.2, #Attr.3): + procedure Num.25 (#Attr.2, #Attr.3): let Test.14 = lowlevel NumSub #Attr.2 #Attr.3; ret Test.14; - procedure Num.16 (#Attr.2, #Attr.3): + procedure Num.26 (#Attr.2, #Attr.3): let Test.12 = lowlevel NumMul #Attr.2 #Attr.3; ret Test.12; @@ -1512,8 +1512,8 @@ mod test_mono { ret Test.3; else let Test.13 = 1i64; - let Test.10 = CallByName Num.15 Test.2 Test.13; - let Test.11 = CallByName Num.16 Test.2 Test.3; + let Test.10 = CallByName Num.25 Test.2 Test.13; + let Test.11 = CallByName Num.26 Test.2 Test.3; jump Test.7 Test.10 Test.11; in jump Test.7 Test.2 Test.3; @@ -1715,7 +1715,7 @@ mod test_mono { let Test.9 = lowlevel ListLen #Attr.2; ret Test.9; - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.7 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.7; @@ -1740,7 +1740,7 @@ mod test_mono { let Test.8 = FunctionPointer Test.1; let Test.6 = CallByName List.7 Test.8; dec Test.8; - let Test.4 = CallByName Num.14 Test.5 Test.6; + let Test.4 = CallByName Num.24 Test.5 Test.6; ret Test.4; "# ), @@ -1935,7 +1935,7 @@ mod test_mono { ), indoc!( r#" - procedure Num.16 (#Attr.2, #Attr.3): + procedure Num.26 (#Attr.2, #Attr.3): let Test.13 = lowlevel NumMul #Attr.2 #Attr.3; ret Test.13; @@ -1976,9 +1976,9 @@ mod test_mono { let Test.22 = false; let Test.15 = Struct {Test.21, Test.22}; let Test.2 = CallByName Test.1 Test.15; - let Test.14 = CallByName Num.16 Test.2 Test.3; - let Test.12 = CallByName Num.16 Test.14 Test.4; - let Test.11 = CallByName Num.16 Test.12 Test.5; + let Test.14 = CallByName Num.26 Test.2 Test.3; + let Test.12 = CallByName Num.26 Test.14 Test.4; + let Test.11 = CallByName Num.26 Test.12 Test.5; ret Test.11; "# ), @@ -2002,7 +2002,7 @@ mod test_mono { ), indoc!( r#" - procedure Num.14 (#Attr.2, #Attr.3): + procedure Num.24 (#Attr.2, #Attr.3): let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3; ret Test.6; @@ -2028,7 +2028,7 @@ mod test_mono { let Test.7 = Index 1 Test.2; let Test.3 = Index 1 Test.7; let Test.5 = 1i64; - let Test.4 = CallByName Num.14 Test.3 Test.5; + let Test.4 = CallByName Num.24 Test.3 Test.5; ret Test.4; else jump Test.14; diff --git a/compiler/reporting/tests/test_reporting.rs b/compiler/reporting/tests/test_reporting.rs index 6f394ac6fd..0f3b3dfc56 100644 --- a/compiler/reporting/tests/test_reporting.rs +++ b/compiler/reporting/tests/test_reporting.rs @@ -447,9 +447,9 @@ mod test_reporting { these names seem close though: baz - Map Str main + U8 "# ), ) @@ -3534,8 +3534,8 @@ mod test_reporting { Bool Num - Map Set + Str "# ), ) @@ -3928,10 +3928,10 @@ mod test_reporting { # The color of a node. Leaves are considered Black. NodeColor : [ Red, Black ] - Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ] + RBTree k v : [ Node NodeColor k v (RBTree k v) (RBTree k v), Empty ] # Create an empty dictionary. - empty : Dict k v + empty : RBTree k v empty = Empty diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index a651fa05f1..835473f518 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -3102,10 +3102,10 @@ mod solve_expr { infer_eq_without_problem( indoc!( r#" - Map.insert + Dict.insert "# ), - "Map a b, a, b -> Map a b", + "Dict a b, a, b -> Dict a b", ); } @@ -3186,9 +3186,9 @@ mod solve_expr { infer_eq_without_problem( indoc!( r#" - reconstructPath : Map position position, position -> List position + reconstructPath : Dict position position, position -> List position reconstructPath = \cameFrom, goal -> - when Map.get cameFrom goal is + when Dict.get cameFrom goal is Err KeyNotFound -> [] @@ -3198,7 +3198,7 @@ mod solve_expr { reconstructPath "# ), - "Map position position, position -> List position", + "Dict position position, position -> List position", ); } @@ -3695,22 +3695,22 @@ mod solve_expr { # The color of a node. Leaves are considered Black. NodeColor : [ Red, Black ] - Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ] + RBTree k v : [ Node NodeColor k v (RBTree k v) (RBTree k v), Empty ] # Create an empty dictionary. - empty : Dict k v + empty : RBTree k v empty = Empty - foo : Dict I64 I64 + foo : RBTree I64 I64 foo = empty - main : Dict I64 I64 + main : RBTree I64 I64 main = foo "# ), - "Dict I64 I64", + "RBTree I64 I64", ); } @@ -3725,21 +3725,21 @@ mod solve_expr { r#" app "test" provides [ main ] to "./platform" - Dict k : [ Node k (Dict k), Empty ] + RBTree k : [ Node k (RBTree k), Empty ] - balance : Dict k -> Dict k + balance : RBTree k -> RBTree k balance = \left -> when left is Node _ Empty -> Empty _ -> Empty - main : Dict {} + main : RBTree {} main = balance Empty "# ), - "Dict {}", + "RBTree {}", ); } @@ -3752,9 +3752,9 @@ mod solve_expr { NodeColor : [ Red, Black ] - Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ] + RBTree k v : [ Node NodeColor k v (RBTree k v) (RBTree k v), Empty ] - moveRedLeft : Dict k v -> Dict k v + moveRedLeft : RBTree k v -> RBTree k v moveRedLeft = \dict -> when dict is # Node clr k v (Node lClr lK lV lLeft lRight) (Node rClr rK rV ((Node Red rlK rlV rlL rlR) as rLeft) rRight) -> @@ -3790,7 +3790,7 @@ mod solve_expr { _ -> dict - balance : NodeColor, k, v, Dict k v, Dict k v -> Dict k v + balance : NodeColor, k, v, RBTree k v, RBTree k v -> RBTree k v balance = \color, key, value, left, right -> when right is Node Red rK rV rLeft rRight -> @@ -3822,7 +3822,7 @@ mod solve_expr { Key k : Num k - removeHelpEQGT : Key k, Dict (Key k) v -> Dict (Key k) v + removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v removeHelpEQGT = \targetKey, dict -> when dict is Node color key value left right -> @@ -3839,7 +3839,7 @@ mod solve_expr { Empty -> Empty - getMin : Dict k v -> Dict k v + getMin : RBTree k v -> RBTree k v getMin = \dict -> when dict is # Node _ _ _ ((Node _ _ _ _ _) as left) _ -> @@ -3852,7 +3852,7 @@ mod solve_expr { dict - moveRedRight : Dict k v -> Dict k v + moveRedRight : RBTree k v -> RBTree k v moveRedRight = \dict -> when dict is Node clr k v (Node lClr lK lV (Node Red llK llV llLeft llRight) lRight) (Node rClr rK rV rLeft rRight) -> @@ -3885,7 +3885,7 @@ mod solve_expr { dict - removeHelpPrepEQGT : Key k, Dict (Key k) v, NodeColor, (Key k), v, Dict (Key k) v, Dict (Key k) v -> Dict (Key k) v + removeHelpPrepEQGT : Key k, RBTree (Key k) v, NodeColor, (Key k), v, RBTree (Key k) v, RBTree (Key k) v -> RBTree (Key k) v removeHelpPrepEQGT = \_, dict, color, key, value, left, right -> when left is Node Red lK lV lLeft lRight -> @@ -3908,7 +3908,7 @@ mod solve_expr { dict - removeMin : Dict k v -> Dict k v + removeMin : RBTree k v -> RBTree k v removeMin = \dict -> when dict is Node color key value left right -> @@ -3936,7 +3936,7 @@ mod solve_expr { _ -> Empty - removeHelp : Key k, Dict (Key k) v -> Dict (Key k) v + removeHelp : Key k, RBTree (Key k) v -> RBTree (Key k) v removeHelp = \targetKey, dict -> when dict is Empty -> @@ -3964,12 +3964,12 @@ mod solve_expr { removeHelpEQGT targetKey (removeHelpPrepEQGT targetKey dict color key value left right) - main : Dict I64 I64 + main : RBTree I64 I64 main = removeHelp 1 Empty "# ), - "Dict I64 I64", + "RBTree I64 I64", ); } @@ -3980,9 +3980,9 @@ mod solve_expr { r#" app "test" provides [ main ] to "./platform" - Dict k : [ Node k (Dict k) (Dict k), Empty ] + RBTree k : [ Node k (RBTree k) (RBTree k), Empty ] - removeHelp : Num k, Dict (Num k) -> Dict (Num k) + removeHelp : Num k, RBTree (Num k) -> RBTree (Num k) removeHelp = \targetKey, dict -> when dict is Empty -> @@ -4004,12 +4004,12 @@ mod solve_expr { Empty - main : Dict I64 + main : RBTree I64 main = removeHelp 1 Empty "# ), - "Dict I64", + "RBTree I64", ); } @@ -4022,9 +4022,9 @@ mod solve_expr { NodeColor : [ Red, Black ] - Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ] + RBTree k v : [ Node NodeColor k v (RBTree k v) (RBTree k v), Empty ] - removeHelp : Num k, Dict (Num k) v -> Dict (Num k) v + removeHelp : Num k, RBTree (Num k) v -> RBTree (Num k) v removeHelp = \targetKey, dict -> when dict is Empty -> @@ -4053,13 +4053,13 @@ mod solve_expr { Key k : Num k - balance : NodeColor, k, v, Dict k v, Dict k v -> Dict k v + balance : NodeColor, k, v, RBTree k v, RBTree k v -> RBTree k v - moveRedLeft : Dict k v -> Dict k v + moveRedLeft : RBTree k v -> RBTree k v - removeHelpPrepEQGT : Key k, Dict (Key k) v, NodeColor, (Key k), v, Dict (Key k) v, Dict (Key k) v -> Dict (Key k) v + removeHelpPrepEQGT : Key k, RBTree (Key k) v, NodeColor, (Key k), v, RBTree (Key k) v, RBTree (Key k) v -> RBTree (Key k) v - removeHelpEQGT : Key k, Dict (Key k) v -> Dict (Key k) v + removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v removeHelpEQGT = \targetKey, dict -> when dict is Node color key value left right -> @@ -4076,16 +4076,16 @@ mod solve_expr { Empty -> Empty - getMin : Dict k v -> Dict k v + getMin : RBTree k v -> RBTree k v - removeMin : Dict k v -> Dict k v + removeMin : RBTree k v -> RBTree k v - main : Dict I64 I64 + main : RBTree I64 I64 main = removeHelp 1 Empty "# ), - "Dict I64 I64", + "RBTree I64 I64", ); } @@ -4134,18 +4134,18 @@ mod solve_expr { r#" app "test" provides [ main ] to "./platform" - Dict k : [ Node k (Dict k) (Dict k), Empty ] + RBTree k : [ Node k (RBTree k) (RBTree k), Empty ] - balance : k, Dict k -> Dict k + balance : k, RBTree k -> RBTree k balance = \key, left -> Node key left Empty - main : Dict I64 + main : RBTree I64 main = balance 0 Empty "# ), - "Dict I64", + "RBTree I64", ); } @@ -4156,20 +4156,20 @@ mod solve_expr { r#" app "test" provides [ main ] to "./platform" - Dict k : [ Node k (Dict k) (Dict k), Empty ] + RBTree k : [ Node k (RBTree k) (RBTree k), Empty ] node = \x,y,z -> Node x y z - balance : k, Dict k -> Dict k + balance : k, RBTree k -> RBTree k balance = \key, left -> node key left Empty - main : Dict I64 + main : RBTree I64 main = balance 0 Empty "# ), - "Dict I64", + "RBTree I64", ); } @@ -4182,9 +4182,9 @@ mod solve_expr { NodeColor : [ Red, Black ] - Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ] + RBTree k v : [ Node NodeColor k v (RBTree k v) (RBTree k v), Empty ] - balance : NodeColor, k, v, Dict k v, Dict k v -> Dict k v + balance : NodeColor, k, v, RBTree k v, RBTree k v -> RBTree k v balance = \color, key, value, left, right -> when right is Node Red rK rV rLeft rRight -> @@ -4213,12 +4213,12 @@ mod solve_expr { _ -> Node color key value left right - main : Dict I64 I64 + main : RBTree I64 I64 main = balance Red 0 0 Empty Empty "# ), - "Dict I64 I64", + "RBTree I64 I64", ); } @@ -4230,9 +4230,9 @@ mod solve_expr { r#" app Test provides [ main ] imports [] - Dict k : [ Node k (Dict k) (Dict k), Empty ] + RBTree k : [ Node k (RBTree k) (RBTree k), Empty ] - balance : k, Dict k -> Dict k + balance : k, RBTree k -> RBTree k balance = \key, left -> when left is Node _ _ lRight -> @@ -4242,12 +4242,12 @@ mod solve_expr { Empty - main : Dict I64 + main : RBTree I64 main = balance 0 Empty "# ), - "Dict I64", + "RBTree I64", ); } } diff --git a/compiler/solve/tests/solve_uniq_expr.rs b/compiler/solve/tests/solve_uniq_expr.rs index cfc0ed1c7a..adf9f098bf 100644 --- a/compiler/solve/tests/solve_uniq_expr.rs +++ b/compiler/solve/tests/solve_uniq_expr.rs @@ -2397,24 +2397,24 @@ mod solve_uniq_expr { #[test] fn map_empty() { - infer_eq("Map.empty", "Attr * (Map * *)"); + infer_eq("Dict.empty", "Attr * (Dict * *)"); } #[test] fn map_singelton() { - infer_eq("Map.singleton", "Attr * (a, b -> Attr * (Map a b))"); + infer_eq("Dict.singleton", "Attr * (a, b -> Attr * (Dict a b))"); } #[test] fn map_get() { - infer_eq("Map.get", "Attr * (Attr (* | c) (Map (Attr * a) (Attr c b)), Attr * a -> Attr * (Result (Attr c b) (Attr * [ KeyNotFound ]*)))"); + infer_eq("Dict.get", "Attr * (Attr (* | c) (Dict (Attr * a) (Attr c b)), Attr * a -> Attr * (Result (Attr c b) (Attr * [ KeyNotFound ]*)))"); } #[test] fn map_insert() { infer_eq( - "Map.insert", - "Attr * (Attr * (Map a b), a, b -> Attr * (Map a b))", + "Dict.insert", + "Attr * (Attr * (Dict a b), a, b -> Attr * (Dict a b))", ); } @@ -2747,9 +2747,9 @@ mod solve_uniq_expr { infer_eq( indoc!( r#" - reconstructPath : Map position position, position -> List position + reconstructPath : Dict position position, position -> List position reconstructPath = \cameFrom, goal -> - when Map.get cameFrom goal is + when Dict.get cameFrom goal is Err KeyNotFound -> [] @@ -2759,7 +2759,7 @@ mod solve_uniq_expr { reconstructPath "# ), - "Attr Shared (Attr Shared (Map (Attr * position) (Attr Shared position)), Attr Shared position -> Attr * (List (Attr Shared position)))" + "Attr Shared (Attr Shared (Dict (Attr * position) (Attr Shared position)), Attr Shared position -> Attr * (List (Attr Shared position)))" ); } @@ -2772,15 +2772,15 @@ mod solve_uniq_expr { r#" Model position : { evaluated : Set position , openSet : Set position - , costs : Map.Map position F64 - , cameFrom : Map.Map position position + , costs : Dict.Dict position F64 + , cameFrom : Dict.Dict position position } cheapestOpen : (position -> F64), Model position -> Result position [ KeyNotFound ]* cheapestOpen = \costFunction, model -> folder = \position, resSmallestSoFar -> - when Map.get model.costs position is + when Dict.get model.costs position is Err e -> Err e @@ -2815,13 +2815,13 @@ mod solve_uniq_expr { r#" Model position : { evaluated : Set position , openSet : Set position - , costs : Map.Map position F64 - , cameFrom : Map.Map position position + , costs : Dict.Dict position F64 + , cameFrom : Dict.Dict position position } - reconstructPath : Map position position, position -> List position + reconstructPath : Dict position position, position -> List position reconstructPath = \cameFrom, goal -> - when Map.get cameFrom goal is + when Dict.get cameFrom goal is Err KeyNotFound -> [] @@ -2830,9 +2830,9 @@ mod solve_uniq_expr { updateCost : position, position, Model position -> Model position updateCost = \current, neighbour, model -> - newCameFrom = Map.insert model.cameFrom neighbour current + newCameFrom = Dict.insert model.cameFrom neighbour current - newCosts = Map.insert model.costs neighbour distanceTo + newCosts = Dict.insert model.costs neighbour distanceTo distanceTo = reconstructPath newCameFrom neighbour |> List.len @@ -2840,7 +2840,7 @@ mod solve_uniq_expr { newModel = { model & costs : newCosts , cameFrom : newCameFrom } - when Map.get model.costs neighbour is + when Dict.get model.costs neighbour is Err KeyNotFound -> newModel @@ -2867,8 +2867,8 @@ mod solve_uniq_expr { r#" Model position : { evaluated : Set position , openSet : Set position - , costs : Map.Map position F64 - , cameFrom : Map.Map position position + , costs : Dict.Dict position F64 + , cameFrom : Dict.Dict position position } @@ -2876,8 +2876,8 @@ mod solve_uniq_expr { initialModel = \start -> { evaluated : Set.empty , openSet : Set.singleton start - , costs : Map.singleton start 0.0 - , cameFrom : Map.empty + , costs : Dict.singleton start 0.0 + , cameFrom : Dict.empty } @@ -2885,7 +2885,7 @@ mod solve_uniq_expr { cheapestOpen = \costFunction, model -> folder = \position, resSmallestSoFar -> - when Map.get model.costs position is + when Dict.get model.costs position is Err e -> Err e @@ -2906,9 +2906,9 @@ mod solve_uniq_expr { |> Result.map (\x -> x.position) - reconstructPath : Map position position, position -> List position + reconstructPath : Dict position position, position -> List position reconstructPath = \cameFrom, goal -> - when Map.get cameFrom goal is + when Dict.get cameFrom goal is Err KeyNotFound -> [] @@ -2918,9 +2918,9 @@ mod solve_uniq_expr { updateCost : position, position, Model position -> Model position updateCost = \current, neighbour, model -> - newCameFrom = Map.insert model.cameFrom neighbour current + newCameFrom = Dict.insert model.cameFrom neighbour current - newCosts = Map.insert model.costs neighbour distanceTo + newCosts = Dict.insert model.costs neighbour distanceTo distanceTo = reconstructPath newCameFrom neighbour @@ -2929,7 +2929,7 @@ mod solve_uniq_expr { newModel = { model & costs : newCosts , cameFrom : newCameFrom } - when Map.get model.costs neighbour is + when Dict.get model.costs neighbour is Err KeyNotFound -> newModel diff --git a/compiler/types/src/builtin_aliases.rs b/compiler/types/src/builtin_aliases.rs index 280386fc28..885d9fa395 100644 --- a/compiler/types/src/builtin_aliases.rs +++ b/compiler/types/src/builtin_aliases.rs @@ -347,8 +347,8 @@ pub fn set_type(a: SolvedType) -> SolvedType { } #[inline(always)] -pub fn map_type(key: SolvedType, value: SolvedType) -> SolvedType { - SolvedType::Apply(Symbol::MAP_MAP, vec![key, value]) +pub fn dict_type(key: SolvedType, value: SolvedType) -> SolvedType { + SolvedType::Apply(Symbol::DICT_DICT, vec![key, value]) } fn single_private_tag(symbol: Symbol, type_arguments: Vec) -> SolvedType { diff --git a/compiler/types/src/types.rs b/compiler/types/src/types.rs index 4d07aa859d..ac62591a15 100644 --- a/compiler/types/src/types.rs +++ b/compiler/types/src/types.rs @@ -150,7 +150,7 @@ pub enum Type { actual: Box, }, RecursiveTagUnion(Variable, Vec<(TagName, Vec)>, Box), - /// Applying a type to some arguments (e.g. Map.Map String Int) + /// Applying a type to some arguments (e.g. Dict.Dict String Int) Apply(Symbol, Vec), /// Boolean type used in uniqueness inference Boolean(boolean_algebra::Bool), diff --git a/docs/src/main.rs b/docs/src/main.rs index 256978028e..8e644c9780 100644 --- a/docs/src/main.rs +++ b/docs/src/main.rs @@ -48,7 +48,7 @@ fn main() { generate( vec![ PathBuf::from(r"../compiler/builtins/docs/Bool.roc"), - PathBuf::from(r"../compiler/builtins/docs/Map.roc"), + PathBuf::from(r"../compiler/builtins/docs/Dict.roc"), // Not working // PathBuf::from(r"../compiler/builtins/docs/List.roc"), // Not working diff --git a/examples/tea/Main.roc b/examples/tea/Main.roc new file mode 100644 index 0000000000..6a02b55825 --- /dev/null +++ b/examples/tea/Main.roc @@ -0,0 +1,7 @@ +app "effect-example" + packages { base: "platform" } + imports [base.Cmd] + provides [ main ] to base + +main : I64 +main = 42 diff --git a/examples/tea/platform/Cargo.lock b/examples/tea/platform/Cargo.lock new file mode 100644 index 0000000000..331efb48b9 --- /dev/null +++ b/examples/tea/platform/Cargo.lock @@ -0,0 +1,21 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "host" +version = "0.1.0" +dependencies = [ + "roc_std", +] + +[[package]] +name = "libc" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" + +[[package]] +name = "roc_std" +version = "0.1.0" +dependencies = [ + "libc", +] diff --git a/examples/tea/platform/Cargo.toml b/examples/tea/platform/Cargo.toml new file mode 100644 index 0000000000..70f3c1f86c --- /dev/null +++ b/examples/tea/platform/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "host" +version = "0.1.0" +authors = ["Richard Feldman "] +edition = "2018" + +[lib] +crate-type = ["staticlib"] + +[dependencies] +roc_std = { path = "../../../roc_std" } + +[workspace] diff --git a/examples/tea/platform/Cmd.roc b/examples/tea/platform/Cmd.roc new file mode 100644 index 0000000000..cb0a78b1cc --- /dev/null +++ b/examples/tea/platform/Cmd.roc @@ -0,0 +1,24 @@ +interface Cmd + exposes [ Cmd, none, map, putLine, getLine, always, after ] + imports [ Effect ] + +Cmd a : Effect.Effect a + +none : Cmd {} +none = Effect.always {} + +always : {} -> Cmd {} +always = \x -> Effect.always x + +getLine : (Str -> msg) -> Cmd msg +getLine = \toMsg -> + Effect.map Effect.getLine toMsg + +putLine : Str -> Cmd {} +putLine = \line -> Effect.putLine line + +map : Cmd a, (a -> b) -> Cmd b +map = \cmd, transform -> Effect.map cmd transform + +after : Cmd a, (a -> Cmd b) -> Cmd b +after = \cmd, transform -> Effect.after cmd transform diff --git a/examples/tea/platform/Pkg-Config.roc b/examples/tea/platform/Pkg-Config.roc new file mode 100644 index 0000000000..6d9a0a0752 --- /dev/null +++ b/examples/tea/platform/Pkg-Config.roc @@ -0,0 +1,41 @@ +platform folkertdev/foo + requires { main : Effect {} } + exposes [] + packages {} + imports [Cmd] + provides [ mainForHost ] + effects Effect + { + putChar : I64 -> Effect {}, + putLine : Str -> Effect {}, + getLine : Effect Str + } + + +mainForHost : + { + init : ({} -> { model: I64, cmd : (Cmd.Cmd [ Line Str ]) as Fx }) as Init, + update : ([ Line Str ], I64 -> { model: I64, cmd : Cmd.Cmd [ Line Str ] } ) as Update + } +mainForHost = + { + init : \{} -> + { + model: 42, + cmd: + Cmd.after (Cmd.putLine "Type a thing, and I'll say it back") \{} -> + Cmd.getLine (\l -> Line l) + }, + update : \msg, model -> + when msg is + Line line -> + cmd = + Cmd.after (Cmd.putLine "You said:") \{} -> + Cmd.after (Cmd.putLine line) \{} -> + Cmd.after (Cmd.putLine "Type another thing, and I'll say it back") \{} -> + Cmd.getLine (\l -> Line l) + + { model: model + 1, cmd } + } + + diff --git a/examples/tea/platform/host.c b/examples/tea/platform/host.c new file mode 100644 index 0000000000..0378c69589 --- /dev/null +++ b/examples/tea/platform/host.c @@ -0,0 +1,7 @@ +#include + +extern int rust_main(); + +int main() { + return rust_main(); +} diff --git a/examples/tea/platform/src/lib.rs b/examples/tea/platform/src/lib.rs new file mode 100644 index 0000000000..3d9efe668d --- /dev/null +++ b/examples/tea/platform/src/lib.rs @@ -0,0 +1,298 @@ +#![allow(non_snake_case)] + +use roc_std::alloca; +use roc_std::RocCallResult; +use roc_std::RocStr; +use std::alloc::Layout; +use std::time::SystemTime; + +type Msg = RocStr; +type Model = i64; + +extern "C" { + #[link_name = "roc__mainForHost_1_exposed"] + fn roc_main(output: *mut u8) -> (); + + #[link_name = "roc__mainForHost_1_size"] + fn roc_main_size() -> i64; + + #[link_name = "roc__mainForHost_1_Init_caller"] + fn call_Init(function_pointer: *const u8, closure_data: *const u8, output: *mut u8) -> (); + + #[link_name = "roc__mainForHost_1_Init_size"] + fn size_Init() -> i64; + + #[link_name = "roc__mainForHost_1_Init_result_size"] + fn size_Init_result() -> i64; + + #[link_name = "roc__mainForHost_1_Update_caller"] + fn call_Update( + msg: Msg, + model: Model, + function_pointer: *const u8, + closure_data: *const u8, + output: *mut u8, + ) -> (); + + #[link_name = "roc__mainForHost_1_Update_size"] + fn size_Update() -> i64; + + #[link_name = "roc__mainForHost_1_Update_result_size"] + fn size_Update_result() -> i64; + + #[link_name = "roc__mainForHost_1_Fx_caller"] + fn call_Fx(function_pointer: *const u8, closure_data: *const u8, output: *mut u8) -> (); + + #[link_name = "roc__mainForHost_1_Fx_size"] + fn size_Fx() -> i64; + + #[link_name = "roc__mainForHost_1_Fx_result_size"] + fn size_Fx_result() -> i64; + + #[link_name = "roc__mainForHost_1_Model_size"] + fn size_Model() -> i64; +} + +#[no_mangle] +pub fn roc_fx_putChar(foo: i64) -> () { + let character = foo as u8 as char; + print!("{}", character); + + () +} + +#[no_mangle] +pub fn roc_fx_putLine(line: RocStr) -> () { + let bytes = line.as_slice(); + let string = unsafe { std::str::from_utf8_unchecked(bytes) }; + println!("{}", string); + + () +} + +#[no_mangle] +pub fn roc_fx_getLine() -> RocStr { + use std::io::{self, BufRead}; + + let stdin = io::stdin(); + let line1 = stdin.lock().lines().next().unwrap().unwrap(); + + RocStr::from_slice_with_capacity(line1.as_bytes(), line1.len()) +} + +unsafe fn run_fx(function_pointer: *const u8, closure_data_ptr: *const u8) -> Msg { + let size = size_Fx_result() as usize; + + alloca::with_stack_bytes(size, |buffer| { + let buffer: *mut std::ffi::c_void = buffer; + let buffer: *mut u8 = buffer as *mut u8; + + call_Fx( + function_pointer, + closure_data_ptr as *const u8, + buffer as *mut u8, + ); + + let output = &*(buffer as *mut RocCallResult<()>); + + match output.into() { + Ok(()) => { + let mut bytes = *(buffer.add(8) as *const (u64, u64)); + let msg = std::mem::transmute::<(u64, u64), RocStr>(bytes); + + msg + } + + Err(e) => panic!("failed with {}", e), + } + }) +} + +unsafe fn run_init(function_pointer: *const u8, closure_data_ptr: *const u8) -> (Model, Msg) { + let size = size_Init_result() as usize; + + alloca::with_stack_bytes(size, |buffer| { + let buffer: *mut std::ffi::c_void = buffer; + let buffer: *mut u8 = buffer as *mut u8; + + call_Init(function_pointer, 0 as *const u8, buffer as *mut u8); + + // cmd < model, so the command comes first + let output = &*(buffer as *mut RocCallResult<()>); + + match output.into() { + Ok(_) => { + let offset = 8 + size_Fx(); + let model_ptr = buffer.add(offset as usize); + let model: i64 = *(model_ptr as *const i64); + + let cmd_fn_ptr_ptr = buffer.add(8) as *const i64; + let cmd_fn_ptr = (*cmd_fn_ptr_ptr) as *const u8; + let cmd_closure_data_ptr = buffer.add(16); + + let msg = run_fx(cmd_fn_ptr, cmd_closure_data_ptr); + + (model, msg) + } + + Err(e) => panic!("failed with {}", e), + } + }) +} + +unsafe fn run_update( + msg: RocStr, + model: Model, + function_pointer: *const u8, + closure_data_ptr: *const u8, +) -> (Model, Msg) { + let size = size_Update_result() as usize; + + alloca::with_stack_bytes(size, |buffer| { + let buffer: *mut std::ffi::c_void = buffer; + let buffer: *mut u8 = buffer as *mut u8; + + call_Update( + msg, + model, + function_pointer, + closure_data_ptr, + buffer as *mut u8, + ); + + // cmd < model, so the command comes first + let output = &*(buffer as *mut RocCallResult<()>); + + match output.into() { + Ok(_) => { + let offset = 8 + size_Fx(); + let model_ptr = buffer.add(offset as usize); + let model: i64 = *(model_ptr as *const i64); + + let cmd_fn_ptr_ptr = buffer.add(8) as *const i64; + let cmd_fn_ptr = (*cmd_fn_ptr_ptr) as *const u8; + let cmd_closure_data_ptr = buffer.add(16); + + let msg = run_fx(cmd_fn_ptr, cmd_closure_data_ptr); + + (model, msg) + } + + Err(e) => panic!("failed with {}", e), + } + }) +} + +#[no_mangle] +pub fn rust_main() -> isize { + let start_time = SystemTime::now(); + + let size = unsafe { roc_main_size() } as usize; + let layout = Layout::array::(size).unwrap(); + let answer = unsafe { + let buffer = std::alloc::alloc(layout); + + roc_main(buffer); + + let output = &*(buffer as *mut RocCallResult<(*const u8, *const u8)>); + + match output.into() { + Ok((init_fn_ptr, update_fn_ptr)) => { + // let closure_data_ptr = buffer.offset(16); + let closure_data_ptr = 0 as *const u8; + + let (mut model, mut msg) = + run_init(init_fn_ptr as *const u8, closure_data_ptr as *const u8); + + for _ in 0..5 { + let result = run_update( + msg, + model, + update_fn_ptr as *const u8, + closure_data_ptr as *const u8, + ); + + model = result.0; + msg = result.1; + } + + std::alloc::dealloc(buffer, layout); + + model + } + Err(msg) => { + std::alloc::dealloc(buffer, layout); + + panic!("Roc failed with message: {}", msg); + } + } + }; + let end_time = SystemTime::now(); + let duration = end_time.duration_since(start_time).unwrap(); + + println!( + "Roc closure took {:.4} ms to compute this answer: {:?}", + duration.as_secs_f64() * 1000.0, + // truncate the answer, so stdout is not swamped + answer + ); + + // Exit code + 0 +} + +/* +#[no_mangle] +pub fn old_rust_main() -> isize { + println!("Running Roc closure"); + let start_time = SystemTime::now(); + + let size = unsafe { roc_main_size() } as usize; + let layout = Layout::array::(size).unwrap(); + let answer = unsafe { + let buffer = std::alloc::alloc(layout); + + roc_main(buffer); + + let output = &*(buffer as *mut RocCallResult<()>); + + match output.into() { + Ok(()) => { + let function_pointer = { + // this is a pointer to the location where the function pointer is stored + // we pass just the function pointer + let temp = buffer.offset(8) as *const i64; + + (*temp) as *const u8 + }; + + let closure_data_ptr = buffer.offset(16); + + let result = + call_the_closure(function_pointer as *const u8, closure_data_ptr as *const u8); + + std::alloc::dealloc(buffer, layout); + + result + } + Err(msg) => { + std::alloc::dealloc(buffer, layout); + + panic!("Roc failed with message: {}", msg); + } + } + }; + let end_time = SystemTime::now(); + let duration = end_time.duration_since(start_time).unwrap(); + + println!( + "Roc closure took {:.4} ms to compute this answer: {:?}", + duration.as_secs_f64() * 1000.0, + // truncate the answer, so stdout is not swamped + answer + ); + + // Exit code + 0 +} +*/