diff --git a/Cargo.lock b/Cargo.lock index 1ce9784ff3..0ceea578ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3273,7 +3273,6 @@ dependencies = [ "morphic_lib", "roc_collections", "roc_debug_flags", - "roc_intern", "roc_module", "roc_mono", ] @@ -3404,7 +3403,6 @@ dependencies = [ "roc_fmt", "roc_gen_llvm", "roc_glue", - "roc_intern", "roc_linker", "roc_load", "roc_module", @@ -3621,7 +3619,6 @@ dependencies = [ "roc_can", "roc_collections", "roc_error_macros", - "roc_intern", "roc_module", "roc_mono", "roc_parse", @@ -3647,7 +3644,6 @@ dependencies = [ "roc_collections", "roc_debug_flags", "roc_error_macros", - "roc_intern", "roc_module", "roc_mono", "roc_region", @@ -3665,7 +3661,6 @@ dependencies = [ "roc_builtins", "roc_collections", "roc_error_macros", - "roc_intern", "roc_module", "roc_mono", "roc_std", @@ -3689,7 +3684,6 @@ dependencies = [ "roc_can", "roc_collections", "roc_error_macros", - "roc_intern", "roc_load", "roc_module", "roc_mono", @@ -3718,14 +3712,6 @@ dependencies = [ name = "roc_ident" version = "0.0.1" -[[package]] -name = "roc_intern" -version = "0.0.1" -dependencies = [ - "parking_lot 0.12.1", - "roc_collections", -] - [[package]] name = "roc_late_solve" version = "0.0.1" @@ -3799,7 +3785,6 @@ dependencies = [ "roc_derive", "roc_derive_key", "roc_error_macros", - "roc_intern", "roc_late_solve", "roc_module", "roc_mono", @@ -3839,6 +3824,7 @@ dependencies = [ "bitvec 1.0.1", "bumpalo", "hashbrown 0.12.3", + "parking_lot 0.12.1", "roc_builtins", "roc_can", "roc_collections", @@ -3847,7 +3833,6 @@ dependencies = [ "roc_derive_key", "roc_error_macros", "roc_exhaustive", - "roc_intern", "roc_late_solve", "roc_module", "roc_problem", @@ -3928,7 +3913,6 @@ dependencies = [ "roc_builtins", "roc_collections", "roc_gen_llvm", - "roc_intern", "roc_load", "roc_module", "roc_mono", @@ -3954,7 +3938,6 @@ dependencies = [ "roc_can", "roc_collections", "roc_fmt", - "roc_intern", "roc_load", "roc_module", "roc_mono", @@ -3984,7 +3967,6 @@ dependencies = [ "roc_collections", "roc_error_macros", "roc_gen_llvm", - "roc_intern", "roc_load", "roc_module", "roc_mono", diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 7e68d415da..ddc7c62344 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -63,7 +63,6 @@ roc_editor = { path = "../editor", optional = true } roc_linker = { path = "../linker" } roc_repl_cli = { path = "../repl_cli", optional = true } roc_tracing = { path = "../tracing" } -roc_intern = { path = "../compiler/intern" } roc_gen_llvm = {path = "../compiler/gen_llvm"} roc_wasm_interp = { path = "../wasm_interp", optional = true } diff --git a/crates/compiler/alias_analysis/Cargo.toml b/crates/compiler/alias_analysis/Cargo.toml index 82e5f69671..3b2abd0000 100644 --- a/crates/compiler/alias_analysis/Cargo.toml +++ b/crates/compiler/alias_analysis/Cargo.toml @@ -8,7 +8,6 @@ version = "0.0.1" [dependencies] morphic_lib = {path = "../../vendor/morphic_lib"} roc_collections = {path = "../collections"} -roc_intern = {path = "../intern"} roc_module = {path = "../module"} roc_mono = {path = "../mono"} roc_debug_flags = {path = "../debug_flags"} diff --git a/crates/compiler/alias_analysis/src/lib.rs b/crates/compiler/alias_analysis/src/lib.rs index a47ff74445..000982887f 100644 --- a/crates/compiler/alias_analysis/src/lib.rs +++ b/crates/compiler/alias_analysis/src/lib.rs @@ -6,7 +6,6 @@ use morphic_lib::{ TypeDefBuilder, TypeId, TypeName, UpdateModeVar, ValueId, }; use roc_collections::all::{MutMap, MutSet}; -use roc_intern::Interner; use roc_module::low_level::LowLevel; use roc_module::symbol::Symbol; @@ -15,7 +14,8 @@ use roc_mono::ir::{ Literal, ModifyRc, OptLevel, Proc, ProcLayout, SingleEntryPoint, Stmt, }; use roc_mono::layout::{ - Builtin, FieldOrderHash, Layout, Niche, RawFunctionLayout, STLayoutInterner, UnionLayout, + Builtin, FieldOrderHash, Layout, LayoutInterner, Niche, RawFunctionLayout, STLayoutInterner, + UnionLayout, }; // just using one module for now diff --git a/crates/compiler/gen_dev/Cargo.toml b/crates/compiler/gen_dev/Cargo.toml index efb194e282..5225d9f3c5 100644 --- a/crates/compiler/gen_dev/Cargo.toml +++ b/crates/compiler/gen_dev/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" [dependencies] roc_collections = { path = "../collections" } -roc_intern = { path = "../intern" } roc_region = { path = "../region" } roc_module = { path = "../module" } roc_problem = { path = "../problem" } diff --git a/crates/compiler/gen_llvm/Cargo.toml b/crates/compiler/gen_llvm/Cargo.toml index 73e556cad0..af3bf91a16 100644 --- a/crates/compiler/gen_llvm/Cargo.toml +++ b/crates/compiler/gen_llvm/Cargo.toml @@ -9,7 +9,6 @@ edition = "2021" [dependencies] roc_alias_analysis = { path = "../alias_analysis" } roc_collections = { path = "../collections" } -roc_intern = { path = "../intern" } roc_module = { path = "../module" } roc_builtins = { path = "../builtins" } roc_error_macros = { path = "../../error_macros" } diff --git a/crates/compiler/gen_llvm/src/llvm/build.rs b/crates/compiler/gen_llvm/src/llvm/build.rs index a0b18f3b56..2431b17753 100644 --- a/crates/compiler/gen_llvm/src/llvm/build.rs +++ b/crates/compiler/gen_llvm/src/llvm/build.rs @@ -38,15 +38,14 @@ use roc_debug_flags::dbg_do; #[cfg(debug_assertions)] use roc_debug_flags::ROC_PRINT_LLVM_FN_VERIFICATION; use roc_error_macros::internal_error; -use roc_intern::Interner; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_mono::ir::{ BranchInfo, CallType, CrashTag, EntryPoint, JoinPointId, ListLiteralElement, ModifyRc, OptLevel, ProcLayout, SingleEntryPoint, }; use roc_mono::layout::{ - Builtin, LambdaName, LambdaSet, Layout, LayoutIds, Niche, RawFunctionLayout, STLayoutInterner, - TagIdIntType, UnionLayout, + Builtin, LambdaName, LambdaSet, Layout, LayoutIds, LayoutInterner, Niche, RawFunctionLayout, + STLayoutInterner, TagIdIntType, UnionLayout, }; use roc_std::RocDec; use roc_target::{PtrWidth, TargetInfo}; diff --git a/crates/compiler/gen_llvm/src/llvm/build_list.rs b/crates/compiler/gen_llvm/src/llvm/build_list.rs index 483ba10428..1d4f7f4180 100644 --- a/crates/compiler/gen_llvm/src/llvm/build_list.rs +++ b/crates/compiler/gen_llvm/src/llvm/build_list.rs @@ -10,9 +10,8 @@ use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, Str use inkwell::{AddressSpace, IntPredicate}; use morphic_lib::UpdateMode; use roc_builtins::bitcode; -use roc_intern::Interner; use roc_module::symbol::Symbol; -use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, STLayoutInterner}; +use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, LayoutInterner, STLayoutInterner}; use super::bitcode::{call_list_bitcode_fn, BitcodeReturns}; use super::build::{ diff --git a/crates/compiler/gen_llvm/src/llvm/compare.rs b/crates/compiler/gen_llvm/src/llvm/compare.rs index 0870c4f2ff..7ca474b719 100644 --- a/crates/compiler/gen_llvm/src/llvm/compare.rs +++ b/crates/compiler/gen_llvm/src/llvm/compare.rs @@ -12,9 +12,10 @@ use inkwell::values::{ use inkwell::{AddressSpace, FloatPredicate, IntPredicate}; use roc_builtins::bitcode; use roc_builtins::bitcode::{FloatWidth, IntWidth}; -use roc_intern::Interner; use roc_module::symbol::Symbol; -use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, STLayoutInterner, UnionLayout}; +use roc_mono::layout::{ + Builtin, InLayout, Layout, LayoutIds, LayoutInterner, STLayoutInterner, UnionLayout, +}; use super::build::{load_roc_value, use_roc_value, BuilderExt}; use super::convert::argument_type_from_union_layout; diff --git a/crates/compiler/gen_llvm/src/llvm/convert.rs b/crates/compiler/gen_llvm/src/llvm/convert.rs index 70d7a15fbd..869bef03d8 100644 --- a/crates/compiler/gen_llvm/src/llvm/convert.rs +++ b/crates/compiler/gen_llvm/src/llvm/convert.rs @@ -5,8 +5,9 @@ use inkwell::types::{BasicType, BasicTypeEnum, FloatType, IntType, StructType}; use inkwell::values::StructValue; use inkwell::AddressSpace; use roc_builtins::bitcode::{FloatWidth, IntWidth}; -use roc_intern::Interner; -use roc_mono::layout::{round_up_to_alignment, Builtin, Layout, STLayoutInterner, UnionLayout}; +use roc_mono::layout::{ + round_up_to_alignment, Builtin, Layout, LayoutInterner, STLayoutInterner, UnionLayout, +}; use roc_target::TargetInfo; fn basic_type_from_record<'a, 'ctx, 'env>( diff --git a/crates/compiler/gen_llvm/src/llvm/expect.rs b/crates/compiler/gen_llvm/src/llvm/expect.rs index 2fd769f482..4dc3f2cf3e 100644 --- a/crates/compiler/gen_llvm/src/llvm/expect.rs +++ b/crates/compiler/gen_llvm/src/llvm/expect.rs @@ -9,10 +9,9 @@ use inkwell::types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum}; use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue}; use inkwell::AddressSpace; use roc_builtins::bitcode; -use roc_intern::Interner; use roc_module::symbol::Symbol; use roc_mono::ir::LookupType; -use roc_mono::layout::{Builtin, Layout, LayoutIds, STLayoutInterner, UnionLayout}; +use roc_mono::layout::{Builtin, Layout, LayoutIds, LayoutInterner, STLayoutInterner, UnionLayout}; use roc_region::all::Region; use super::build::BuilderExt; diff --git a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs index 25941b6fc6..63bf733840 100644 --- a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs +++ b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs @@ -9,11 +9,10 @@ use inkwell::{ use morphic_lib::{FuncSpec, UpdateMode}; use roc_builtins::bitcode::{self, FloatWidth, IntWidth}; use roc_error_macros::internal_error; -use roc_intern::Interner; use roc_module::{low_level::LowLevel, symbol::Symbol}; use roc_mono::{ ir::HigherOrderLowLevel, - layout::{Builtin, LambdaSet, Layout, LayoutIds, STLayoutInterner}, + layout::{Builtin, LambdaSet, Layout, LayoutIds, LayoutInterner, STLayoutInterner}, }; use roc_target::PtrWidth; diff --git a/crates/compiler/gen_llvm/src/llvm/refcounting.rs b/crates/compiler/gen_llvm/src/llvm/refcounting.rs index 6425e91ee2..ba05daeb40 100644 --- a/crates/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/crates/compiler/gen_llvm/src/llvm/refcounting.rs @@ -15,10 +15,11 @@ use inkwell::values::{ BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue, }; use inkwell::{AddressSpace, IntPredicate}; -use roc_intern::Interner; use roc_module::symbol::Interns; use roc_module::symbol::Symbol; -use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, STLayoutInterner, UnionLayout}; +use roc_mono::layout::{ + Builtin, InLayout, Layout, LayoutIds, LayoutInterner, STLayoutInterner, UnionLayout, +}; use super::build::{cast_if_necessary_for_opaque_recursive_pointers, load_roc_value, FunctionSpec}; use super::convert::{argument_type_from_layout, argument_type_from_union_layout}; diff --git a/crates/compiler/gen_wasm/Cargo.toml b/crates/compiler/gen_wasm/Cargo.toml index f3b487ead9..b96de60b50 100644 --- a/crates/compiler/gen_wasm/Cargo.toml +++ b/crates/compiler/gen_wasm/Cargo.toml @@ -9,7 +9,6 @@ description = "Provides the WASM backend to generate Roc binaries." [dependencies] roc_builtins = { path = "../builtins" } roc_collections = { path = "../collections" } -roc_intern = { path = "../intern" } roc_module = { path = "../module" } roc_mono = { path = "../mono" } roc_target = { path = "../roc_target" } diff --git a/crates/compiler/gen_wasm/src/backend.rs b/crates/compiler/gen_wasm/src/backend.rs index a236ed2bdd..4c39e79b54 100644 --- a/crates/compiler/gen_wasm/src/backend.rs +++ b/crates/compiler/gen_wasm/src/backend.rs @@ -4,7 +4,6 @@ use bumpalo::collections::{String, Vec}; use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_collections::all::MutMap; use roc_error_macros::internal_error; -use roc_intern::Interner; use roc_module::low_level::{LowLevel, LowLevelWrapperType}; use roc_module::symbol::{Interns, Symbol}; use roc_mono::code_gen_help::{CodeGenHelp, HelperOp, REFCOUNT_MAX}; @@ -12,7 +11,9 @@ use roc_mono::ir::{ BranchInfo, CallType, CrashTag, Expr, JoinPointId, ListLiteralElement, Literal, ModifyRc, Param, Proc, ProcLayout, Stmt, }; -use roc_mono::layout::{Builtin, Layout, LayoutIds, STLayoutInterner, TagIdIntType, UnionLayout}; +use roc_mono::layout::{ + Builtin, Layout, LayoutIds, LayoutInterner, STLayoutInterner, TagIdIntType, UnionLayout, +}; use roc_std::RocDec; use roc_wasm_module::linking::{DataSymbol, WasmObjectSymbol}; diff --git a/crates/compiler/gen_wasm/src/low_level.rs b/crates/compiler/gen_wasm/src/low_level.rs index d1e0d02caf..c1c93a8491 100644 --- a/crates/compiler/gen_wasm/src/low_level.rs +++ b/crates/compiler/gen_wasm/src/low_level.rs @@ -2,12 +2,11 @@ use bumpalo::collections::Vec; use bumpalo::Bump; use roc_builtins::bitcode::{self, FloatWidth, IntWidth}; use roc_error_macros::internal_error; -use roc_intern::Interner; use roc_module::low_level::LowLevel; use roc_module::symbol::Symbol; use roc_mono::code_gen_help::HelperOp; use roc_mono::ir::{HigherOrderLowLevel, PassedFunction, ProcLayout}; -use roc_mono::layout::{Builtin, FieldOrderHash, InLayout, Layout, UnionLayout}; +use roc_mono::layout::{Builtin, FieldOrderHash, InLayout, Layout, LayoutInterner, UnionLayout}; use roc_mono::low_level::HigherOrder; use crate::backend::{ProcLookupData, ProcSource, WasmBackend}; diff --git a/crates/compiler/intern/Cargo.toml b/crates/compiler/intern/Cargo.toml deleted file mode 100644 index 2d9623d0e2..0000000000 --- a/crates/compiler/intern/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "roc_intern" -version = "0.0.1" -authors = ["The Roc Contributors"] -license = "UPL-1.0" -edition = "2021" -description = "Provides generic interners for concurrent and single-thread use cases." - -[dependencies] -roc_collections = { path = "../collections" } -parking_lot = "0.12" diff --git a/crates/compiler/intern/src/lib.rs b/crates/compiler/intern/src/lib.rs deleted file mode 100644 index c7640233d3..0000000000 --- a/crates/compiler/intern/src/lib.rs +++ /dev/null @@ -1,253 +0,0 @@ -//! Generic interners for concurrent and single-thread use cases. - -use std::{ - cell::RefCell, - hash::{BuildHasher, Hash, Hasher}, - marker::PhantomData, - sync::Arc, -}; - -use parking_lot::{Mutex, RwLock}; -use roc_collections::{default_hasher, BumpMap}; - -/// An interned value. -/// -/// When possible, prefer comparing/hashing on the [Interned] representation of a value, rather -/// than the value itself. -#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Interned(usize, std::marker::PhantomData); -impl Clone for Interned { - fn clone(&self) -> Self { - Self(self.0, Default::default()) - } -} - -impl Copy for Interned {} - -impl Interned { - /// # Safety - /// - /// The index is not guaranteed to exist. Use this only when creating an interner with constant - /// indices, with the variant that `insert` returns a monotonically increasing index. - /// - /// For example: - /// - /// ```ignore(illustrative) - /// let reserved_interned = Interned::from_reserved_index(0); - /// let interner = GlobalInterner::with_capacity(1); - /// let inserted = interner.insert("something"); - /// assert_eq!(reserved_interned, inserted); - /// ``` - pub const unsafe fn from_reserved_index(index: usize) -> Self { - Self(index, PhantomData) - } -} - -/// A concurrent interner, suitable for usage between threads. -/// -/// The interner does not currently maintain its own arena; you will have to supply -/// values-to-be-interned as allocated in an independent arena. -/// -/// If you need a concurrent global interner, you'll likely want each thread to take a -/// [ThreadLocalInterner] via [GlobalInterner::fork], for caching purposes. -/// -/// Originally derived from https://gist.github.com/matklad/44ba1a5a6168bc0c26c995131c007907; -/// thank you, Aleksey! -#[derive(Debug)] -pub struct GlobalInterner<'a, K> { - map: Mutex>>, - vec: RwLock>, -} - -/// A derivative of a [GlobalInterner] interner that provides caching desirable for -/// thread-local workloads. The only way to get a [ThreadLocalInterner] is via -/// [GlobalInterner::fork]. -/// -/// All values interned into a [ThreadLocalInterner] are made available in its parent -/// [GlobalInterner], making this suitable for global sharing of interned values. -/// -/// Originally derived from https://gist.github.com/matklad/44ba1a5a6168bc0c26c995131c007907; -/// thank you, Aleksey! -#[derive(Debug)] -pub struct ThreadLocalInterner<'a, K> { - parent: Arc>, - map: BumpMap<&'a K, Interned>, - /// Cache of interned values from the parent for local access. - vec: RefCell>>, -} - -/// A single-threaded interner, with no concurrency properties. -/// -/// The only way to construct such an interner is to collapse a shared [GlobalInterner] into -/// a [SingleThreadedInterner], via [GlobalInterner::unwrap]. -#[derive(Debug)] -pub struct SingleThreadedInterner<'a, K> { - map: BumpMap<&'a K, Interned>, - vec: Vec<&'a K>, -} - -/// Generic hasher for a value, to be used by all interners. -/// -/// This uses the [default_hasher], so interner maps should also rely on [default_hasher]. -fn hash(val: V) -> u64 { - let mut state = roc_collections::all::BuildHasher::default().build_hasher(); - val.hash(&mut state); - state.finish() -} - -pub trait Interner<'a, K: Hash + Eq> { - /// Interns a value, returning its interned representation. - /// If the value has been interned before, the old interned representation will be re-used. - /// - /// Note that the provided value must be allocated into an arena of your choosing, but which - /// must live at least as long as the interner lives. - // TODO: we should consider maintaining our own arena in the interner, to avoid redundant - // allocations when values already have interned representations. - fn insert(&mut self, value: &'a K) -> Interned; - - /// Retrieves a value from the interner. - fn get(&self, key: Interned) -> &'a K; -} - -impl<'a, K: Hash + Eq> GlobalInterner<'a, K> { - /// Creates a new global interner with the given capacity. - pub fn with_capacity(cap: usize) -> Arc> { - let map: BumpMap<&'a K, Interned> = - BumpMap::with_capacity_and_hasher(cap, default_hasher()); - - Arc::new(GlobalInterner { - map: Mutex::new(map), - vec: RwLock::new(Vec::with_capacity(cap)), - }) - } - - /// Creates a derivative [ThreadLocalInterner] pointing back to this global interner. - pub fn fork(self: &Arc>) -> ThreadLocalInterner<'a, K> { - ThreadLocalInterner { - parent: Arc::clone(self), - map: Default::default(), - vec: Default::default(), - } - } - - /// Collapses a shared [GlobalInterner] into a [SingleThreadedInterner]. - /// - /// Returns an [Err] with `self` if there are outstanding references to the [GlobalInterner]. - pub fn unwrap( - self: Arc>, - ) -> Result, Arc> { - let GlobalInterner { map, vec } = Arc::try_unwrap(self)?; - let map = Mutex::into_inner(map); - let vec = RwLock::into_inner(vec); - Ok(SingleThreadedInterner { map, vec }) - } - - /// Interns a value with a pre-computed hash. - /// Prefer calling this when possible, especially from [ThreadLocalInterner], to avoid - /// re-computing hashes. - fn insert_hashed(&self, value: &'a K, hash: u64) -> Interned { - let mut map = self.map.lock(); - let (_, interned) = map - .raw_entry_mut() - .from_key_hashed_nocheck(hash, &value) - .or_insert_with(|| { - let mut vec = self.vec.write(); - let interned = Interned(vec.len(), Default::default()); - vec.push(value); - (value, interned) - }); - *interned - } - - fn get(&self, interned: Interned) -> &'a K { - let Interned(index, _) = interned; - self.vec.read()[index] - } - - pub fn is_empty(&self) -> bool { - self.vec.read().is_empty() - } -} - -impl<'a, K: Hash + Eq> ThreadLocalInterner<'a, K> { - /// Records an interned value in thread-specific storage, for faster access on lookups. - fn record(&self, key: &'a K, interned: Interned) { - let mut vec = self.vec.borrow_mut(); - let len = vec.len().max(interned.0 + 1); - vec.resize(len, None); - vec[interned.0] = Some(key); - } -} - -impl<'a, K: Hash + Eq> Interner<'a, K> for ThreadLocalInterner<'a, K> { - fn insert(&mut self, value: &'a K) -> Interned { - let global = &*self.parent; - let hash = hash(value); - let (&mut value, &mut interned) = self - .map - .raw_entry_mut() - .from_key_hashed_nocheck(hash, &value) - .or_insert_with(|| { - let interned = global.insert_hashed(value, hash); - (value, interned) - }); - self.record(value, interned); - interned - } - - fn get(&self, key: Interned) -> &'a K { - if let Some(Some(value)) = self.vec.borrow().get(key.0) { - return value; - } - let value = self.parent.get(key); - self.record(value, key); - value - } -} - -impl<'a, K> SingleThreadedInterner<'a, K> { - /// Creates a new single threaded interner with the given capacity. - pub fn with_capacity(cap: usize) -> Self { - Self { - map: BumpMap::with_capacity_and_hasher(cap, default_hasher()), - vec: Vec::with_capacity(cap), - } - } - - /// Promotes the [SingleThreadedInterner] back to a [GlobalInterner]. - /// - /// You should *only* use this if you need to go from a single-threaded to a concurrent context, - /// or in a case where you explicitly need access to [ThreadLocalInterner]s. - pub fn into_global(self) -> Arc> { - let SingleThreadedInterner { map, vec } = self; - Arc::new(GlobalInterner { - map: Mutex::new(map), - vec: RwLock::new(vec), - }) - } - - pub fn is_empty(&self) -> bool { - self.vec.is_empty() - } -} - -impl<'a, K: Hash + Eq> Interner<'a, K> for SingleThreadedInterner<'a, K> { - fn insert(&mut self, value: &'a K) -> Interned { - let hash = hash(value); - let (_, interned) = self - .map - .raw_entry_mut() - .from_key_hashed_nocheck(hash, value) - .or_insert_with(|| { - let interned = Interned(self.vec.len(), Default::default()); - self.vec.push(value); - (value, interned) - }); - *interned - } - - fn get(&self, key: Interned) -> &'a K { - let Interned(index, _) = key; - self.vec[index] - } -} diff --git a/crates/compiler/load_internal/Cargo.toml b/crates/compiler/load_internal/Cargo.toml index 2e2a6f147f..a52d997f93 100644 --- a/crates/compiler/load_internal/Cargo.toml +++ b/crates/compiler/load_internal/Cargo.toml @@ -24,7 +24,6 @@ roc_solve = { path = "../solve" } roc_solve_problem = { path = "../solve_problem" } roc_late_solve = { path = "../late_solve" } roc_mono = { path = "../mono" } -roc_intern = { path = "../intern" } roc_target = { path = "../roc_target" } roc_tracing = { path = "../../tracing" } roc_packaging = { path = "../../packaging" } diff --git a/crates/compiler/mono/Cargo.toml b/crates/compiler/mono/Cargo.toml index 86dbabe0dd..73ce78d7a0 100644 --- a/crates/compiler/mono/Cargo.toml +++ b/crates/compiler/mono/Cargo.toml @@ -15,7 +15,6 @@ roc_types = { path = "../types" } roc_can = { path = "../can" } roc_derive_key = { path = "../derive_key" } roc_derive = { path = "../derive" } -roc_intern = { path = "../intern" } roc_late_solve = { path = "../late_solve" } roc_std = { path = "../../roc_std" } roc_problem = { path = "../problem" } @@ -30,3 +29,4 @@ bumpalo.workspace = true hashbrown.workspace = true static_assertions.workspace = true bitvec.workspace = true +parking_lot.workspace = true diff --git a/crates/compiler/mono/src/code_gen_help/equality.rs b/crates/compiler/mono/src/code_gen_help/equality.rs index 7c6cb5ff14..0cca077512 100644 --- a/crates/compiler/mono/src/code_gen_help/equality.rs +++ b/crates/compiler/mono/src/code_gen_help/equality.rs @@ -1,12 +1,13 @@ use bumpalo::collections::vec::Vec; -use roc_intern::Interner; use roc_module::low_level::LowLevel; use roc_module::symbol::{IdentIds, Symbol}; use crate::ir::{ BranchInfo, Call, CallType, Expr, JoinPointId, Literal, Param, Stmt, UpdateModeId, }; -use crate::layout::{Builtin, InLayout, Layout, STLayoutInterner, TagIdIntType, UnionLayout}; +use crate::layout::{ + Builtin, InLayout, Layout, LayoutInterner, STLayoutInterner, TagIdIntType, UnionLayout, +}; use super::{let_lowlevel, CodeGenHelp, Context, LAYOUT_BOOL}; diff --git a/crates/compiler/mono/src/code_gen_help/mod.rs b/crates/compiler/mono/src/code_gen_help/mod.rs index a0c43a8988..35f49d2e7b 100644 --- a/crates/compiler/mono/src/code_gen_help/mod.rs +++ b/crates/compiler/mono/src/code_gen_help/mod.rs @@ -1,6 +1,5 @@ use bumpalo::collections::vec::Vec; use bumpalo::Bump; -use roc_intern::Interner; use roc_module::low_level::LowLevel; use roc_module::symbol::{IdentIds, ModuleId, Symbol}; use roc_target::TargetInfo; @@ -9,7 +8,9 @@ use crate::ir::{ Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout, SelfRecursive, Stmt, UpdateModeId, }; -use crate::layout::{Builtin, LambdaName, Layout, Niche, STLayoutInterner, UnionLayout}; +use crate::layout::{ + Builtin, LambdaName, Layout, LayoutInterner, Niche, STLayoutInterner, UnionLayout, +}; mod equality; mod refcount; diff --git a/crates/compiler/mono/src/code_gen_help/refcount.rs b/crates/compiler/mono/src/code_gen_help/refcount.rs index 701d146014..897fb863fc 100644 --- a/crates/compiler/mono/src/code_gen_help/refcount.rs +++ b/crates/compiler/mono/src/code_gen_help/refcount.rs @@ -2,7 +2,6 @@ use bumpalo::collections::vec::Vec; use roc_builtins::bitcode::IntWidth; -use roc_intern::Interner; use roc_module::low_level::{LowLevel, LowLevel::*}; use roc_module::symbol::{IdentIds, Symbol}; use roc_target::PtrWidth; diff --git a/crates/compiler/mono/src/debug/checker.rs b/crates/compiler/mono/src/debug/checker.rs index dfaa98336b..e6823bb8b4 100644 --- a/crates/compiler/mono/src/debug/checker.rs +++ b/crates/compiler/mono/src/debug/checker.rs @@ -2,7 +2,6 @@ use bumpalo::Bump; use roc_collections::{MutMap, VecMap, VecSet}; -use roc_intern::Interner; use roc_module::symbol::Symbol; use crate::{ @@ -10,7 +9,9 @@ use crate::{ Call, CallSpecId, CallType, Expr, HigherOrderLowLevel, JoinPointId, ListLiteralElement, ModifyRc, Param, Proc, ProcLayout, Stmt, }, - layout::{Builtin, LambdaSet, Layout, STLayoutInterner, TagIdIntType, UnionLayout}, + layout::{ + Builtin, LambdaSet, Layout, LayoutInterner, STLayoutInterner, TagIdIntType, UnionLayout, + }, }; pub enum UseKind { diff --git a/crates/compiler/mono/src/decision_tree.rs b/crates/compiler/mono/src/decision_tree.rs index 0b9f692a65..4c60bc57e1 100644 --- a/crates/compiler/mono/src/decision_tree.rs +++ b/crates/compiler/mono/src/decision_tree.rs @@ -2,12 +2,13 @@ use crate::ir::{ build_list_index_probe, BranchInfo, Call, CallType, DestructType, Env, Expr, JoinPointId, ListIndex, Literal, Param, Pattern, Procs, Stmt, }; -use crate::layout::{Builtin, Layout, LayoutCache, TLLayoutInterner, TagIdIntType, UnionLayout}; +use crate::layout::{ + Builtin, Layout, LayoutCache, LayoutInterner, TLLayoutInterner, TagIdIntType, UnionLayout, +}; use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_collections::all::{MutMap, MutSet}; use roc_error_macros::internal_error; use roc_exhaustive::{Ctor, CtorName, ListArity, RenderAs, TagId, Union}; -use roc_intern::Interner; use roc_module::ident::TagName; use roc_module::low_level::LowLevel; use roc_module::symbol::Symbol; diff --git a/crates/compiler/mono/src/layout.rs b/crates/compiler/mono/src/layout.rs index 64dcd19484..2591320706 100644 --- a/crates/compiler/mono/src/layout.rs +++ b/crates/compiler/mono/src/layout.rs @@ -5,7 +5,6 @@ use bumpalo::Bump; use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_collections::all::{default_hasher, FnvMap, MutMap}; use roc_error_macros::{internal_error, todo_abilities}; -use roc_intern::Interner; use roc_module::ident::{Lowercase, TagName}; use roc_module::symbol::{Interns, Symbol}; use roc_problem::can::RuntimeError; @@ -23,7 +22,9 @@ use std::hash::{Hash, Hasher}; use ven_pretty::{DocAllocator, DocBuilder}; mod intern; -pub use intern::{GlobalLayoutInterner, LayoutInterner, STLayoutInterner, TLLayoutInterner}; +pub use intern::{ + GlobalLayoutInterner, InLayout, LayoutInterner, STLayoutInterner, TLLayoutInterner, +}; // if your changes cause this number to go down, great! // please change it to the lower number. @@ -661,10 +662,6 @@ impl FieldOrderHash { } } -/// An interned layout. -// One day I would like to take over `LayoutId` as the name here, but that is currently used elsewhere. -pub type InLayout<'a> = roc_intern::Interned>; - /// Types for code gen must be monomorphic. No type variables allowed! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum Layout<'a> { diff --git a/crates/compiler/mono/src/layout/intern.rs b/crates/compiler/mono/src/layout/intern.rs index d7b6d28b7d..4881e96bd7 100644 --- a/crates/compiler/mono/src/layout/intern.rs +++ b/crates/compiler/mono/src/layout/intern.rs @@ -1,25 +1,33 @@ -use std::{marker::PhantomData, sync::Arc}; +use std::{ + cell::RefCell, + hash::{BuildHasher, Hasher}, + marker::PhantomData, + sync::Arc, +}; +use parking_lot::{Mutex, RwLock}; use roc_builtins::bitcode::{FloatWidth, IntWidth}; -use roc_intern::{GlobalInterner, Interned, Interner, SingleThreadedInterner, ThreadLocalInterner}; +use roc_collections::{default_hasher, BumpMap}; use roc_target::TargetInfo; use super::{Builtin, Layout}; -pub struct InternedLayouts(PhantomData<()>); +#[allow(unused)] // for now +pub struct InLayouts(PhantomData<()>); macro_rules! cache_interned_layouts { ($($i:literal, $name:ident, $layout:expr)*; $total_constants:literal) => { - impl InternedLayouts { + impl InLayouts { $( - pub const $name: Interned> = unsafe { Interned::from_reserved_index($i) }; + #[allow(unused)] // for now + pub const $name: InLayout<'static> = unsafe { InLayout::from_reserved_index($i) }; )* } fn fill_reserved_layouts<'a>(interner: &mut STLayoutInterner<'a>) { - assert!(interner.0.is_empty()); + assert!(interner.is_empty()); $( - interner.0.insert(&$layout); + interner.insert(&$layout); )* } @@ -59,8 +67,9 @@ cache_interned_layouts! { ; 16 } -impl InternedLayouts { - pub const fn from_int_width(w: IntWidth) -> Interned> { +impl InLayouts { + #[allow(unused)] // for now + pub const fn from_int_width(w: IntWidth) -> InLayout<'static> { match w { IntWidth::U8 => Self::U8, IntWidth::U16 => Self::U16, @@ -74,7 +83,8 @@ impl InternedLayouts { IntWidth::I128 => Self::I128, } } - pub const fn from_float_width(w: FloatWidth) -> Interned> { + #[allow(unused)] // for now + pub const fn from_float_width(w: FloatWidth) -> InLayout<'static> { match w { FloatWidth::F32 => Self::F32, FloatWidth::F64 => Self::F64, @@ -82,63 +92,248 @@ impl InternedLayouts { } } -pub trait LayoutInterner<'a>: Interner<'a, Layout<'a>> + Sized { - fn alignment_bytes(&self, target_info: TargetInfo, layout: Interned>) -> u32 { +pub trait LayoutInterner<'a>: Sized { + /// Interns a value, returning its interned representation. + /// If the value has been interned before, the old interned representation will be re-used. + /// + /// Note that the provided value must be allocated into an arena of your choosing, but which + /// must live at least as long as the interner lives. + // TODO: we should consider maintaining our own arena in the interner, to avoid redundant + // allocations when values already have interned representations. + fn insert(&mut self, value: &'a Layout<'a>) -> InLayout<'a>; + + /// Retrieves a value from the interner. + fn get(&self, key: InLayout<'a>) -> &'a Layout<'a>; + + fn alignment_bytes(&self, target_info: TargetInfo, layout: InLayout<'a>) -> u32 { self.get(layout).alignment_bytes(self, target_info) } } +/// An interned layout. +/// +/// When possible, prefer comparing/hashing on the [InLayout] representation of a value, rather +/// than the value itself. +#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct InLayout<'a>(usize, std::marker::PhantomData<&'a ()>); +impl<'a> Clone for InLayout<'a> { + fn clone(&self) -> Self { + Self(self.0, Default::default()) + } +} + +impl<'a> Copy for InLayout<'a> {} + +impl<'a> InLayout<'a> { + /// # Safety + /// + /// The index is not guaranteed to exist. Use this only when creating an interner with constant + /// indices, with the variant that `insert` returns a monotonically increasing index. + /// + /// For example: + /// + /// ```ignore(illustrative) + /// let reserved_interned = InLayout::from_reserved_index(0); + /// let interner = GlobalLayoutInterner::with_capacity(1); + /// let inserted = interner.insert("something"); + /// assert_eq!(reserved_interned, inserted); + /// ``` + const unsafe fn from_reserved_index(index: usize) -> Self { + Self(index, PhantomData) + } +} + +/// A concurrent interner, suitable for usage between threads. +/// +/// The interner does not currently maintain its own arena; you will have to supply +/// values-to-be-interned as allocated in an independent arena. +/// +/// If you need a concurrent global interner, you'll likely want each thread to take a +/// [TLLayoutInterner] via [GlobalLayoutInterner::fork], for caching purposes. +/// +/// Originally derived from https://gist.github.com/matklad/44ba1a5a6168bc0c26c995131c007907; +/// thank you, Aleksey! #[derive(Debug)] -pub struct GlobalLayoutInterner<'a>(Arc>>); +pub struct GlobalLayoutInterner<'a>(Arc>); + #[derive(Debug)] -pub struct TLLayoutInterner<'a>(ThreadLocalInterner<'a, Layout<'a>>); +struct GlobalLayoutInternerInner<'a> { + map: Mutex, InLayout<'a>>>, + vec: RwLock>>, +} + +/// A derivative of a [GlobalLayoutInterner] interner that provides caching desirable for +/// thread-local workloads. The only way to get a [TLLayoutInterner] is via +/// [GlobalLayoutInterner::fork]. +/// +/// All values interned into a [TLLayoutInterner] are made available in its parent +/// [GlobalLayoutInterner], making this suitable for global sharing of interned values. +/// +/// Originally derived from https://gist.github.com/matklad/44ba1a5a6168bc0c26c995131c007907; +/// thank you, Aleksey! #[derive(Debug)] -pub struct STLayoutInterner<'a>(SingleThreadedInterner<'a, Layout<'a>>); +pub struct TLLayoutInterner<'a> { + parent: GlobalLayoutInterner<'a>, + map: BumpMap<&'a Layout<'a>, InLayout<'a>>, + /// Cache of interned values from the parent for local access. + vec: RefCell>>>, +} + +/// A single-threaded interner, with no concurrency properties. +/// +/// The only way to construct such an interner is to collapse a shared [GlobalLayoutInterner] into +/// a [STLayoutInterner], via [GlobalLayoutInterner::unwrap]. +#[derive(Debug)] +pub struct STLayoutInterner<'a> { + map: BumpMap<&'a Layout<'a>, InLayout<'a>>, + vec: Vec<&'a Layout<'a>>, +} + +/// Generic hasher for a value, to be used by all interners. +/// +/// This uses the [default_hasher], so interner maps should also rely on [default_hasher]. +fn hash(val: V) -> u64 { + let mut state = roc_collections::all::BuildHasher::default().build_hasher(); + val.hash(&mut state); + state.finish() +} impl<'a> GlobalLayoutInterner<'a> { - pub fn with_capacity(capacity: usize) -> Self { - STLayoutInterner::with_capacity(capacity).into_global() + /// Creates a new global interner with the given capacity. + pub fn with_capacity(cap: usize) -> Self { + STLayoutInterner::with_capacity(cap).into_global() } + + /// Creates a derivative [TLLayoutInterner] pointing back to this global interner. pub fn fork(&self) -> TLLayoutInterner<'a> { - TLLayoutInterner(self.0.fork()) - } - pub fn unwrap(self) -> Result, Self> { - match self.0.unwrap() { - Ok(st) => Ok(STLayoutInterner(st)), - Err(global) => Err(Self(global)), + TLLayoutInterner { + parent: Self(Arc::clone(&self.0)), + map: Default::default(), + vec: Default::default(), } } + + /// Collapses a shared [GlobalLayoutInterner] into a [STLayoutInterner]. + /// + /// Returns an [Err] with `self` if there are outstanding references to the [GlobalLayoutInterner]. + pub fn unwrap(self) -> Result, Self> { + let GlobalLayoutInternerInner { map, vec } = match Arc::try_unwrap(self.0) { + Ok(inner) => inner, + Err(li) => return Err(Self(li)), + }; + let map = Mutex::into_inner(map); + let vec = RwLock::into_inner(vec); + Ok(STLayoutInterner { map, vec }) + } + + /// Interns a value with a pre-computed hash. + /// Prefer calling this when possible, especially from [TLLayoutInterner], to avoid + /// re-computing hashes. + fn insert_hashed(&self, value: &'a Layout<'a>, hash: u64) -> InLayout<'a> { + let mut map = self.0.map.lock(); + let (_, interned) = map + .raw_entry_mut() + .from_key_hashed_nocheck(hash, &value) + .or_insert_with(|| { + let mut vec = self.0.vec.write(); + let interned = InLayout(vec.len(), Default::default()); + vec.push(value); + (value, interned) + }); + *interned + } + + fn get(&self, interned: InLayout<'a>) -> &'a Layout<'a> { + let InLayout(index, _) = interned; + self.0.vec.read()[index] + } + + pub fn is_empty(&self) -> bool { + self.0.vec.read().is_empty() + } +} + +impl<'a> TLLayoutInterner<'a> { + /// Records an interned value in thread-specific storage, for faster access on lookups. + fn record(&self, key: &'a Layout<'a>, interned: InLayout<'a>) { + let mut vec = self.vec.borrow_mut(); + let len = vec.len().max(interned.0 + 1); + vec.resize(len, None); + vec[interned.0] = Some(key); + } +} + +impl<'a> LayoutInterner<'a> for TLLayoutInterner<'a> { + fn insert(&mut self, value: &'a Layout<'a>) -> InLayout<'a> { + let global = &self.parent; + let hash = hash(value); + let (&mut value, &mut interned) = self + .map + .raw_entry_mut() + .from_key_hashed_nocheck(hash, &value) + .or_insert_with(|| { + let interned = global.insert_hashed(value, hash); + (value, interned) + }); + self.record(value, interned); + interned + } + + fn get(&self, key: InLayout<'a>) -> &'a Layout<'a> { + if let Some(Some(value)) = self.vec.borrow().get(key.0) { + return value; + } + let value = self.parent.get(key); + self.record(value, key); + value + } } impl<'a> STLayoutInterner<'a> { - pub fn with_capacity(capacity: usize) -> Self { - let mut interner = Self(SingleThreadedInterner::with_capacity(capacity)); + /// Creates a new single threaded interner with the given capacity. + pub fn with_capacity(cap: usize) -> Self { + let mut interner = Self { + map: BumpMap::with_capacity_and_hasher(cap, default_hasher()), + vec: Vec::with_capacity(cap), + }; fill_reserved_layouts(&mut interner); interner } + + /// Promotes the [STLayoutInterner] back to a [GlobalLayoutInterner]. + /// + /// You should *only* use this if you need to go from a single-threaded to a concurrent context, + /// or in a case where you explicitly need access to [TLLayoutInterner]s. pub fn into_global(self) -> GlobalLayoutInterner<'a> { - GlobalLayoutInterner(self.0.into_global()) + let STLayoutInterner { map, vec } = self; + GlobalLayoutInterner(Arc::new(GlobalLayoutInternerInner { + map: Mutex::new(map), + vec: RwLock::new(vec), + })) + } + + pub fn is_empty(&self) -> bool { + self.vec.is_empty() } } -impl<'a> Interner<'a, Layout<'a>> for TLLayoutInterner<'a> { - fn insert(&mut self, value: &'a Layout<'a>) -> Interned> { - self.0.insert(value) +impl<'a> LayoutInterner<'a> for STLayoutInterner<'a> { + fn insert(&mut self, value: &'a Layout<'a>) -> InLayout<'a> { + let hash = hash(value); + let (_, interned) = self + .map + .raw_entry_mut() + .from_key_hashed_nocheck(hash, value) + .or_insert_with(|| { + let interned = InLayout(self.vec.len(), Default::default()); + self.vec.push(value); + (value, interned) + }); + *interned } - fn get(&self, key: Interned>) -> &'a Layout<'a> { - self.0.get(key) + fn get(&self, key: InLayout<'a>) -> &'a Layout<'a> { + let InLayout(index, _) = key; + self.vec[index] } } -impl<'a> LayoutInterner<'a> for TLLayoutInterner<'a> {} - -impl<'a> Interner<'a, Layout<'a>> for STLayoutInterner<'a> { - fn insert(&mut self, value: &'a Layout<'a>) -> Interned> { - self.0.insert(value) - } - - fn get(&self, key: Interned>) -> &'a Layout<'a> { - self.0.get(key) - } -} -impl<'a> LayoutInterner<'a> for STLayoutInterner<'a> {} diff --git a/crates/glue/Cargo.toml b/crates/glue/Cargo.toml index 4b750ef0b9..90564f6864 100644 --- a/crates/glue/Cargo.toml +++ b/crates/glue/Cargo.toml @@ -9,7 +9,6 @@ description = "Generates code needed for platform hosts to communicate with Roc [dependencies] roc_std = { path = "../roc_std"} roc_can = { path = "../compiler/can" } -roc_intern = { path = "../compiler/intern" } roc_mono = { path = "../compiler/mono" } roc_load = { path = "../compiler/load" } roc_reporting = { path = "../reporting" } diff --git a/crates/repl_cli/Cargo.toml b/crates/repl_cli/Cargo.toml index 7425e6bcd3..518953831a 100644 --- a/crates/repl_cli/Cargo.toml +++ b/crates/repl_cli/Cargo.toml @@ -29,7 +29,6 @@ roc_build = {path = "../compiler/build"} roc_builtins = {path = "../compiler/builtins"} roc_collections = {path = "../compiler/collections"} roc_gen_llvm = {path = "../compiler/gen_llvm"} -roc_intern = {path = "../compiler/intern"} roc_load = {path = "../compiler/load"} roc_mono = {path = "../compiler/mono"} roc_parse = {path = "../compiler/parse"} diff --git a/crates/repl_eval/Cargo.toml b/crates/repl_eval/Cargo.toml index d98083b459..d1ffdf93a1 100644 --- a/crates/repl_eval/Cargo.toml +++ b/crates/repl_eval/Cargo.toml @@ -15,7 +15,6 @@ roc_builtins = {path = "../compiler/builtins"} roc_can = {path = "../compiler/can"} roc_collections = {path = "../compiler/collections"} roc_fmt = {path = "../compiler/fmt"} -roc_intern = {path = "../compiler/intern"} roc_load = {path = "../compiler/load"} roc_module = {path = "../compiler/module"} roc_mono = {path = "../compiler/mono"} diff --git a/crates/repl_eval/src/eval.rs b/crates/repl_eval/src/eval.rs index 6346f1c7d9..65b952acc6 100644 --- a/crates/repl_eval/src/eval.rs +++ b/crates/repl_eval/src/eval.rs @@ -1,6 +1,5 @@ use bumpalo::collections::Vec; use bumpalo::Bump; -use roc_intern::Interner; use roc_types::types::AliasKind; use std::cmp::{max_by_key, min_by_key}; @@ -11,8 +10,8 @@ use roc_module::ident::TagName; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_mono::ir::ProcLayout; use roc_mono::layout::{ - self, union_sorted_tags_pub, Builtin, InLayout, Layout, LayoutCache, TLLayoutInterner, - UnionLayout, UnionVariant, WrappedVariant, + self, union_sorted_tags_pub, Builtin, InLayout, Layout, LayoutCache, LayoutInterner, + TLLayoutInterner, UnionLayout, UnionVariant, WrappedVariant, }; use roc_parse::ast::{AssignedField, Collection, Expr, Pattern, StrLiteral}; use roc_region::all::{Loc, Region}; diff --git a/crates/repl_expect/Cargo.toml b/crates/repl_expect/Cargo.toml index 760de2913c..bae087b61c 100644 --- a/crates/repl_expect/Cargo.toml +++ b/crates/repl_expect/Cargo.toml @@ -17,7 +17,6 @@ inkwell.workspace = true roc_builtins = {path = "../compiler/builtins"} roc_can = {path = "../compiler/can"} roc_collections = {path = "../compiler/collections"} -roc_intern = {path = "../compiler/intern"} roc_load = {path = "../compiler/load"} roc_mono = {path = "../compiler/mono"} roc_parse = {path = "../compiler/parse"}