diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index a263de8995..a823bf9e3e 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -36,7 +36,7 @@ const ROC_FILE_EXTENSION: &str = "roc"; const MODULE_SEPARATOR: char = '.'; #[derive(Debug)] -pub struct LoadedModule { +pub struct LoadedModule<'a> { pub module_id: ModuleId, pub interns: Interns, pub solved: Solved, @@ -44,7 +44,7 @@ pub struct LoadedModule { pub type_problems: Vec, pub declarations_by_id: MutMap>, pub exposed_vars_by_symbol: Vec<(Symbol, Variable)>, - pub src: Box, + pub src: &'a str, } #[derive(Debug)] @@ -85,6 +85,7 @@ enum Msg<'a> { }, Finished { solved: Solved, + problems: Vec, exposed_vars_by_symbol: Vec<(Symbol, Variable)>, src: &'a str, }, @@ -161,15 +162,15 @@ type MsgReceiver<'a> = Receiver>; /// specializations, so if none of their specializations changed, we don't even need /// to rebuild the module and can link in the cached one directly.) #[allow(clippy::cognitive_complexity)] -pub fn load( +pub fn load<'a>( + arena: &'a Bump, stdlib: &StdLib, src_dir: PathBuf, filename: PathBuf, exposed_types: SubsByModule, -) -> Result { +) -> Result, LoadingProblem> { use self::MaybeShared::*; - let arena = Bump::new(); let (msg_tx, msg_rx) = bounded(1024); let arc_modules = Arc::new(Mutex::new(ModuleIds::default())); let root_exposed_ident_ids = IdentIds::exposed_builtins(0); @@ -278,7 +279,7 @@ fn load_deps<'a>( arc_modules: Arc>, ident_ids_by_module: Arc>, exposed_types: SubsByModule, -) -> Result { +) -> Result, LoadingProblem> { // Reserve one CPU for the main thread, and let all the others be eligible // to spawn workers. let num_workers = num_cpus::get() - 1; @@ -409,6 +410,7 @@ fn load_deps<'a>( match msg { Msg::Finished { solved, + problems, exposed_vars_by_symbol, src, } => { @@ -417,6 +419,8 @@ fn load_deps<'a>( dbg!("TODO send Shutdown messages to all the worker threads."); + state.type_problems.extend(problems); + let module_ids = Arc::try_unwrap(state.arc_modules) .unwrap_or_else(|_| { panic!("There were still outstanding Arc references to module_ids") @@ -762,19 +766,22 @@ fn update<'a>( solved_module, solved_subs, } => { - state.type_problems.extend(solved_module.problems); - if module_id == state.root_id { let solved = Arc::try_unwrap(solved_subs).unwrap_or_else(|_| { panic!("There were still outstanding Arc references to Solved") }); - msg_tx.send(Msg::Finished { - solved, - exposed_vars_by_symbol: solved_module.exposed_vars_by_symbol, - src, - }); + msg_tx + .send(Msg::Finished { + solved, + problems: solved_module.problems, + exposed_vars_by_symbol: solved_module.exposed_vars_by_symbol, + src, + }) + .map_err(|_| LoadingProblem::MsgChannelDied)?; } else { + state.type_problems.extend(solved_module.problems); + // This was a dependency. Write it down and keep processing messages. debug_assert!(!state.exposed_types.contains_key(&module_id)); state.exposed_types.insert( @@ -1147,84 +1154,84 @@ fn add_exposed_to_scope( } } -//// TODO trim down these arguments - possibly by moving Constraint into Module -//#[allow(clippy::too_many_arguments)] -//fn spawn_solve_module( -// module: Module, -// src: Box, -// constraint: Constraint, -// mut var_store: VarStore, -// imported_modules: MutSet, -// msg_tx: MsgSender, -// exposed_types: &mut SubsByModule, -// stdlib: &StdLib, -//) { -// let home = module.module_id; +// TODO trim down these arguments - possibly by moving Constraint into Module +#[allow(clippy::too_many_arguments)] +fn spawn_solve_module( + module: Module, + src: Box, + constraint: Constraint, + mut var_store: VarStore, + imported_modules: MutSet, + msg_tx: MsgSender, + exposed_types: &mut SubsByModule, + stdlib: &StdLib, +) { + let home = module.module_id; -// // Get the constraints for this module's imports. We do this on the main thread -// // to avoid having to lock the map of exposed types, or to clone it -// // (which would be more expensive for the main thread). -// let ConstrainableImports { -// imported_symbols, -// imported_aliases, -// unused_imports, -// } = pre_constrain_imports( -// home, -// &module.references, -// imported_modules, -// exposed_types, -// stdlib, -// ); + // Get the constraints for this module's imports. We do this on the main thread + // to avoid having to lock the map of exposed types, or to clone it + // (which would be more expensive for the main thread). + let ConstrainableImports { + imported_symbols, + imported_aliases, + unused_imports, + } = pre_constrain_imports( + home, + &module.references, + imported_modules, + exposed_types, + stdlib, + ); -// for unused_import in unused_imports { -// todo!( -// "TODO gracefully handle unused import {:?} from module {:?}", -// unused_import, -// home -// ); -// } + for unused_import in unused_imports { + todo!( + "TODO gracefully handle unused import {:?} from module {:?}", + unused_import, + home + ); + } -// // We can't pass the reference to stdlib to the thread, but we can pass mode. -// let mode = stdlib.mode; + // We can't pass the reference to stdlib to the thread, but we can pass mode. + let mode = stdlib.mode; -// // Start solving this module in the background. -// thread_scope.spawn(move |_| { -// // Rebuild the aliases in this thread, so we don't have to clone all of -// // stdlib.aliases on the main thread. -// let aliases = match mode { -// Mode::Standard => roc_builtins::std::aliases(), -// Mode::Uniqueness => roc_builtins::unique::aliases(), -// }; + // Start solving this module in the background. + // thread_scope.spawn(move |_| { + // // Rebuild the aliases in this thread, so we don't have to clone all of + // // stdlib.aliases on the main thread. + // let aliases = match mode { + // Mode::Standard => roc_builtins::std::aliases(), + // Mode::Uniqueness => roc_builtins::unique::aliases(), + // }; -// // Finish constraining the module by wrapping the existing Constraint -// // in the ones we just computed. We can do this off the main thread. -// let constraint = constrain_imports( -// imported_symbols, -// imported_aliases, -// constraint, -// &mut var_store, -// ); -// let mut constraint = load_builtin_aliases(aliases, constraint, &mut var_store); + // // Finish constraining the module by wrapping the existing Constraint + // // in the ones we just computed. We can do this off the main thread. + // let constraint = constrain_imports( + // imported_symbols, + // imported_aliases, + // constraint, + // &mut var_store, + // ); + // let mut constraint = load_builtin_aliases(aliases, constraint, &mut var_store); -// // Turn Apply into Alias -// constraint.instantiate_aliases(&mut var_store); + // // Turn Apply into Alias + // constraint.instantiate_aliases(&mut var_store); -// let (solved_subs, solved_module) = -// roc_solve::module::solve_module(module, constraint, var_store); + // let (solved_subs, solved_module) = + // roc_solve::module::solve_module(module, constraint, var_store); -// thread_scope.spawn(move |_| { -// // Send the subs to the main thread for processing, -// msg_tx -// .send(Msg::Solved { -// src, -// module_id: home, -// solved_subs: Arc::new(solved_subs), -// solved_module, -// }) -// .unwrap_or_else(|_| panic!("Failed to send Solved message")); -// }); -// }); -//} + // thread_scope.spawn(move |_| { + // // Send the subs to the main thread for processing, + // msg_tx + // .send(Msg::Solved { + // src, + // module_id: home, + // solved_subs: Arc::new(solved_subs), + // solved_module, + // }) + // .unwrap_or_else(|_| panic!("Failed to send Solved message")); + // }); + // }); +} #[allow(clippy::too_many_arguments)] fn build_parse_and_constrain_task<'a, 'b>( diff --git a/compiler/load/tests/test_load.rs b/compiler/load/tests/test_load.rs index de870cf84b..0314a7bca3 100644 --- a/compiler/load/tests/test_load.rs +++ b/compiler/load/tests/test_load.rs @@ -14,6 +14,7 @@ mod helpers; #[cfg(test)] mod test_load { use crate::helpers::fixtures_dir; + use bumpalo::Bump; use inlinable_string::InlinableString; use roc_can::def::Declaration::*; use roc_can::def::Def; @@ -27,14 +28,16 @@ mod test_load { // HELPERS - fn load_fixture( + fn load_fixture<'a>( + arena: &'a Bump, dir_name: &str, module_name: &str, subs_by_module: SubsByModule, - ) -> LoadedModule { + ) -> LoadedModule<'a> { let src_dir = fixtures_dir().join(dir_name); let filename = src_dir.join(format!("{}.roc", module_name)); let loaded = load( + &arena, &roc_builtins::std::standard_stdlib(), src_dir, filename, @@ -128,7 +131,9 @@ mod test_load { let subs_by_module = MutMap::default(); let src_dir = fixtures_dir().join("interface_with_deps"); let filename = src_dir.join("Primary.roc"); + let arena = Bump::new(); let loaded = load( + &arena, &roc_builtins::std::standard_stdlib(), src_dir, filename, @@ -160,8 +165,9 @@ mod test_load { #[test] fn load_unit() { + let arena = Bump::new(); let subs_by_module = MutMap::default(); - let loaded_module = load_fixture("no_deps", "Unit", subs_by_module); + let loaded_module = load_fixture(&arena, "no_deps", "Unit", subs_by_module); expect_types( loaded_module, @@ -173,8 +179,10 @@ mod test_load { #[test] fn import_alias() { + let arena = Bump::new(); let subs_by_module = MutMap::default(); - let loaded_module = load_fixture("interface_with_deps", "ImportAlias", subs_by_module); + let loaded_module = + load_fixture(&arena, "interface_with_deps", "ImportAlias", subs_by_module); expect_types( loaded_module, @@ -186,8 +194,14 @@ mod test_load { #[test] fn load_and_typecheck() { + let arena = Bump::new(); let subs_by_module = MutMap::default(); - let loaded_module = load_fixture("interface_with_deps", "WithBuiltins", subs_by_module); + let loaded_module = load_fixture( + &arena, + "interface_with_deps", + "WithBuiltins", + subs_by_module, + ); expect_types( loaded_module, @@ -206,8 +220,10 @@ mod test_load { #[test] fn iface_quicksort() { + let arena = Bump::new(); let subs_by_module = MutMap::default(); - let loaded_module = load_fixture("interface_with_deps", "Quicksort", subs_by_module); + let loaded_module = + load_fixture(&arena, "interface_with_deps", "Quicksort", subs_by_module); expect_types( loaded_module, @@ -221,8 +237,9 @@ mod test_load { #[test] fn app_quicksort() { + let arena = Bump::new(); let subs_by_module = MutMap::default(); - let loaded_module = load_fixture("app_with_deps", "Quicksort", subs_by_module); + let loaded_module = load_fixture(&arena, "app_with_deps", "Quicksort", subs_by_module); expect_types( loaded_module, @@ -236,8 +253,9 @@ mod test_load { #[test] fn load_astar() { + let arena = Bump::new(); let subs_by_module = MutMap::default(); - let loaded_module = load_fixture("interface_with_deps", "AStar", subs_by_module); + let loaded_module = load_fixture(&arena, "interface_with_deps", "AStar", subs_by_module); expect_types( loaded_module, @@ -254,8 +272,9 @@ mod test_load { #[test] fn load_principal_types() { + let arena = Bump::new(); let subs_by_module = MutMap::default(); - let loaded_module = load_fixture("no_deps", "Principal", subs_by_module); + let loaded_module = load_fixture(&arena, "no_deps", "Principal", subs_by_module); expect_types( loaded_module, @@ -268,8 +287,9 @@ mod test_load { #[test] fn iface_dep_types() { + let arena = Bump::new(); let subs_by_module = MutMap::default(); - let loaded_module = load_fixture("interface_with_deps", "Primary", subs_by_module); + let loaded_module = load_fixture(&arena, "interface_with_deps", "Primary", subs_by_module); expect_types( loaded_module, @@ -290,8 +310,9 @@ mod test_load { #[test] fn app_dep_types() { + let arena = Bump::new(); let subs_by_module = MutMap::default(); - let loaded_module = load_fixture("app_with_deps", "Primary", subs_by_module); + let loaded_module = load_fixture(&arena, "app_with_deps", "Primary", subs_by_module); expect_types( loaded_module, @@ -312,8 +333,9 @@ mod test_load { #[test] fn imported_dep_regression() { + let arena = Bump::new(); let subs_by_module = MutMap::default(); - let loaded_module = load_fixture("interface_with_deps", "OneDep", subs_by_module); + let loaded_module = load_fixture(&arena, "interface_with_deps", "OneDep", subs_by_module); expect_types( loaded_module,