From 2cbe5f52310f00fce68dbca335fb8b078c51f243 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 19 Mar 2022 16:26:38 +0100 Subject: [PATCH] idea (rejected): only generate work up to constraint gen, then look at what modules are actually used and generate Solve.. work based on that --- cli/src/build.rs | 2 + compiler/constrain/src/module.rs | 12 ++++- compiler/load/src/file.rs | 90 +++++++++++++++++++++++++++----- compiler/load/src/work.rs | 73 +++++++++++++++++++++++--- compiler/module/src/symbol.rs | 2 +- 5 files changed, 156 insertions(+), 23 deletions(-) diff --git a/cli/src/build.rs b/cli/src/build.rs index 2d4f7fae53..d6e7f6fbc6 100644 --- a/cli/src/build.rs +++ b/cli/src/build.rs @@ -157,6 +157,8 @@ pub fn build_file<'a>( buf.push('\n'); + dbg!(module_id); + report_timing(buf, "Read .roc file from disk", module_timing.read_roc_file); report_timing(buf, "Parse header", module_timing.parse_header); report_timing(buf, "Parse body", module_timing.parse_body); diff --git a/compiler/constrain/src/module.rs b/compiler/constrain/src/module.rs index 8af7f4c38e..9128006892 100644 --- a/compiler/constrain/src/module.rs +++ b/compiler/constrain/src/module.rs @@ -32,13 +32,21 @@ impl ExposedByModule { /// /// Useful when we know what modules a particular module imports, and want just /// the exposed types for those exposed modules. - pub fn retain_modules<'a>(&self, it: impl Iterator) -> Self { + pub fn retain_modules<'a>( + &self, + home: ModuleId, + it: impl Iterator, + ) -> Self { let mut output = Self::default(); for module_id in it { match self.exposed.get(module_id) { None => { - internal_error!("Module {:?} did not register its exposed values", module_id) + internal_error!( + "Module {:?} did not register its exposed values for {:?}", + module_id, + home, + ) } Some(exposed_types) => { output.exposed.insert(*module_id, exposed_types.clone()); diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 76e1c6eac1..3451c2c269 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -1099,7 +1099,7 @@ fn load<'a>( ) -> Result, LoadingProblem<'a>> { // When compiling to wasm, we cannot spawn extra threads // so we have a single-threaded implementation - if true || cfg!(target_family = "wasm") { + if cfg!(target_family = "wasm") { load_single_threaded( arena, load_start, @@ -1614,14 +1614,18 @@ fn report_unused_imported_modules<'a>( state: &mut State<'a>, module_id: ModuleId, constrained_module: &ConstrainedModule, -) { +) -> (Vec, Vec) { + let mut kept = vec![]; + let mut removed = vec![]; let mut unused_imported_modules = constrained_module.imported_modules.clone(); for symbol in constrained_module.module.referenced_values.iter() { + kept.push(symbol.module_id()); unused_imported_modules.remove(&symbol.module_id()); } for symbol in constrained_module.module.referenced_types.iter() { + kept.push(symbol.module_id()); unused_imported_modules.remove(&symbol.module_id()); } @@ -1633,8 +1637,23 @@ fn report_unused_imported_modules<'a>( for (unused, region) in unused_imported_modules.drain() { if !unused.is_builtin() { existing.push(roc_problem::can::Problem::UnusedImport(unused, region)); + + // we will still typecheck this module to report errors + kept.push(unused) + } else { + // for builtin modules, we will just skip the rest of the process + // in the future, we can also do this for modules from packages + removed.push(unused); } } + + kept.sort(); + kept.dedup(); + + removed.sort(); + removed.dedup(); + + (kept, removed) } fn update<'a>( @@ -1870,7 +1889,7 @@ fn update<'a>( work.extend(state.dependencies.add_module( header.module_id, &header.package_qualified_imported_modules, - state.goal_phase, + Phase::CanonicalizeAndConstrain, )); state.module_cache.headers.insert(header.module_id, header); @@ -1919,7 +1938,7 @@ fn update<'a>( } CanonicalizedAndConstrained { - constrained_module, + mut constrained_module, canonicalization_problems, module_docs, } => { @@ -1934,7 +1953,51 @@ fn update<'a>( state.module_cache.documentation.insert(module_id, docs); } - report_unused_imported_modules(&mut state, module_id, &constrained_module); + let (kept, removed) = + report_unused_imported_modules(&mut state, module_id, &constrained_module); + + for rem in removed { + constrained_module.imported_modules.remove(&rem); + } + + use std::fmt::Write; + let mut buf = String::new(); + writeln!(buf, "{:?} depends on:", module_id); + for dep in kept { + if !constrained_module.imported_modules.contains_key(&dep) { + continue; + } + writeln!(buf, " {:?} ", dep); + if module_id != dep { + state + .dependencies + .add_dependency(module_id, dep, Phase::SolveTypes); + } + } + println!("{}", buf); + + state.dependencies.add_dependency_help( + module_id, + module_id, + Phase::SolveTypes, + Phase::CanonicalizeAndConstrain, + ); + + state + .dependencies + .add_to_status(module_id, Phase::SolveTypes); + + /* + for dependency in remove_dependencies { + println!("remove dep {:?} <- {:?}", module_id, dependency); + state.dependencies.remove_dependencies( + module_id, + dependency, + Phase::SolveTypes, + state.goal_phase, + ); + } + */ state .module_cache @@ -1996,7 +2059,7 @@ fn update<'a>( if is_host_exposed && state.goal_phase == Phase::SolveTypes { debug_assert!(work.is_empty()); - debug_assert!(state.dependencies.solved_all()); + // debug_assert!(state.dependencies.solved_all()); state.timings.insert(module_id, module_timing); @@ -2787,10 +2850,7 @@ fn load_module<'a>( roc_parse::header::ModuleName::new("Bool"), Collection::with_items(&[Loc::at_zero(Spaced::Item(ExposedName::new("Bool")))]), )), - Loc::at_zero(ImportsEntry::Module( - roc_parse::header::ModuleName::new("List"), - Collection::with_items(&[Loc::at_zero(Spaced::Item(ExposedName::new("List")))]), - )), + // Note: List is only used for the type, which we ensure is always in scope Loc::at_zero(ImportsEntry::Module( roc_parse::header::ModuleName::new("Num"), Collection::with_items(&[ @@ -2856,9 +2916,6 @@ fn load_module<'a>( toUtf8 : Str -> List U8 - # fromUtf8 : List U8 -> Result Str [ BadUtf8 Utf8Problem ]* - # fromUtf8Range : List U8 -> Result Str [ BadUtf8 Utf8Problem Nat, OutOfBounds ]* - fromUtf8 : List U8 -> Result Str [ BadUtf8 Utf8ByteProblem Nat ]* fromUtf8Range : List U8, { start : Nat, count : Nat } -> Result Str [ BadUtf8 Utf8ByteProblem Nat, OutOfBounds ]* @@ -4344,7 +4401,8 @@ impl<'a> BuildTask<'a> { dep_idents: MutMap, declarations: Vec, ) -> Self { - let exposed_by_module = exposed_types.retain_modules(imported_modules.keys()); + let exposed_by_module = + exposed_types.retain_modules(module.module_id, imported_modules.keys()); let exposed_for_module = ExposedForModule::new(module.referenced_values.iter(), exposed_by_module); @@ -4635,6 +4693,10 @@ fn canonicalize_and_constrain<'a>( let constraint = constrain_module(&mut constraints, &module_output.declarations, module_id); + if module_id == ModuleId::STR { + dbg!(&constraints); + } + let after = roc_types::types::get_type_clone_count(); log!( diff --git a/compiler/load/src/work.rs b/compiler/load/src/work.rs index f26209163d..9662190fe8 100644 --- a/compiler/load/src/work.rs +++ b/compiler/load/src/work.rs @@ -32,7 +32,7 @@ enum Status { Done, } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum Job<'a> { Step(ModuleId, Phase), ResolveShorthand(&'a str), @@ -74,8 +74,10 @@ impl<'a> Dependencies<'a> { // to canonicalize a module, all its dependencies must be canonicalized self.add_dependency(module_id, dep, Phase::CanonicalizeAndConstrain); - // to typecheck a module, all its dependencies must be type checked already - self.add_dependency(module_id, dep, Phase::SolveTypes); + if goal_phase >= Phase::SolveTypes { + // to typecheck a module, all its dependencies must be type checked already + self.add_dependency(module_id, dep, Phase::SolveTypes); + } if goal_phase >= FindSpecializations { self.add_dependency(module_id, dep, Phase::FindSpecializations); @@ -101,7 +103,7 @@ impl<'a> Dependencies<'a> { output } - fn add_to_status(&mut self, module_id: ModuleId, goal_phase: Phase) { + pub fn add_to_status(&mut self, module_id: ModuleId, goal_phase: Phase) { for phase in PHASES.iter() { if *phase > goal_phase { break; @@ -193,13 +195,72 @@ impl<'a> Dependencies<'a> { } } + pub fn remove_dependencies( + &mut self, + a: ModuleId, + b: ModuleId, + start_phase: Phase, + goal_phase: Phase, + ) { + let mut i = 0; + while PHASES[i] < goal_phase { + let phase = PHASES[i]; + + if phase >= start_phase { + self.remove_dependency(a, b, phase); + } + + i += 1; + } + } + /// A waits for B, and B will notify A when it completes the phase - fn add_dependency(&mut self, a: ModuleId, b: ModuleId, phase: Phase) { + /// we will remove both of these connections + fn remove_dependency(&mut self, a: ModuleId, b: ModuleId, phase: Phase) { + let key = Job::Step(a, phase); + + let mut notifications = vec![]; + + match self.waiting_for.get_mut(&key) { + None => unreachable!(), + Some(x) => { + x.retain(|job| match job { + Job::Step(module, _) => { + if *module == b { + notifications.push(*job); + false + } else { + true + } + } + Job::ResolveShorthand(_) => true, + }); + } + } + + for notification in notifications { + match self.notifies.get_mut(¬ification) { + None => unreachable!(), + Some(x) => { + x.retain(|notify_job| notify_job != &key); + } + } + } + } + + /// A waits for B, and B will notify A when it completes the phase + pub fn add_dependency(&mut self, a: ModuleId, b: ModuleId, phase: Phase) { self.add_dependency_help(a, b, phase, phase); } /// phase_a of module a is waiting for phase_b of module_b - fn add_dependency_help(&mut self, a: ModuleId, b: ModuleId, phase_a: Phase, phase_b: Phase) { + pub fn add_dependency_help( + &mut self, + a: ModuleId, + b: ModuleId, + phase_a: Phase, + phase_b: Phase, + ) { // no need to wait if the dependency is already done! if let Some(Status::Done) = self.status.get(&Job::Step(b, phase_b)) { return; diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index ec179365dc..0ab8982962 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -293,7 +293,7 @@ lazy_static! { } /// A globally unique ID that gets assigned to each module as it is loaded. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct ModuleId(u32); impl ModuleId {