mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-11 05:34:11 +03:00
idea (rejected): only generate work up to constraint gen, then look at what modules are actually used and generate Solve.. work based on that
This commit is contained in:
parent
3db44af36f
commit
2cbe5f5231
@ -157,6 +157,8 @@ pub fn build_file<'a>(
|
|||||||
|
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
|
|
||||||
|
dbg!(module_id);
|
||||||
|
|
||||||
report_timing(buf, "Read .roc file from disk", module_timing.read_roc_file);
|
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 header", module_timing.parse_header);
|
||||||
report_timing(buf, "Parse body", module_timing.parse_body);
|
report_timing(buf, "Parse body", module_timing.parse_body);
|
||||||
|
@ -32,13 +32,21 @@ impl ExposedByModule {
|
|||||||
///
|
///
|
||||||
/// Useful when we know what modules a particular module imports, and want just
|
/// Useful when we know what modules a particular module imports, and want just
|
||||||
/// the exposed types for those exposed modules.
|
/// the exposed types for those exposed modules.
|
||||||
pub fn retain_modules<'a>(&self, it: impl Iterator<Item = &'a ModuleId>) -> Self {
|
pub fn retain_modules<'a>(
|
||||||
|
&self,
|
||||||
|
home: ModuleId,
|
||||||
|
it: impl Iterator<Item = &'a ModuleId>,
|
||||||
|
) -> Self {
|
||||||
let mut output = Self::default();
|
let mut output = Self::default();
|
||||||
|
|
||||||
for module_id in it {
|
for module_id in it {
|
||||||
match self.exposed.get(module_id) {
|
match self.exposed.get(module_id) {
|
||||||
None => {
|
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) => {
|
Some(exposed_types) => {
|
||||||
output.exposed.insert(*module_id, exposed_types.clone());
|
output.exposed.insert(*module_id, exposed_types.clone());
|
||||||
|
@ -1099,7 +1099,7 @@ fn load<'a>(
|
|||||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||||
// When compiling to wasm, we cannot spawn extra threads
|
// When compiling to wasm, we cannot spawn extra threads
|
||||||
// so we have a single-threaded implementation
|
// so we have a single-threaded implementation
|
||||||
if true || cfg!(target_family = "wasm") {
|
if cfg!(target_family = "wasm") {
|
||||||
load_single_threaded(
|
load_single_threaded(
|
||||||
arena,
|
arena,
|
||||||
load_start,
|
load_start,
|
||||||
@ -1614,14 +1614,18 @@ fn report_unused_imported_modules<'a>(
|
|||||||
state: &mut State<'a>,
|
state: &mut State<'a>,
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
constrained_module: &ConstrainedModule,
|
constrained_module: &ConstrainedModule,
|
||||||
) {
|
) -> (Vec<ModuleId>, Vec<ModuleId>) {
|
||||||
|
let mut kept = vec![];
|
||||||
|
let mut removed = vec![];
|
||||||
let mut unused_imported_modules = constrained_module.imported_modules.clone();
|
let mut unused_imported_modules = constrained_module.imported_modules.clone();
|
||||||
|
|
||||||
for symbol in constrained_module.module.referenced_values.iter() {
|
for symbol in constrained_module.module.referenced_values.iter() {
|
||||||
|
kept.push(symbol.module_id());
|
||||||
unused_imported_modules.remove(&symbol.module_id());
|
unused_imported_modules.remove(&symbol.module_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
for symbol in constrained_module.module.referenced_types.iter() {
|
for symbol in constrained_module.module.referenced_types.iter() {
|
||||||
|
kept.push(symbol.module_id());
|
||||||
unused_imported_modules.remove(&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() {
|
for (unused, region) in unused_imported_modules.drain() {
|
||||||
if !unused.is_builtin() {
|
if !unused.is_builtin() {
|
||||||
existing.push(roc_problem::can::Problem::UnusedImport(unused, region));
|
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>(
|
fn update<'a>(
|
||||||
@ -1870,7 +1889,7 @@ fn update<'a>(
|
|||||||
work.extend(state.dependencies.add_module(
|
work.extend(state.dependencies.add_module(
|
||||||
header.module_id,
|
header.module_id,
|
||||||
&header.package_qualified_imported_modules,
|
&header.package_qualified_imported_modules,
|
||||||
state.goal_phase,
|
Phase::CanonicalizeAndConstrain,
|
||||||
));
|
));
|
||||||
|
|
||||||
state.module_cache.headers.insert(header.module_id, header);
|
state.module_cache.headers.insert(header.module_id, header);
|
||||||
@ -1919,7 +1938,7 @@ fn update<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
CanonicalizedAndConstrained {
|
CanonicalizedAndConstrained {
|
||||||
constrained_module,
|
mut constrained_module,
|
||||||
canonicalization_problems,
|
canonicalization_problems,
|
||||||
module_docs,
|
module_docs,
|
||||||
} => {
|
} => {
|
||||||
@ -1934,7 +1953,51 @@ fn update<'a>(
|
|||||||
state.module_cache.documentation.insert(module_id, docs);
|
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
|
state
|
||||||
.module_cache
|
.module_cache
|
||||||
@ -1996,7 +2059,7 @@ fn update<'a>(
|
|||||||
|
|
||||||
if is_host_exposed && state.goal_phase == Phase::SolveTypes {
|
if is_host_exposed && state.goal_phase == Phase::SolveTypes {
|
||||||
debug_assert!(work.is_empty());
|
debug_assert!(work.is_empty());
|
||||||
debug_assert!(state.dependencies.solved_all());
|
// debug_assert!(state.dependencies.solved_all());
|
||||||
|
|
||||||
state.timings.insert(module_id, module_timing);
|
state.timings.insert(module_id, module_timing);
|
||||||
|
|
||||||
@ -2787,10 +2850,7 @@ fn load_module<'a>(
|
|||||||
roc_parse::header::ModuleName::new("Bool"),
|
roc_parse::header::ModuleName::new("Bool"),
|
||||||
Collection::with_items(&[Loc::at_zero(Spaced::Item(ExposedName::new("Bool")))]),
|
Collection::with_items(&[Loc::at_zero(Spaced::Item(ExposedName::new("Bool")))]),
|
||||||
)),
|
)),
|
||||||
Loc::at_zero(ImportsEntry::Module(
|
// Note: List is only used for the type, which we ensure is always in scope
|
||||||
roc_parse::header::ModuleName::new("List"),
|
|
||||||
Collection::with_items(&[Loc::at_zero(Spaced::Item(ExposedName::new("List")))]),
|
|
||||||
)),
|
|
||||||
Loc::at_zero(ImportsEntry::Module(
|
Loc::at_zero(ImportsEntry::Module(
|
||||||
roc_parse::header::ModuleName::new("Num"),
|
roc_parse::header::ModuleName::new("Num"),
|
||||||
Collection::with_items(&[
|
Collection::with_items(&[
|
||||||
@ -2856,9 +2916,6 @@ fn load_module<'a>(
|
|||||||
|
|
||||||
toUtf8 : Str -> List U8
|
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 ]*
|
fromUtf8 : List U8 -> Result Str [ BadUtf8 Utf8ByteProblem Nat ]*
|
||||||
fromUtf8Range : List U8, { start : Nat, count : Nat } -> Result Str [ BadUtf8 Utf8ByteProblem Nat, OutOfBounds ]*
|
fromUtf8Range : List U8, { start : Nat, count : Nat } -> Result Str [ BadUtf8 Utf8ByteProblem Nat, OutOfBounds ]*
|
||||||
|
|
||||||
@ -4344,7 +4401,8 @@ impl<'a> BuildTask<'a> {
|
|||||||
dep_idents: MutMap<ModuleId, IdentIds>,
|
dep_idents: MutMap<ModuleId, IdentIds>,
|
||||||
declarations: Vec<Declaration>,
|
declarations: Vec<Declaration>,
|
||||||
) -> Self {
|
) -> 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 =
|
let exposed_for_module =
|
||||||
ExposedForModule::new(module.referenced_values.iter(), exposed_by_module);
|
ExposedForModule::new(module.referenced_values.iter(), exposed_by_module);
|
||||||
|
|
||||||
@ -4635,6 +4693,10 @@ fn canonicalize_and_constrain<'a>(
|
|||||||
let constraint =
|
let constraint =
|
||||||
constrain_module(&mut constraints, &module_output.declarations, module_id);
|
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();
|
let after = roc_types::types::get_type_clone_count();
|
||||||
|
|
||||||
log!(
|
log!(
|
||||||
|
@ -32,7 +32,7 @@ enum Status {
|
|||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
enum Job<'a> {
|
enum Job<'a> {
|
||||||
Step(ModuleId, Phase),
|
Step(ModuleId, Phase),
|
||||||
ResolveShorthand(&'a str),
|
ResolveShorthand(&'a str),
|
||||||
@ -74,8 +74,10 @@ impl<'a> Dependencies<'a> {
|
|||||||
// to canonicalize a module, all its dependencies must be canonicalized
|
// to canonicalize a module, all its dependencies must be canonicalized
|
||||||
self.add_dependency(module_id, dep, Phase::CanonicalizeAndConstrain);
|
self.add_dependency(module_id, dep, Phase::CanonicalizeAndConstrain);
|
||||||
|
|
||||||
// to typecheck a module, all its dependencies must be type checked already
|
if goal_phase >= Phase::SolveTypes {
|
||||||
self.add_dependency(module_id, dep, 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 {
|
if goal_phase >= FindSpecializations {
|
||||||
self.add_dependency(module_id, dep, Phase::FindSpecializations);
|
self.add_dependency(module_id, dep, Phase::FindSpecializations);
|
||||||
@ -101,7 +103,7 @@ impl<'a> Dependencies<'a> {
|
|||||||
output
|
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() {
|
for phase in PHASES.iter() {
|
||||||
if *phase > goal_phase {
|
if *phase > goal_phase {
|
||||||
break;
|
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
|
/// 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);
|
self.add_dependency_help(a, b, phase, phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// phase_a of module a is waiting for phase_b of module_b
|
/// 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!
|
// no need to wait if the dependency is already done!
|
||||||
if let Some(Status::Done) = self.status.get(&Job::Step(b, phase_b)) {
|
if let Some(Status::Done) = self.status.get(&Job::Step(b, phase_b)) {
|
||||||
return;
|
return;
|
||||||
|
@ -293,7 +293,7 @@ lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A globally unique ID that gets assigned to each module as it is loaded.
|
/// 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);
|
pub struct ModuleId(u32);
|
||||||
|
|
||||||
impl ModuleId {
|
impl ModuleId {
|
||||||
|
Loading…
Reference in New Issue
Block a user