From f72a63edbb6d84243614b97b7effb558b656ccaf Mon Sep 17 00:00:00 2001 From: rvcas Date: Sat, 28 Nov 2020 15:42:29 -0500 Subject: [PATCH] feat: build a map of package qualified module names --- compiler/load/src/file.rs | 89 +++++++++++++++++++++++++++++------ compiler/module/src/ident.rs | 5 ++ compiler/module/src/symbol.rs | 73 +++++++++++++++++++++++++++- 3 files changed, 150 insertions(+), 17 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 0175e0bb77..ddc3cb3dc7 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -13,8 +13,8 @@ use roc_constrain::module::{ constrain_imports, pre_constrain_imports, ConstrainableImports, Import, }; use roc_constrain::module::{constrain_module, ExposedModuleTypes, SubsByModule}; -use roc_module::ident::{Ident, Lowercase, ModuleName, TagName}; -use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, Symbol}; +use roc_module::ident::{Ident, Lowercase, ModuleName, QualifiedModuleName, TagName}; +use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, PackageModuleIds, Symbol}; use roc_mono::ir::{ CapturedSymbols, ExternalSpecializations, PartialProc, PendingSpecialization, Proc, Procs, }; @@ -346,6 +346,7 @@ fn start_phase<'a>(module_id: ModuleId, phase: Phase, state: &mut State<'a>) -> // Provide mutexes of ModuleIds and IdentIds by module, // so other modules can populate them as they load. module_ids: Arc::clone(&state.arc_modules), + package_module_ids: Arc::clone(&state.arc_package_modules), ident_ids_by_module: Arc::clone(&state.ident_ids_by_module), mode: state.stdlib.mode, } @@ -690,6 +691,7 @@ struct State<'a> { /// From now on, these will be used by multiple threads; time to make an Arc>! pub arc_modules: Arc>, + pub arc_package_modules: Arc>>, pub ident_ids_by_module: Arc>>, @@ -819,6 +821,7 @@ enum BuildTask<'a> { LoadModule { module_name: ModuleName, module_ids: Arc>, + package_module_ids: Arc>>, ident_ids_by_module: Arc>>, mode: Mode, }, @@ -989,6 +992,7 @@ pub fn load_and_monomorphize_from_str<'a>( struct LoadStart<'a> { pub arc_modules: Arc>, + pub arc_package_modules: Arc>>, pub ident_ids_by_module: Arc>>, pub root_id: ModuleId, pub root_msg: Msg<'a>, @@ -1001,6 +1005,7 @@ impl<'a> LoadStart<'a> { mode: Mode, ) -> Result { let arc_modules = Arc::new(Mutex::new(ModuleIds::default())); + let arc_package_modules = Arc::new(Mutex::new(PackageModuleIds::default())); let root_exposed_ident_ids = IdentIds::exposed_builtins(0); let ident_ids_by_module = Arc::new(Mutex::new(root_exposed_ident_ids)); @@ -1012,6 +1017,7 @@ impl<'a> LoadStart<'a> { arena, filename, Arc::clone(&arc_modules), + Arc::clone(&arc_package_modules), Arc::clone(&ident_ids_by_module), root_start_time, mode, @@ -1020,6 +1026,7 @@ impl<'a> LoadStart<'a> { Ok(LoadStart { arc_modules, + arc_package_modules, ident_ids_by_module, root_id, root_msg, @@ -1033,6 +1040,7 @@ impl<'a> LoadStart<'a> { mode: Mode, ) -> Result { let arc_modules = Arc::new(Mutex::new(ModuleIds::default())); + let arc_package_modules = Arc::new(Mutex::new(PackageModuleIds::default())); let root_exposed_ident_ids = IdentIds::exposed_builtins(0); let ident_ids_by_module = Arc::new(Mutex::new(root_exposed_ident_ids)); @@ -1045,6 +1053,7 @@ impl<'a> LoadStart<'a> { filename, src, Arc::clone(&arc_modules), + Arc::clone(&arc_package_modules), Arc::clone(&ident_ids_by_module), root_start_time, mode, @@ -1053,6 +1062,7 @@ impl<'a> LoadStart<'a> { Ok(LoadStart { arc_modules, + arc_package_modules, ident_ids_by_module, root_id, root_msg, @@ -1121,6 +1131,7 @@ where { let LoadStart { arc_modules, + arc_package_modules, ident_ids_by_module, root_id, root_msg, @@ -1256,6 +1267,7 @@ where headers_parsed, loading_started, arc_modules, + arc_package_modules, constrained_ident_ids: IdentIds::exposed_builtins(0), ident_ids_by_module, declarations_by_id: MutMap::default(), @@ -1913,6 +1925,7 @@ fn load_module<'a>( src_dir: &Path, module_name: ModuleName, module_ids: Arc>, + package_module_ids: Arc>>, ident_ids_by_module: Arc>>, mode: Mode, ) -> Result<(ModuleId, Msg<'a>), LoadingProblem> { @@ -1933,6 +1946,7 @@ fn load_module<'a>( arena, filename, module_ids, + package_module_ids, ident_ids_by_module, module_start_time, mode, @@ -1971,6 +1985,7 @@ fn parse_header<'a>( read_file_duration: Duration, filename: PathBuf, module_ids: Arc>, + package_module_ids: Arc>>, ident_ids_by_module: Arc>>, mode: Mode, src_bytes: &'a [u8], @@ -1998,6 +2013,7 @@ fn parse_header<'a>( header.imports.into_bump_slice(), parse_state, module_ids, + package_module_ids, ident_ids_by_module, module_timing, )), @@ -2015,6 +2031,7 @@ fn parse_header<'a>( header.imports.into_bump_slice(), parse_state, module_ids.clone(), + package_module_ids, ident_ids_by_module.clone(), module_timing, ); @@ -2059,6 +2076,7 @@ fn load_filename<'a>( arena: &'a Bump, filename: PathBuf, module_ids: Arc>, + package_module_ids: Arc>>, ident_ids_by_module: Arc>>, module_start_time: SystemTime, mode: Mode, @@ -2073,6 +2091,7 @@ fn load_filename<'a>( file_io_duration, filename, module_ids, + package_module_ids, ident_ids_by_module, mode, arena.alloc(bytes), @@ -2092,6 +2111,7 @@ fn load_from_str<'a>( filename: PathBuf, src: &'a str, module_ids: Arc>, + package_module_ids: Arc>>, ident_ids_by_module: Arc>>, module_start_time: SystemTime, mode: Mode, @@ -2104,6 +2124,7 @@ fn load_from_str<'a>( file_io_duration, filename, module_ids, + package_module_ids, ident_ids_by_module, mode, src.as_bytes(), @@ -2126,6 +2147,7 @@ fn send_header<'a>( imports: &'a [Located>], parse_state: parser::State<'a>, module_ids: Arc>, + package_module_ids: Arc>>, ident_ids_by_module: Arc>>, module_timing: ModuleTiming, ) -> (ModuleId, Msg<'a>) { @@ -2141,16 +2163,18 @@ fn send_header<'a>( } }; - let mut imported: Vec<(ModuleName, Vec, Region)> = Vec::with_capacity(imports.len()); + let mut imported: Vec<(QualifiedModuleName, Vec, Region)> = + Vec::with_capacity(imports.len()); let mut imported_modules: MutSet = MutSet::default(); + let mut imported_package_modules: MutSet = MutSet::default(); let mut scope_size = 0; for loc_entry in imports { - let (module_name, exposed) = exposed_from_import(&loc_entry.value); + let (qualified_module_name, exposed) = exposed_from_import(&loc_entry.value); scope_size += exposed.len(); - imported.push((module_name, exposed, loc_entry.region)); + imported.push((qualified_module_name, exposed, loc_entry.region)); } let num_exposes = exposes.len(); @@ -2167,6 +2191,7 @@ fn send_header<'a>( let ident_ids = { // Lock just long enough to perform the minimal operations necessary. let mut module_ids = (*module_ids).lock(); + let mut package_module_ids = (*package_module_ids).lock(); let mut ident_ids_by_module = (*ident_ids_by_module).lock(); home = module_ids.get_or_insert(&declared_name.as_inline_str()); @@ -2178,16 +2203,30 @@ fn send_header<'a>( // For each of our imports, add an entry to deps_by_name // - // e.g. for `imports [ Foo.{ bar } ]`, add `Foo` to deps_by_name + // e.g. for `imports [ base.Foo.{ bar } ]`, add `Foo` to deps_by_name // // Also build a list of imported_values_to_expose (like `bar` above.) - for (module_name, exposed_idents, region) in imported.into_iter() { - let cloned_module_name = module_name.clone(); - let module_id = module_ids.get_or_insert(&module_name.into()); + for (qualified_module_name, exposed_idents, region) in imported.into_iter() { + let cloned_module_name = qualified_module_name.module.clone(); + let module_id = match qualified_module_name.opt_package { + None => { + let id = module_ids.get_or_insert(&qualified_module_name.module.into()); - deps_by_name.insert(cloned_module_name, module_id); + imported_modules.insert(id); - imported_modules.insert(module_id); + deps_by_name.insert(cloned_module_name, id); + + id + } + Some(package) => { + let id = + package_module_ids.get_or_insert(&(package, cloned_module_name.into())); + + imported_package_modules.insert(id); + + id + } + }; // Add the new exposed idents to the dep module's IdentIds, so // once that module later gets loaded, its lookups will resolve @@ -2236,6 +2275,8 @@ fn send_header<'a>( ident_ids.clone() }; + dbg!(package_module_ids); + // Send the deps to the coordinator thread for processing, // then continue on to parsing and canonicalizing defs. // @@ -2782,7 +2823,7 @@ fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result, Loadi Ok(Msg::Parsed(parsed)) } -fn exposed_from_import(entry: &ImportsEntry<'_>) -> (ModuleName, Vec) { +fn exposed_from_import<'a>(entry: &ImportsEntry<'a>) -> (QualifiedModuleName<'a>, Vec) { use roc_parse::header::ImportsEntry::*; match entry { @@ -2793,11 +2834,27 @@ fn exposed_from_import(entry: &ImportsEntry<'_>) -> (ModuleName, Vec) { exposed.push(ident_from_exposed(&loc_entry.value)); } - (module_name.as_str().into(), exposed) + let qualified_module_name = QualifiedModuleName { + opt_package: None, + module: module_name.as_str().into(), + }; + + (qualified_module_name, exposed) } - Package(_package_name, _module_name, _exposes) => { - todo!("TODO support exposing package-qualified module names."); + Package(package_name, module_name, exposes) => { + let mut exposed = Vec::with_capacity(exposes.len()); + + for loc_entry in exposes { + exposed.push(ident_from_exposed(&loc_entry.value)); + } + + let qualified_module_name = QualifiedModuleName { + opt_package: Some(package_name), + module: module_name.as_str().into(), + }; + + (qualified_module_name, exposed) } SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => { @@ -3074,6 +3131,7 @@ fn run_task<'a>( LoadModule { module_name, module_ids, + package_module_ids, ident_ids_by_module, mode, } => load_module( @@ -3081,6 +3139,7 @@ fn run_task<'a>( src_dir, module_name, module_ids, + package_module_ids, ident_ids_by_module, mode, ) diff --git a/compiler/module/src/ident.rs b/compiler/module/src/ident.rs index f3bcb53561..438fa88060 100644 --- a/compiler/module/src/ident.rs +++ b/compiler/module/src/ident.rs @@ -12,6 +12,11 @@ impl Ident { } } +pub struct QualifiedModuleName<'a> { + pub opt_package: Option<&'a str>, + pub module: ModuleName, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct ModuleName(InlinableString); diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 44fd48637f..c8c9b3cd67 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -310,14 +310,71 @@ impl fmt::Debug for ModuleId { } } -/// Stores a mapping between ModuleId and InlinableString. -/// /// base.Task /// 1. build mapping from short name to package /// 2. when adding new modules from package we need to register them in some other map (this module id goes with short name) (shortname, module-name) -> moduleId /// 3. pass this around to other modules getting headers parsed. when parsing interfaces we need to use this map to reference shortnames /// 4. throw away short names. stash the module id in the can env under the resolved module name /// 5. test: + +type PackageModule<'a> = (&'a str, InlinableString); + +#[derive(Debug, Clone)] +pub struct PackageModuleIds<'a> { + by_name: MutMap, ModuleId>, + by_id: Vec>, +} + +impl<'a> PackageModuleIds<'a> { + pub fn get_or_insert(&mut self, module_name: &PackageModule<'a>) -> ModuleId { + match self.by_name.get(module_name) { + Some(id) => *id, + None => { + let by_id = &mut self.by_id; + let module_id = ModuleId(by_id.len() as u32); + + by_id.push(module_name.clone()); + + self.by_name.insert(module_name.clone(), module_id); + + if cfg!(debug_assertions) { + Self::insert_debug_name(module_id, &module_name); + } + + module_id + } + } + } + + #[cfg(debug_assertions)] + fn insert_debug_name(module_id: ModuleId, module_name: &PackageModule) { + let mut names = DEBUG_MODULE_ID_NAMES.lock().expect("Failed to acquire lock for Debug interning into DEBUG_MODULE_ID_NAMES, presumably because a thread panicked."); + + let (_package, module) = module_name; + + names.insert(module_id.0, module.to_string().into()); + } + + #[cfg(not(debug_assertions))] + fn insert_debug_name(_module_id: ModuleId, _module_name: &PackageModule) { + // By design, this is a no-op in release builds! + } + + pub fn get_id(&self, module_name: &PackageModule<'a>) -> Option<&ModuleId> { + self.by_name.get(module_name) + } + + pub fn get_name(&self, id: ModuleId) -> Option<&PackageModule> { + self.by_id.get(id.0 as usize) + } + + pub fn available_modules(&self) -> impl Iterator { + self.by_id.iter() + } +} + +/// Stores a mapping between ModuleId and InlinableString. +/// /// Each module name is stored twice, for faster lookups. /// Since these are interned strings, this shouldn't result in many total allocations in practice. #[derive(Debug, Clone)] @@ -557,6 +614,18 @@ macro_rules! define_builtins { } } + impl<'a> Default for PackageModuleIds<'a> { + fn default() -> Self { + // +1 because the user will be compiling at least 1 non-builtin module! + let capacity = $total + 1; + + let by_name = HashMap::with_capacity_and_hasher(capacity, default_hasher()); + let by_id = Vec::with_capacity(capacity); + + PackageModuleIds { by_name, by_id } + } + } + impl Symbol { $( $(