diff --git a/cli/src/repl/eval.rs b/cli/src/repl/eval.rs index 94f51ec6cf..21304feab9 100644 --- a/cli/src/repl/eval.rs +++ b/cli/src/repl/eval.rs @@ -116,7 +116,7 @@ fn jit_to_ast_help<'a>( } })) } - Layout::Builtin(Builtin::List(_, elem_layout)) => Ok(run_jit_function!( + Layout::Builtin(Builtin::List(elem_layout)) => Ok(run_jit_function!( lib, main_fn_name, (*const u8, usize), @@ -125,12 +125,6 @@ fn jit_to_ast_help<'a>( Layout::Builtin(other) => { todo!("add support for rendering builtin {:?} to the REPL", other) } - Layout::PhantomEmptyStruct => Ok(run_jit_function!(lib, main_fn_name, &u8, |_| { - Expr::Record { - fields: &[], - final_comments: env.arena.alloc([]), - } - })), Layout::Struct(field_layouts) => { let ptr_to_ast = |ptr: *const u8| match content { Content::Structure(FlatType::Record(fields, _)) => { @@ -247,7 +241,6 @@ fn jit_to_ast_help<'a>( Layout::Closure(_, _, _) => Err(ToAstProblem::FunctionLayout), Layout::FunctionPointer(_, _) => Err(ToAstProblem::FunctionLayout), - Layout::Pointer(_) => todo!("add support for rendering pointers in the REPL"), } } @@ -298,7 +291,7 @@ fn ptr_to_ast<'a>( items: &[], final_comments: &[], }, - Layout::Builtin(Builtin::List(_, elem_layout)) => { + Layout::Builtin(Builtin::List(elem_layout)) => { // Turn the (ptr, len) wrapper struct into actual ptr and len values. let len = unsafe { *(ptr.offset(env.ptr_bytes as isize) as *const usize) }; let ptr = unsafe { *(ptr as *const *const u8) }; diff --git a/compiler/builtins/build.rs b/compiler/builtins/build.rs index c157c1cef7..b6a4e41f14 100644 --- a/compiler/builtins/build.rs +++ b/compiler/builtins/build.rs @@ -32,7 +32,7 @@ fn main() { run_command(&bitcode_path, "zig", &["build", "ir", "-Drelease=true"]); - let dest_bc_path = Path::new(&out_dir).join("builtins.bc"); + let dest_bc_path = bitcode_path.join("builtins.bc"); let dest_bc = dest_bc_path.to_str().expect("Invalid dest bc path"); println!("Compiling bitcode to: {}", dest_bc); @@ -43,7 +43,6 @@ fn main() { ); println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rustc-env=BUILTINS_BC={}", dest_bc); println!("cargo:rustc-env=BUILTINS_O={}", dest_obj); get_zig_files(bitcode_path.as_path(), &|path| { let path: &Path = path; diff --git a/compiler/builtins/docs/Num.roc b/compiler/builtins/docs/Num.roc index 813fe34e23..419672c852 100644 --- a/compiler/builtins/docs/Num.roc +++ b/compiler/builtins/docs/Num.roc @@ -533,7 +533,10 @@ mul : Num range, Num range -> Num range ## Convert -## Convert a number to a string, formatted as the traditional base 10 (decimal). +## Convert a number to a [Str]. +## +## This is the same as calling `Num.format {}` - so for more details on +## exact formatting, see [Num.format]. ## ## >>> Num.toStr 42 ## @@ -546,6 +549,68 @@ mul : Num range, Num range -> Num range ## For other bases see #toHexStr, #toOctalStr, and #toBinaryStr. toStr : Num * -> Str +## Convert a number into a [Str], formatted with the given options. +## +## Default options: +## * `base: Decimal` +## * `notation: Standard` +## * `decimalMark: HideForIntegers "."` +## * `decimalDigits: { min: 0, max: All }` +## * `minIntDigits: 1` +## * `wholeSep: { mark: ",", places: 3 }` +## +## ## Options +## +## +## ### decimalMark +## +## * `AlwaysShow` always shows the decimal mark, no matter what. +## * `HideForIntegers` hides the decimal mark if all the numbers after the decimal mark are 0. +## +## The [Str] included in either of these represents the mark itself. +## +## ### `decimalDigits +## +## With 0 decimal digits, the decimal mark will still be rendered if +## `decimalMark` is set to `AlwaysShow`. +## +## If `max` is less than `min`, then first the number will be truncated to `max` +## digits, and then zeroes will be added afterwards until it reaches `min` digits. +## +## >>> Num.format 1.23 { decPlaces: 0, decPointVis: AlwaysShow } +## +## ### minIntDigits +## +## If the integer portion of number is fewer than this many digits, zeroes will +## be added in front of it until there are at least `minWholeDigits` digits. +## +## If this is set to zero, then numbers less than 1 will begin with `"."` +## rather than `"0."`. +## +## ### wholeSep +## +## Examples: +## +## In some countries (e.g. USA and UK), a comma is used to separate thousands: +## >>> Num.format 1_000_000 { base: Decimal, wholeSep: { mark: ",", places: 3 } } +## +## Sometimes when rendering bits, it's nice to group them into groups of 4: +## >>> Num.format 1_000_000 { base: Binary, wholeSep: { mark: " ", places: 4 } } +## +## It's also common to render hexadecimal in groups of 2: +## >>> Num.format 1_000_000 { base: Hexadecimal, wholeSep: { mark: " ", places: 2 } } +format : + Num *, + { + base ? [ Decimal, Hexadecimal, Octal, Binary ], + notation ? [ Standard, Scientific ], + decimalMark ? [ AlwaysShow Str, HideForIntegers ], + decimalDigits ? { min : U16, max : [ All, Trunc U16, Round U16, Floor U16, Ceil U16 ] }, + minWholeDigits ? U16, + wholeSep ? { mark : Str, places : U64 } + } + -> Str + ## Round off the given float to the nearest integer. round : Float * -> Int * ceil : Float * -> Int * diff --git a/compiler/builtins/docs/Str.roc b/compiler/builtins/docs/Str.roc index 4789db17b2..b8a216d514 100644 --- a/compiler/builtins/docs/Str.roc +++ b/compiler/builtins/docs/Str.roc @@ -429,16 +429,22 @@ chompCodePoint : Str, U32 -> Result Str [ Expected [ ExactCodePoint U32 ]* Str ] ## If the string begins with digits which can represent a valid #U8, return ## that number along with the rest of the string after the digits. -parseU8 : Str -> Result { val : U8, rest : Str } [ Expected [ NumU8 ]* Str ]* -parseI8 : Str -> Result { val : I8, rest : Str } [ Expected [ NumI8 ]* Str ]* -parseU16 : Str -> Result { val : U16, rest : Str } [ Expected [ NumU16 ]* Str ]* -parseI16 : Str -> Result { val : I16, rest : Str } [ Expected [ NumI16 ]* Str ]* -parseU32 : Str -> Result { val : U32, rest : Str } [ Expected [ NumU32 ]* Str ]* -parseI32 : Str -> Result { val : I32, rest : Str } [ Expected [ NumI32 ]* Str ]* -parseU64 : Str -> Result { val : U64, rest : Str } [ Expected [ NumU64 ]* Str ]* -parseI64 : Str -> Result { val : I64, rest : Str } [ Expected [ NumI64 ]* Str ]* -parseU128 : Str -> Result { val : U128, rest : Str } [ Expected [ NumU128 ]* Str ]* -parseI128 : Str -> Result { val : I128, rest : Str } [ Expected [ NumI128 ]* Str ]* +parseU8 : Str, NumFormat -> Result { val : U8, rest : Str } [ Expected [ NumU8 ]* Str ]* +parseI8 : Str, NumFormat -> Result { val : I8, rest : Str } [ Expected [ NumI8 ]* Str ]* +parseU16 : Str, NumFormat -> Result { val : U16, rest : Str } [ Expected [ NumU16 ]* Str ]* +parseI16 : Str, NumFormat -> Result { val : I16, rest : Str } [ Expected [ NumI16 ]* Str ]* +parseU32 : Str, NumFormat -> Result { val : U32, rest : Str } [ Expected [ NumU32 ]* Str ]* +parseI32 : Str, NumFormat -> Result { val : I32, rest : Str } [ Expected [ NumI32 ]* Str ]* +parseU64 : Str, NumFormat -> Result { val : U64, rest : Str } [ Expected [ NumU64 ]* Str ]* +parseI64 : Str, NumFormat -> Result { val : I64, rest : Str } [ Expected [ NumI64 ]* Str ]* +parseU128 : Str, NumFormat -> Result { val : U128, rest : Str } [ Expected [ NumU128 ]* Str ]* +parseI128 : Str, NumFormat -> Result { val : I128, rest : Str } [ Expected [ NumI128 ]* Str ]* -parseF64 : Str -> Result { val : U128, rest : Str } [ Expected [ NumF64 ]* Str ]* -parseF32 : Str -> Result { val : I128, rest : Str } [ Expected [ NumF32 ]* Str ]* +parseF64 : Str, NumFormat -> Result { val : U128, rest : Str } [ Expected [ NumF64 ]* Str ]* +parseF32 : Str, NumFormat -> Result { val : I128, rest : Str } [ Expected [ NumF32 ]* Str ]* + +## TODO make this similar to the Num.format argument +## except more flexible - e.g. the policy for whole number separators +## might be to allow them, to require them, or to allow them only every N digits +## (e.g. 3 for thousands, 4 for bits, 2 for hex) +NumFormat : { } diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index 732244d4ae..53cd979abb 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -1,26 +1,12 @@ -use std::fs::File; -use std::io::prelude::Read; -use std::vec::Vec; - -const BC_PATH: &str = env!( - "BUILTINS_BC", - "Env var BUILTINS_BC not found. Is there a problem with the build script?" -); - pub const OBJ_PATH: &str = env!( "BUILTINS_O", "Env var BUILTINS_O not found. Is there a problem with the build script?" ); -pub fn get_bytes() -> Vec { - // In the build script for the builtins module, we compile the builtins bitcode and set - // BUILTINS_BC to the path to the compiled output. - let mut builtins_bitcode = File::open(BC_PATH).expect("Unable to find builtins bitcode source"); - let mut buffer = Vec::new(); - builtins_bitcode - .read_to_end(&mut buffer) - .expect("Unable to read builtins bitcode"); - buffer +pub fn as_bytes() -> &'static [u8] { + // In the build script for the builtins module, + // we compile the builtins into LLVM bitcode + include_bytes!("../bitcode/builtins.bc") } pub const NUM_ASIN: &str = "roc_builtins.num.asin"; diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index c1a0006844..ed34bfc104 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -353,7 +353,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { } pub fn module_from_builtins<'ctx>(ctx: &'ctx Context, module_name: &str) -> Module<'ctx> { - let bitcode_bytes = bitcode::get_bytes(); + let bitcode_bytes = bitcode::as_bytes(); let memory_buffer = MemoryBuffer::create_from_memory_range(&bitcode_bytes, module_name); @@ -906,9 +906,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( arguments, tag_layout, .. - } if *union_size == 1 - && matches!(tag_layout, Layout::Union(UnionLayout::NonRecursive(_))) => - { + } if *union_size == 1 && matches!(tag_layout, UnionLayout::NonRecursive(_)) => { let it = arguments.iter(); let ctx = env.context; @@ -956,7 +954,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( Tag { arguments, - tag_layout: Layout::Union(UnionLayout::NonRecursive(fields)), + tag_layout: UnionLayout::NonRecursive(fields), union_size, tag_id, .. @@ -1044,7 +1042,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( } Tag { arguments, - tag_layout: Layout::Union(UnionLayout::Recursive(fields)), + tag_layout: UnionLayout::Recursive(fields), union_size, tag_id, .. @@ -1119,7 +1117,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( Tag { arguments, - tag_layout: Layout::Union(UnionLayout::NonNullableUnwrapped(fields)), + tag_layout: UnionLayout::NonNullableUnwrapped(fields), union_size, tag_id, .. @@ -1195,10 +1193,10 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( Tag { arguments, tag_layout: - Layout::Union(UnionLayout::NullableWrapped { + UnionLayout::NullableWrapped { nullable_id, other_tags: fields, - }), + }, union_size, tag_id, .. @@ -1287,11 +1285,11 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( Tag { arguments, tag_layout: - Layout::Union(UnionLayout::NullableUnwrapped { + UnionLayout::NullableUnwrapped { nullable_id, other_fields, .. - }), + }, union_size, tag_id, tag_name, @@ -1387,8 +1385,6 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( data_ptr.into() } - Tag { .. } => unreachable!("tags should have a Union or RecursiveUnion layout"), - Reset(_) => todo!(), Reuse { .. } => todo!(), @@ -2180,7 +2176,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( let (value, layout) = load_symbol_and_layout(scope, symbol); match layout { - Layout::Builtin(Builtin::List(_, _)) => { + Layout::Builtin(Builtin::List(_)) => { debug_assert!(value.is_struct_value()); // because of how we insert DECREF for lists, we can't guarantee that @@ -3360,11 +3356,9 @@ pub fn build_proc<'a, 'ctx, 'env>( } Layout::Builtin(_) => {} - Layout::PhantomEmptyStruct => {} Layout::Struct(_) => {} Layout::Union(_) => {} Layout::RecursivePointer => {} - Layout::Pointer(_) => {} } } } @@ -3587,7 +3581,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( match list_layout { Layout::Builtin(Builtin::EmptyList) => default, - Layout::Builtin(Builtin::List(_, element_layout)) => { + Layout::Builtin(Builtin::List(element_layout)) => { let argument_layouts = &[**element_layout, *default_layout]; let roc_function_call = roc_function_call( @@ -3629,8 +3623,8 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( match (list_layout, return_layout) { (Layout::Builtin(Builtin::EmptyList), _) => empty_list(env), ( - Layout::Builtin(Builtin::List(_, element_layout)), - Layout::Builtin(Builtin::List(_, result_layout)), + Layout::Builtin(Builtin::List(element_layout)), + Layout::Builtin(Builtin::List(result_layout)), ) => { let argument_layouts = &[**element_layout]; @@ -3660,9 +3654,9 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( match (list1_layout, list2_layout, return_layout) { ( - Layout::Builtin(Builtin::List(_, element1_layout)), - Layout::Builtin(Builtin::List(_, element2_layout)), - Layout::Builtin(Builtin::List(_, result_layout)), + Layout::Builtin(Builtin::List(element1_layout)), + Layout::Builtin(Builtin::List(element2_layout)), + Layout::Builtin(Builtin::List(result_layout)), ) => { let argument_layouts = &[**element1_layout, **element2_layout]; @@ -3704,10 +3698,10 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( match (list1_layout, list2_layout, list3_layout, return_layout) { ( - Layout::Builtin(Builtin::List(_, element1_layout)), - Layout::Builtin(Builtin::List(_, element2_layout)), - Layout::Builtin(Builtin::List(_, element3_layout)), - Layout::Builtin(Builtin::List(_, result_layout)), + Layout::Builtin(Builtin::List(element1_layout)), + Layout::Builtin(Builtin::List(element2_layout)), + Layout::Builtin(Builtin::List(element3_layout)), + Layout::Builtin(Builtin::List(result_layout)), ) => { let argument_layouts = &[**element1_layout, **element2_layout, **element3_layout]; @@ -3754,8 +3748,8 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( match (list_layout, return_layout) { (Layout::Builtin(Builtin::EmptyList), _) => empty_list(env), ( - Layout::Builtin(Builtin::List(_, element_layout)), - Layout::Builtin(Builtin::List(_, result_layout)), + Layout::Builtin(Builtin::List(element_layout)), + Layout::Builtin(Builtin::List(result_layout)), ) => { let argument_layouts = &[Layout::Builtin(Builtin::Usize), **element_layout]; @@ -3786,7 +3780,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( match list_layout { Layout::Builtin(Builtin::EmptyList) => empty_list(env), - Layout::Builtin(Builtin::List(_, element_layout)) => { + Layout::Builtin(Builtin::List(element_layout)) => { let argument_layouts = &[**element_layout]; let roc_function_call = roc_function_call( @@ -3818,8 +3812,8 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( (_, Layout::Builtin(Builtin::EmptyList)) | (Layout::Builtin(Builtin::EmptyList), _) => empty_list(env), ( - Layout::Builtin(Builtin::List(_, before_layout)), - Layout::Builtin(Builtin::List(_, after_layout)), + Layout::Builtin(Builtin::List(before_layout)), + Layout::Builtin(Builtin::List(after_layout)), ) => { let argument_layouts = &[**before_layout]; @@ -3862,8 +3856,8 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( (_, Layout::Builtin(Builtin::EmptyList)) | (Layout::Builtin(Builtin::EmptyList), _) => empty_list(env), ( - Layout::Builtin(Builtin::List(_, before_layout)), - Layout::Builtin(Builtin::List(_, after_layout)), + Layout::Builtin(Builtin::List(before_layout)), + Layout::Builtin(Builtin::List(after_layout)), ) => { let argument_layouts = &[**before_layout]; @@ -3913,7 +3907,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>( match list_layout { Layout::Builtin(Builtin::EmptyList) => empty_list(env), - Layout::Builtin(Builtin::List(_, element_layout)) => { + Layout::Builtin(Builtin::List(element_layout)) => { use crate::llvm::bitcode::build_compare_wrapper; let argument_layouts = &[**element_layout, **element_layout]; @@ -4181,7 +4175,7 @@ fn run_low_level<'a, 'ctx, 'env>( match list_layout { Layout::Builtin(Builtin::EmptyList) => empty_list(env), - Layout::Builtin(Builtin::List(_, element_layout)) => list_drop( + Layout::Builtin(Builtin::List(element_layout)) => list_drop( env, layout_ids, original_wrapper, @@ -4450,7 +4444,7 @@ fn run_low_level<'a, 'ctx, 'env>( // no elements, so nothing to remove empty_list(env) } - Layout::Builtin(Builtin::List(_, element_layout)) => list_set( + Layout::Builtin(Builtin::List(element_layout)) => list_set( env, layout_ids, list, @@ -4471,7 +4465,7 @@ fn run_low_level<'a, 'ctx, 'env>( // no elements, so nothing to remove empty_list(env) } - Layout::Builtin(Builtin::List(_, element_layout)) => list_set( + Layout::Builtin(Builtin::List(element_layout)) => list_set( env, layout_ids, list, @@ -4648,7 +4642,7 @@ fn run_low_level<'a, 'ctx, 'env>( match list_layout { Layout::Builtin(Builtin::EmptyList) => dict_empty(env), - Layout::Builtin(Builtin::List(_, key_layout)) => { + Layout::Builtin(Builtin::List(key_layout)) => { set_from_list(env, layout_ids, list, key_layout) } _ => unreachable!("invalid dict layout"), diff --git a/compiler/gen/src/llvm/build_hash.rs b/compiler/gen/src/llvm/build_hash.rs index 95db536a88..195ff1f30e 100644 --- a/compiler/gen/src/llvm/build_hash.rs +++ b/compiler/gen/src/llvm/build_hash.rs @@ -56,11 +56,6 @@ fn build_hash_layout<'a, 'ctx, 'env>( val.into_struct_value(), ), - Layout::PhantomEmptyStruct => { - // just does nothing and returns the seed - seed - } - Layout::Union(union_layout) => { build_hash_tag(env, layout_ids, layout, union_layout, seed, val) } @@ -91,10 +86,6 @@ fn build_hash_layout<'a, 'ctx, 'env>( } }, - Layout::Pointer(_) => { - unreachable!("unused") - } - Layout::FunctionPointer(_, _) | Layout::Closure(_, _, _) => { unreachable!("the type system will guarantee these are never hashed") } @@ -157,7 +148,7 @@ fn hash_builtin<'a, 'ctx, 'env>( Builtin::Set(_) => { todo!("Implement Hash for Set") } - Builtin::List(_, element_layout) => build_hash_list( + Builtin::List(element_layout) => build_hash_list( env, layout_ids, layout, diff --git a/compiler/gen/src/llvm/build_list.rs b/compiler/gen/src/llvm/build_list.rs index f71e4a507a..5a7fea02c9 100644 --- a/compiler/gen/src/llvm/build_list.rs +++ b/compiler/gen/src/llvm/build_list.rs @@ -14,7 +14,7 @@ use inkwell::types::{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, MemoryMode}; +use roc_mono::layout::{Builtin, InPlace, Layout, LayoutIds}; fn list_returned_from_zig<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, @@ -196,12 +196,12 @@ pub fn list_join<'a, 'ctx, 'env>( ) -> BasicValueEnum<'ctx> { match outer_list_layout { Layout::Builtin(Builtin::EmptyList) - | Layout::Builtin(Builtin::List(_, Layout::Builtin(Builtin::EmptyList))) => { + | Layout::Builtin(Builtin::List(Layout::Builtin(Builtin::EmptyList))) => { // If the input list is empty, or if it is a list of empty lists // then simply return an empty list empty_list(env) } - Layout::Builtin(Builtin::List(_, Layout::Builtin(Builtin::List(_, element_layout)))) => { + Layout::Builtin(Builtin::List(Layout::Builtin(Builtin::List(element_layout)))) => { call_bitcode_fn_returns_list( env, &[ @@ -231,13 +231,7 @@ pub fn list_reverse<'a, 'ctx, 'env>( // this pointer will never actually be dereferenced Layout::Builtin(Builtin::Int64), ), - Layout::Builtin(Builtin::List(memory_mode, elem_layout)) => ( - match memory_mode { - MemoryMode::Unique => InPlace::InPlace, - MemoryMode::Refcounted => InPlace::Clone, - }, - *elem_layout, - ), + Layout::Builtin(Builtin::List(elem_layout)) => (InPlace::Clone, *elem_layout), _ => unreachable!("Invalid layout {:?} in List.reverse", list_layout), }; @@ -264,7 +258,7 @@ pub fn list_get_unsafe<'a, 'ctx, 'env>( let builder = env.builder; match list_layout { - Layout::Builtin(Builtin::List(_, elem_layout)) => { + Layout::Builtin(Builtin::List(elem_layout)) => { let elem_type = basic_type_from_layout(env, elem_layout); let ptr_type = get_ptr_type(&elem_type, AddressSpace::Generic); // Load the pointer to the array data @@ -861,7 +855,7 @@ pub fn list_concat<'a, 'ctx, 'env>( // then simply return an empty list empty_list(env) } - Layout::Builtin(Builtin::List(_, elem_layout)) => call_bitcode_fn_returns_list( + Layout::Builtin(Builtin::List(elem_layout)) => call_bitcode_fn_returns_list( env, &[ pass_list_as_i128(env, first_list), diff --git a/compiler/gen/src/llvm/compare.rs b/compiler/gen/src/llvm/compare.rs index 0cf32263d0..7f9cf127dd 100644 --- a/compiler/gen/src/llvm/compare.rs +++ b/compiler/gen/src/llvm/compare.rs @@ -99,7 +99,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>( Builtin::Float16 => float_cmp(FloatPredicate::OEQ, "eq_f16"), Builtin::Str => str_equal(env, lhs_val, rhs_val), - Builtin::List(_, elem) => build_list_eq( + Builtin::List(elem) => build_list_eq( env, layout_ids, &Layout::Builtin(*builtin), @@ -159,11 +159,6 @@ fn build_eq<'a, 'ctx, 'env>( rhs_val, ), - Layout::PhantomEmptyStruct => { - // always equal to itself - env.context.bool_type().const_int(1, false).into() - } - Layout::RecursivePointer => match when_recursive { WhenRecursive::Unreachable => { unreachable!("recursion pointers should never be compared directly") @@ -197,10 +192,6 @@ fn build_eq<'a, 'ctx, 'env>( } }, - Layout::Pointer(_) => { - unreachable!("unused") - } - Layout::FunctionPointer(_, _) | Layout::Closure(_, _, _) => { unreachable!("the type system will guarantee these are never compared") } @@ -258,7 +249,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>( result.into() } - Builtin::List(_, elem) => { + Builtin::List(elem) => { let is_equal = build_list_eq( env, layout_ids, @@ -338,19 +329,10 @@ fn build_neq<'a, 'ctx, 'env>( result.into() } - Layout::PhantomEmptyStruct => { - // always equal to itself - env.context.bool_type().const_int(1, false).into() - } - Layout::RecursivePointer => { unreachable!("recursion pointers should never be compared directly") } - Layout::Pointer(_) => { - unreachable!("unused") - } - Layout::FunctionPointer(_, _) | Layout::Closure(_, _, _) => { unreachable!("the type system will guarantee these are never compared") } diff --git a/compiler/gen/src/llvm/convert.rs b/compiler/gen/src/llvm/convert.rs index 29e874c992..c88c12c18b 100644 --- a/compiler/gen/src/llvm/convert.rs +++ b/compiler/gen/src/llvm/convert.rs @@ -112,10 +112,6 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>( let closure_data_layout = closure_layout.runtime_representation(); basic_type_from_layout(env, &closure_data_layout) } - Pointer(layout) => basic_type_from_layout(env, &layout) - .ptr_type(AddressSpace::Generic) - .into(), - PhantomEmptyStruct => env.context.struct_type(&[], false).into(), Struct(sorted_fields) => basic_type_from_record(env, sorted_fields), Union(variant) => { use UnionLayout::*; @@ -174,7 +170,7 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>( Float16 => context.f16_type().as_basic_type_enum(), Dict(_, _) | EmptyDict => zig_dict_type(env).into(), Set(_) | EmptySet => zig_dict_type(env).into(), - List(_, _) | EmptyList => zig_list_type(env).into(), + List(_) | EmptyList => zig_list_type(env).into(), Str | EmptyStr => zig_str_type(env).into(), } } diff --git a/compiler/gen/src/llvm/refcounting.rs b/compiler/gen/src/llvm/refcounting.rs index cf0a254163..71c309f8b4 100644 --- a/compiler/gen/src/llvm/refcounting.rs +++ b/compiler/gen/src/llvm/refcounting.rs @@ -15,7 +15,7 @@ use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, Str use inkwell::{AddressSpace, IntPredicate}; use roc_module::symbol::Interns; use roc_module::symbol::Symbol; -use roc_mono::layout::{Builtin, Layout, LayoutIds, MemoryMode, UnionLayout}; +use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout}; pub const REFCOUNT_MAX: usize = 0_usize; @@ -469,21 +469,17 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( use Builtin::*; match builtin { - List(memory_mode, element_layout) => { - if let MemoryMode::Refcounted = memory_mode { - let function = modify_refcount_list( - env, - layout_ids, - mode, - when_recursive, - layout, - element_layout, - ); + List(element_layout) => { + let function = modify_refcount_list( + env, + layout_ids, + mode, + when_recursive, + layout, + element_layout, + ); - Some(function) - } else { - None - } + Some(function) } Set(element_layout) => { let key_layout = &Layout::Struct(&[]); @@ -724,8 +720,6 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( Some(function) } - PhantomEmptyStruct => None, - Layout::RecursivePointer => match when_recursive { WhenRecursive::Unreachable => { unreachable!("recursion pointers should never be hashed directly") @@ -746,7 +740,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( } }, - FunctionPointer(_, _) | Pointer(_) => None, + FunctionPointer(_, _) => None, } } @@ -1689,7 +1683,7 @@ pub fn refcount_offset<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, layout: &Layou let value_bytes = layout.stack_size(env.ptr_bytes) as u64; match layout { - Layout::Builtin(Builtin::List(_, _)) => env.ptr_bytes as u64, + Layout::Builtin(Builtin::List(_)) => env.ptr_bytes as u64, Layout::Builtin(Builtin::Str) => env.ptr_bytes as u64, Layout::RecursivePointer | Layout::Union(_) => env.ptr_bytes as u64, _ => (env.ptr_bytes as u64).max(value_bytes), diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index f4529c0ec5..f0a2e1921a 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -433,16 +433,6 @@ fn lowlevel_spec( } fn build_variant_types( - builder: &mut FuncDefBuilder, - layout: &Layout, -) -> Option>> { - match layout { - Layout::Union(union_layout) => Some(build_variant_types_help(builder, union_layout)), - _ => None, - } -} - -fn build_variant_types_help( builder: &mut FuncDefBuilder, union_layout: &UnionLayout, ) -> Result> { @@ -494,7 +484,7 @@ fn expr_spec( arguments, } => { let value_id = build_tuple_value(builder, env, block, arguments)?; - let variant_types = build_variant_types(builder, tag_layout).unwrap()?; + let variant_types = build_variant_types(builder, tag_layout)?; builder.add_make_union(block, &variant_types, *tag_id as u32, value_id) } Struct(fields) => build_tuple_value(builder, env, block, fields), @@ -587,16 +577,14 @@ fn layout_spec(builder: &mut FuncDefBuilder, layout: &Layout) -> Result match layout { Builtin(builtin) => builtin_spec(builder, builtin), - PhantomEmptyStruct => todo!(), Struct(fields) => build_tuple_type(builder, fields), Union(union_layout) => { - let variant_types = build_variant_types_help(builder, union_layout)?; + let variant_types = build_variant_types(builder, union_layout)?; builder.add_union_type(&variant_types) } RecursivePointer => todo!(), FunctionPointer(_, _) => todo!(), Closure(_, _, _) => todo!(), - Pointer(_) => todo!(), } } @@ -625,7 +613,7 @@ fn builtin_spec(builder: &mut FuncDefBuilder, builtin: &Builtin) -> Result { + List(element_layout) => { let element_type = layout_spec(builder, element_layout)?; let cell = builder.add_heap_cell_type(); diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index 3aa4a7f22d..565e9f7126 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -1101,7 +1101,13 @@ fn test_to_equality<'a>( cond_layout: &Layout<'a>, path: &[PathInstruction], test: Test<'a>, -) -> (StoresVec<'a>, Symbol, Symbol, Layout<'a>) { +) -> ( + StoresVec<'a>, + Symbol, + Symbol, + Layout<'a>, + Option>, +) { let (rhs_symbol, mut stores, _layout) = path_to_expr_help(env, cond_symbol, &path, *cond_layout); @@ -1148,6 +1154,11 @@ fn test_to_equality<'a>( lhs_symbol, rhs_symbol, Layout::Builtin(Builtin::Int64), + Some(ConstructorKnown::OnlyPass { + scrutinee: path_symbol, + layout: *cond_layout, + tag_id, + }), ) } Test::IsInt(test_int) => { @@ -1162,6 +1173,7 @@ fn test_to_equality<'a>( lhs_symbol, rhs_symbol, Layout::Builtin(Builtin::Int64), + None, ) } @@ -1177,6 +1189,7 @@ fn test_to_equality<'a>( lhs_symbol, rhs_symbol, Layout::Builtin(Builtin::Float64), + None, ) } @@ -1192,6 +1205,7 @@ fn test_to_equality<'a>( lhs_symbol, rhs_symbol, Layout::Builtin(Builtin::Int8), + None, ) } @@ -1205,6 +1219,7 @@ fn test_to_equality<'a>( lhs_symbol, rhs_symbol, Layout::Builtin(Builtin::Int1), + None, ) } @@ -1219,6 +1234,7 @@ fn test_to_equality<'a>( lhs_symbol, rhs_symbol, Layout::Builtin(Builtin::Str), + None, ) } @@ -1231,6 +1247,7 @@ type Tests<'a> = std::vec::Vec<( Symbol, Symbol, Layout<'a>, + Option>, )>; fn stores_and_condition<'a>( @@ -1239,7 +1256,7 @@ fn stores_and_condition<'a>( cond_layout: &Layout<'a>, test_chain: Vec<(Vec, Test<'a>)>, ) -> (Tests<'a>, Option<(Symbol, JoinPointId, Stmt<'a>)>) { - let mut tests = Vec::with_capacity(test_chain.len()); + let mut tests: Tests = Vec::with_capacity(test_chain.len()); let mut guard = None; @@ -1444,12 +1461,20 @@ fn compile_tests<'a>( cond = compile_guard(env, ret_layout, id, arena.alloc(stmt), fail, cond); } - for (new_stores, lhs, rhs, _layout) in tests.into_iter() { - cond = compile_test(env, ret_layout, new_stores, lhs, rhs, fail, cond); + for (new_stores, lhs, rhs, _layout, opt_constructor_info) in tests.into_iter() { + match opt_constructor_info { + None => { + cond = compile_test(env, ret_layout, new_stores, lhs, rhs, fail, cond); + } + Some(cinfo) => { + cond = compile_test_help(env, cinfo, ret_layout, new_stores, lhs, rhs, fail, cond); + } + } } cond } +#[derive(Debug)] enum ConstructorKnown<'a> { Both { scrutinee: Symbol, @@ -1571,7 +1596,7 @@ fn decide_to_branching<'a>( // use knowledge about constructors for optimization debug_assert_eq!(tests.len(), 1); - let (new_stores, lhs, rhs, _layout) = tests.into_iter().next().unwrap(); + let (new_stores, lhs, rhs, _layout, _cinfo) = tests.into_iter().next().unwrap(); compile_test_help( env, @@ -1681,12 +1706,33 @@ fn decide_to_branching<'a>( // We have learned more about the exact layout of the cond (based on the path) // but tests are still relative to the original cond symbol - let mut switch = Stmt::Switch { - cond_layout: inner_cond_layout, - cond_symbol: inner_cond_symbol, - branches: branches.into_bump_slice(), - default_branch: (default_branch_info, env.arena.alloc(default_branch)), - ret_layout, + let mut switch = if let Layout::Union(_) = inner_cond_layout { + let tag_id_symbol = env.unique_symbol(); + + let temp = Stmt::Switch { + cond_layout: Layout::TAG_SIZE, + cond_symbol: tag_id_symbol, + branches: branches.into_bump_slice(), + default_branch: (default_branch_info, env.arena.alloc(default_branch)), + ret_layout, + }; + + let expr = Expr::AccessAtIndex { + index: 0, + field_layouts: &[Layout::TAG_SIZE], + structure: inner_cond_symbol, + wrapped: Wrapped::MultiTagUnion, + }; + + Stmt::Let(tag_id_symbol, expr, Layout::TAG_SIZE, env.arena.alloc(temp)) + } else { + Stmt::Switch { + cond_layout: inner_cond_layout, + cond_symbol: inner_cond_symbol, + branches: branches.into_bump_slice(), + default_branch: (default_branch_info, env.arena.alloc(default_branch)), + ret_layout, + } }; for (symbol, layout, expr) in cond_stores_vec.into_iter().rev() { diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index cbf8649aaf..4bedd2dae6 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, MemoryMode, - UnionLayout, WrappedVariant, TAG_SIZE, + Builtin, ClosureRepresentation, LambdaSet, Layout, LayoutCache, LayoutProblem, UnionLayout, + WrappedVariant, TAG_SIZE, }; use bumpalo::collections::Vec; use bumpalo::Bump; @@ -916,7 +916,14 @@ impl<'a> BranchInfo<'a> { .append(", tag_id: ") .append(format!("{}", tag_id)) .append("} "), - _ => alloc.text(""), + + _ => { + if PRETTY_PRINT_IR_SYMBOLS { + alloc.text(" ") + } else { + alloc.text("") + } + } } } } @@ -1143,7 +1150,7 @@ pub enum Expr<'a> { Call(Call<'a>), Tag { - tag_layout: Layout<'a>, + tag_layout: UnionLayout<'a>, tag_name: TagName, tag_id: u8, union_size: u8, @@ -3364,10 +3371,7 @@ pub fn with_hole<'a>( Stmt::Let( assigned, expr, - Layout::Builtin(Builtin::List( - MemoryMode::Refcounted, - env.arena.alloc(elem_layout), - )), + Layout::Builtin(Builtin::List(env.arena.alloc(elem_layout))), hole, ) } @@ -3399,12 +3403,10 @@ pub fn with_hole<'a>( elems: arg_symbols, }; - let mode = MemoryMode::Refcounted; - let stmt = Stmt::Let( assigned, expr, - Layout::Builtin(Builtin::List(mode, env.arena.alloc(elem_layout))), + Layout::Builtin(Builtin::List(env.arena.alloc(elem_layout))), hole, ); @@ -4133,10 +4135,15 @@ fn construct_closure_data<'a>( tag_symbols.push(tag_id_symbol); tag_symbols.extend(symbols); + let tag_layout = match lambda_set.runtime_representation() { + Layout::Union(inner) => inner, + _ => unreachable!(), + }; + let expr1 = Expr::Literal(Literal::Int(tag_id as i128)); let expr2 = Expr::Tag { tag_id, - tag_layout: lambda_set.runtime_representation(), + tag_layout, union_size, tag_name, arguments: tag_symbols.into_bump_slice(), @@ -4298,17 +4305,17 @@ fn convert_tag_union<'a>( } debug_assert!(layouts.len() > 1); - let layout = Layout::Union(UnionLayout::Recursive(layouts.into_bump_slice())); + let union_layout = UnionLayout::Recursive(layouts.into_bump_slice()); let tag = Expr::Tag { - tag_layout: layout, + tag_layout: union_layout, tag_name, tag_id: tag_id as u8, union_size, arguments: field_symbols, }; - (tag, layout) + (tag, Layout::Union(union_layout)) } NonNullableUnwrapped { fields, @@ -4326,17 +4333,17 @@ fn convert_tag_union<'a>( temp.into_bump_slice() }; - let layout = Layout::Union(UnionLayout::NonNullableUnwrapped(fields)); + let union_layout = UnionLayout::NonNullableUnwrapped(fields); let tag = Expr::Tag { - tag_layout: layout, + tag_layout: union_layout, tag_name, tag_id: tag_id as u8, union_size, arguments: field_symbols, }; - (tag, layout) + (tag, Layout::Union(union_layout)) } NonRecursive { sorted_tag_layouts } => { let tag_id_symbol = env.unique_symbol(); @@ -4358,18 +4365,17 @@ fn convert_tag_union<'a>( layouts.push(arg_layouts); } - let layout = - Layout::Union(UnionLayout::NonRecursive(layouts.into_bump_slice())); + let union_layout = UnionLayout::NonRecursive(layouts.into_bump_slice()); let tag = Expr::Tag { - tag_layout: layout, + tag_layout: union_layout, tag_name, tag_id: tag_id as u8, union_size, arguments: field_symbols, }; - (tag, layout) + (tag, Layout::Union(union_layout)) } NullableWrapped { nullable_id, @@ -4395,20 +4401,20 @@ fn convert_tag_union<'a>( layouts.push(arg_layouts); } - let layout = Layout::Union(UnionLayout::NullableWrapped { + let union_layout = UnionLayout::NullableWrapped { nullable_id, other_tags: layouts.into_bump_slice(), - }); + }; let tag = Expr::Tag { - tag_layout: layout, + tag_layout: union_layout, tag_name, tag_id: tag_id as u8, union_size, arguments: field_symbols, }; - (tag, layout) + (tag, Layout::Union(union_layout)) } NullableUnwrapped { nullable_id, @@ -4430,20 +4436,20 @@ fn convert_tag_union<'a>( temp.into_bump_slice() }; - let layout = Layout::Union(UnionLayout::NullableUnwrapped { + let union_layout = UnionLayout::NullableUnwrapped { nullable_id, other_fields, - }); + }; let tag = Expr::Tag { - tag_layout: layout, + tag_layout: union_layout, tag_name, tag_id: tag_id as u8, union_size, arguments: field_symbols, }; - (tag, layout) + (tag, Layout::Union(union_layout)) } }; diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 37f8669418..e7af14e26e 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -16,6 +16,10 @@ const GENERATE_NULLABLE: bool = true; const DEFAULT_NUM_BUILTIN: Builtin<'_> = Builtin::Int64; pub const TAG_SIZE: Builtin<'_> = Builtin::Int64; +impl Layout<'_> { + pub const TAG_SIZE: Layout<'static> = Layout::Builtin(Builtin::Int64); +} + #[derive(Copy, Clone)] #[repr(u8)] pub enum InPlace { @@ -36,24 +40,19 @@ pub enum Layout<'a> { /// A layout that is empty (turns into the empty struct in LLVM IR /// but for our purposes, not zero-sized, so it does not get dropped from data structures /// this is important for closures that capture zero-sized values - PhantomEmptyStruct, Struct(&'a [Layout<'a>]), Union(UnionLayout<'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>), - Pointer(&'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(memory_mode, _)) => match memory_mode { - MemoryMode::Unique => InPlace::InPlace, - MemoryMode::Refcounted => InPlace::Clone, - }, + Layout::Builtin(Builtin::List(_)) => InPlace::Clone, Layout::Builtin(Builtin::EmptyStr) => InPlace::InPlace, Layout::Builtin(Builtin::Str) => InPlace::Clone, Layout::Builtin(Builtin::Int1) => InPlace::Clone, @@ -333,12 +332,6 @@ impl<'a> LambdaSet<'a> { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Copy)] -pub enum MemoryMode { - Unique, - Refcounted, -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Builtin<'a> { Int128, @@ -355,7 +348,7 @@ pub enum Builtin<'a> { Str, Dict(&'a Layout<'a>, &'a Layout<'a>), Set(&'a Layout<'a>), - List(MemoryMode, &'a Layout<'a>), + List(&'a Layout<'a>), EmptyStr, EmptyList, EmptyDict, @@ -479,7 +472,6 @@ impl<'a> Layout<'a> { match self { Builtin(builtin) => builtin.safe_to_memcpy(), - PhantomEmptyStruct => true, Struct(fields) => fields .iter() .all(|field_layout| field_layout.safe_to_memcpy()), @@ -504,10 +496,6 @@ impl<'a> Layout<'a> { true } Closure(_, closure_layout, _) => closure_layout.safe_to_memcpy(), - Pointer(_) => { - // We cannot memcpy pointers, because then we would have the same pointer in multiple places! - false - } RecursivePointer => { // We cannot memcpy pointers, because then we would have the same pointer in multiple places! false @@ -519,12 +507,7 @@ impl<'a> Layout<'a> { // For this calculation, we don't need an accurate // stack size, we just need to know whether it's zero, // so it's fine to use a pointer size of 1. - if let Layout::PhantomEmptyStruct = self { - false - } else { - // self.stack_size(1) == 0 - false - } + false } pub fn stack_size(&self, pointer_size: u32) -> u32 { @@ -532,7 +515,6 @@ impl<'a> Layout<'a> { match self { Builtin(builtin) => builtin.stack_size(pointer_size), - PhantomEmptyStruct => 0, Struct(fields) => { let mut sum = 0; @@ -566,7 +548,6 @@ impl<'a> Layout<'a> { Closure(_, lambda_set, _) => lambda_set.stack_size(pointer_size), FunctionPointer(_, _) => pointer_size, RecursivePointer => pointer_size, - Pointer(_) => pointer_size, } } @@ -596,10 +577,8 @@ impl<'a> Layout<'a> { } } Layout::Builtin(builtin) => builtin.alignment_bytes(pointer_size), - Layout::PhantomEmptyStruct => 0, Layout::RecursivePointer => pointer_size, Layout::FunctionPointer(_, _) => pointer_size, - Layout::Pointer(_) => pointer_size, Layout::Closure(_, captured, _) => { pointer_size.max(captured.alignment_bytes(pointer_size)) } @@ -622,7 +601,7 @@ impl<'a> Layout<'a> { RecursivePointer => true, - Builtin(List(MemoryMode::Refcounted, _)) | Builtin(Str) => true, + Builtin(List(_)) | Builtin(Str) => true, _ => false, } @@ -636,7 +615,6 @@ impl<'a> Layout<'a> { match self { Builtin(builtin) => builtin.is_refcounted(), - PhantomEmptyStruct => false, Struct(fields) => fields.iter().any(|f| f.contains_refcounted()), Union(variant) => { use UnionLayout::*; @@ -655,7 +633,7 @@ impl<'a> Layout<'a> { } RecursivePointer => true, Closure(_, closure_layout, _) => closure_layout.contains_refcounted(), - FunctionPointer(_, _) | Pointer(_) => false, + FunctionPointer(_, _) => false, } } @@ -669,7 +647,6 @@ impl<'a> Layout<'a> { match self { Builtin(builtin) => builtin.to_doc(alloc, parens), - PhantomEmptyStruct => alloc.text("{}"), Struct(fields) => { let fields_doc = fields.iter().map(|x| x.to_doc(alloc, parens)); @@ -702,7 +679,6 @@ impl<'a> Layout<'a> { .append(" |} -> ") .append(result.to_doc(alloc, Parens::InFunction)) } - Pointer(_) => todo!(), } } } @@ -874,7 +850,7 @@ impl<'a> Builtin<'a> { Str | EmptyStr => Builtin::STR_WORDS * pointer_size, Dict(_, _) | EmptyDict => Builtin::DICT_WORDS * pointer_size, Set(_) | EmptySet => Builtin::SET_WORDS * pointer_size, - List(_, _) | EmptyList => Builtin::LIST_WORDS * pointer_size, + List(_) | EmptyList => Builtin::LIST_WORDS * pointer_size, } } @@ -900,7 +876,7 @@ impl<'a> Builtin<'a> { Str | EmptyStr => pointer_size, Dict(_, _) | EmptyDict => pointer_size, Set(_) | EmptySet => pointer_size, - List(_, _) | EmptyList => pointer_size, + List(_) | EmptyList => pointer_size, } } @@ -910,7 +886,7 @@ impl<'a> Builtin<'a> { match self { Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Float128 | Float64 | Float32 | Float16 | EmptyStr | EmptyDict | EmptyList | EmptySet => true, - Str | Dict(_, _) | Set(_) | List(_, _) => false, + Str | Dict(_, _) | Set(_) | List(_) => false, } } @@ -921,10 +897,7 @@ impl<'a> Builtin<'a> { match self { Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Float128 | Float64 | Float32 | Float16 | EmptyStr | EmptyDict | EmptyList | EmptySet => false, - List(mode, element_layout) => match mode { - MemoryMode::Refcounted => true, - MemoryMode::Unique => element_layout.contains_refcounted(), - }, + List(_) => true, Str | Dict(_, _) | Set(_) => true, } @@ -957,7 +930,7 @@ impl<'a> Builtin<'a> { EmptySet => alloc.text("EmptySet"), Str => alloc.text("Str"), - List(_, layout) => alloc + List(layout) => alloc .text("List ") .append(layout.to_doc(alloc, Parens::InTypeParam)), Set(layout) => alloc @@ -1897,11 +1870,7 @@ pub fn list_layout_from_elem<'a>( _ => { let elem_layout = Layout::from_var(env, elem_var)?; - // This is a normal list. - Ok(Layout::Builtin(Builtin::List( - MemoryMode::Refcounted, - env.arena.alloc(elem_layout), - ))) + Ok(Layout::Builtin(Builtin::List(env.arena.alloc(elem_layout)))) } } } @@ -1967,7 +1936,7 @@ impl<'a> std::convert::TryFrom<&Layout<'a>> for ListLayout<'a> { fn try_from(value: &Layout<'a>) -> Result { match value { Layout::Builtin(Builtin::EmptyList) => Ok(ListLayout::EmptyList), - Layout::Builtin(Builtin::List(_, element)) => Ok(ListLayout::List(element)), + Layout::Builtin(Builtin::List(element)) => Ok(ListLayout::List(element)), _ => Err(()), } } diff --git a/examples/benchmarks/CFold.roc b/examples/benchmarks/CFold.roc index fc3468886c..85549cb4a2 100644 --- a/examples/benchmarks/CFold.roc +++ b/examples/benchmarks/CFold.roc @@ -81,9 +81,9 @@ constFolding = \e -> when Pair x1 x2 is Pair (Val a) (Val b) -> Val (a+b) - # Pair (Val a) (Add (Val b) x) -> Add (Val (a+b)) x + Pair (Val a) (Add (Val b) x) -> Add (Val (a+b)) x Pair (Val a) (Add x (Val b)) -> Add (Val (a+b)) x - Pair _ _ -> Add x1 x2 + Pair y1 y2 -> Add y1 y2 Mul e1 e2 -> x1 = constFolding e1 @@ -93,7 +93,7 @@ constFolding = \e -> Pair (Val a) (Val b) -> Val (a*b) Pair (Val a) (Mul (Val b) x) -> Mul (Val (a*b)) x Pair (Val a) (Mul x (Val b)) -> Mul (Val (a*b)) x - Pair _ _ -> Mul x1 x2 + Pair y1 y2 -> Add y1 y2 _ -> e