mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-25 21:37:48 +00:00
Merge branch 'trunk' into assoc-list-dict
This commit is contained in:
commit
1b1b63aad0
66 changed files with 2681 additions and 780 deletions
|
|
@ -14,6 +14,7 @@ roc_types = { path = "../types" }
|
|||
roc_can = { path = "../can" }
|
||||
roc_constrain = { path = "../constrain" }
|
||||
roc_derive_key = { path = "../derive_key" }
|
||||
roc_derive = { path = "../derive" }
|
||||
roc_builtins = { path = "../builtins" }
|
||||
roc_problem = { path = "../problem" }
|
||||
roc_unify = { path = "../unify" }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use roc_debug_flags::{
|
|||
ROC_PRINT_IR_AFTER_REFCOUNT, ROC_PRINT_IR_AFTER_RESET_REUSE, ROC_PRINT_IR_AFTER_SPECIALIZATION,
|
||||
ROC_PRINT_LOAD_LOG,
|
||||
};
|
||||
use roc_derive_key::GlobalDerivedSymbols;
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_late_solve::{AbilitiesView, WorldAbilities};
|
||||
use roc_module::ident::{Ident, ModuleName, QualifiedModuleName};
|
||||
|
|
@ -370,7 +370,7 @@ fn start_phase<'a>(
|
|||
..
|
||||
} = constrained;
|
||||
|
||||
let derived_symbols = GlobalDerivedSymbols::clone(&state.derived_symbols);
|
||||
let derived_module = SharedDerivedModule::clone(&state.derived_module);
|
||||
|
||||
BuildTask::solve_module(
|
||||
module,
|
||||
|
|
@ -385,7 +385,7 @@ fn start_phase<'a>(
|
|||
dep_idents,
|
||||
declarations,
|
||||
state.cached_subs.clone(),
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
)
|
||||
}
|
||||
Phase::FindSpecializations => {
|
||||
|
|
@ -413,7 +413,7 @@ fn start_phase<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let derived_symbols = GlobalDerivedSymbols::clone(&state.derived_symbols);
|
||||
let derived_module = SharedDerivedModule::clone(&state.derived_module);
|
||||
|
||||
BuildTask::BuildPendingSpecializations {
|
||||
layout_cache,
|
||||
|
|
@ -425,18 +425,44 @@ fn start_phase<'a>(
|
|||
ident_ids,
|
||||
exposed_to_host: state.exposed_to_host.clone(),
|
||||
abilities_store,
|
||||
derived_symbols,
|
||||
// TODO: awful, how can we get rid of the clone?
|
||||
exposed_by_module: state.exposed_types.clone(),
|
||||
derived_module,
|
||||
}
|
||||
}
|
||||
Phase::MakeSpecializations => {
|
||||
let specializations_we_must_make = state
|
||||
let mut specializations_we_must_make = state
|
||||
.module_cache
|
||||
.external_specializations_requested
|
||||
.remove(&module_id)
|
||||
.unwrap_or_default();
|
||||
|
||||
let (ident_ids, subs, procs_base, layout_cache, module_timing) =
|
||||
if state.make_specializations_pass.current_pass() == 1 {
|
||||
if module_id == ModuleId::DERIVED_GEN {
|
||||
// The derived gen module must also fulfill also specializations asked of the
|
||||
// derived synth module.
|
||||
let derived_synth_specializations = state
|
||||
.module_cache
|
||||
.external_specializations_requested
|
||||
.remove(&ModuleId::DERIVED_SYNTH)
|
||||
.unwrap_or_default();
|
||||
specializations_we_must_make.extend(derived_synth_specializations)
|
||||
}
|
||||
|
||||
let (mut ident_ids, mut subs, mut procs_base, layout_cache, mut module_timing) =
|
||||
if state.make_specializations_pass.current_pass() == 1
|
||||
&& module_id == ModuleId::DERIVED_GEN
|
||||
{
|
||||
// This is the first time the derived module is introduced into the load
|
||||
// graph. It has no abilities of its own or anything, just generate fresh
|
||||
// information for it.
|
||||
(
|
||||
IdentIds::default(),
|
||||
Subs::default(),
|
||||
ProcsBase::default(),
|
||||
LayoutCache::new(state.target_info),
|
||||
ModuleTiming::new(SystemTime::now()),
|
||||
)
|
||||
} else if state.make_specializations_pass.current_pass() == 1 {
|
||||
let found_specializations = state
|
||||
.module_cache
|
||||
.found_specializations
|
||||
|
|
@ -452,12 +478,13 @@ fn start_phase<'a>(
|
|||
abilities_store,
|
||||
} = found_specializations;
|
||||
|
||||
// Safety: by this point every module should have been solved, so there is no need
|
||||
// for our exposed types anymore, but the world does need them.
|
||||
let our_exposed_types = unsafe { state.exposed_types.remove(&module_id) }
|
||||
let our_exposed_types = state
|
||||
.exposed_types
|
||||
.get(&module_id)
|
||||
.unwrap_or_else(|| {
|
||||
internal_error!("Exposed types for {:?} missing", module_id)
|
||||
});
|
||||
})
|
||||
.clone();
|
||||
|
||||
// Add our abilities to the world.
|
||||
state.world_abilities.insert(
|
||||
|
|
@ -483,7 +510,22 @@ fn start_phase<'a>(
|
|||
(ident_ids, subs, procs_base, layout_cache, module_timing)
|
||||
};
|
||||
|
||||
let derived_symbols = GlobalDerivedSymbols::clone(&state.derived_symbols);
|
||||
if module_id == ModuleId::DERIVED_GEN {
|
||||
load_derived_partial_procs(
|
||||
module_id,
|
||||
arena,
|
||||
&mut subs,
|
||||
&mut ident_ids,
|
||||
&state.derived_module,
|
||||
&mut module_timing,
|
||||
state.target_info,
|
||||
&state.exposed_types,
|
||||
&mut procs_base,
|
||||
&mut state.world_abilities,
|
||||
);
|
||||
}
|
||||
|
||||
let derived_module = SharedDerivedModule::clone(&state.derived_module);
|
||||
|
||||
BuildTask::MakeSpecializations {
|
||||
module_id,
|
||||
|
|
@ -494,7 +536,9 @@ fn start_phase<'a>(
|
|||
specializations_we_must_make,
|
||||
module_timing,
|
||||
world_abilities: state.world_abilities.clone_ref(),
|
||||
derived_symbols,
|
||||
// TODO: awful, how can we get rid of the clone?
|
||||
exposed_by_module: state.exposed_types.clone(),
|
||||
derived_module,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -808,7 +852,7 @@ struct State<'a> {
|
|||
pub arc_modules: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||
pub arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
|
||||
#[allow(unused)]
|
||||
pub derived_symbols: GlobalDerivedSymbols,
|
||||
pub derived_module: SharedDerivedModule,
|
||||
|
||||
pub ident_ids_by_module: SharedIdentIdsByModule,
|
||||
|
||||
|
|
@ -853,6 +897,8 @@ impl<'a> State<'a> {
|
|||
) -> Self {
|
||||
let arc_shorthands = Arc::new(Mutex::new(MutMap::default()));
|
||||
|
||||
let dependencies = Dependencies::new(goal_phase);
|
||||
|
||||
Self {
|
||||
root_id,
|
||||
root_subs: None,
|
||||
|
|
@ -862,14 +908,14 @@ impl<'a> State<'a> {
|
|||
output_path: None,
|
||||
platform_path: PlatformPath::NotSpecified,
|
||||
module_cache: ModuleCache::default(),
|
||||
dependencies: Dependencies::default(),
|
||||
dependencies,
|
||||
procedures: MutMap::default(),
|
||||
toplevel_expects: Vec::new(),
|
||||
exposed_to_host: ExposedToHost::default(),
|
||||
exposed_types,
|
||||
arc_modules,
|
||||
arc_shorthands,
|
||||
derived_symbols: Default::default(),
|
||||
derived_module: Default::default(),
|
||||
constrained_ident_ids: IdentIds::exposed_builtins(0),
|
||||
ident_ids_by_module,
|
||||
declarations_by_id: MutMap::default(),
|
||||
|
|
@ -988,7 +1034,7 @@ enum BuildTask<'a> {
|
|||
declarations: Declarations,
|
||||
dep_idents: IdentIdsByModule,
|
||||
cached_subs: CachedSubs,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
},
|
||||
BuildPendingSpecializations {
|
||||
module_timing: ModuleTiming,
|
||||
|
|
@ -999,8 +1045,9 @@ enum BuildTask<'a> {
|
|||
ident_ids: IdentIds,
|
||||
decls: Declarations,
|
||||
exposed_to_host: ExposedToHost,
|
||||
exposed_by_module: ExposedByModule,
|
||||
abilities_store: AbilitiesStore,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
},
|
||||
MakeSpecializations {
|
||||
module_id: ModuleId,
|
||||
|
|
@ -1010,8 +1057,9 @@ enum BuildTask<'a> {
|
|||
layout_cache: LayoutCache<'a>,
|
||||
specializations_we_must_make: Vec<ExternalSpecializations<'a>>,
|
||||
module_timing: ModuleTiming,
|
||||
exposed_by_module: ExposedByModule,
|
||||
world_abilities: WorldAbilities,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1114,13 +1162,13 @@ pub struct LoadStart<'a> {
|
|||
impl<'a> LoadStart<'a> {
|
||||
pub fn from_path(
|
||||
arena: &'a Bump,
|
||||
mut src_dir: PathBuf,
|
||||
filename: PathBuf,
|
||||
render: RenderTarget,
|
||||
) -> Result<Self, LoadingProblem<'a>> {
|
||||
let arc_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));
|
||||
let mut src_dir = filename.parent().unwrap().to_path_buf();
|
||||
|
||||
// Load the root module synchronously; we can't proceed until we have its id.
|
||||
let (root_id, root_msg) = {
|
||||
|
|
@ -2637,7 +2685,16 @@ fn finish_specialization(
|
|||
.into_inner()
|
||||
.into_module_ids();
|
||||
|
||||
let all_ident_ids = state.constrained_ident_ids;
|
||||
let mut all_ident_ids = state.constrained_ident_ids;
|
||||
|
||||
// Associate the ident IDs from the derived synth module
|
||||
let (_, derived_synth_ident_ids) = Arc::try_unwrap(state.derived_module)
|
||||
.unwrap_or_else(|_| internal_error!("Outstanding references to the derived module"))
|
||||
.into_inner()
|
||||
.unwrap()
|
||||
.decompose();
|
||||
ModuleId::DERIVED_SYNTH.register_debug_idents(&derived_synth_ident_ids);
|
||||
all_ident_ids.insert(ModuleId::DERIVED_SYNTH, derived_synth_ident_ids);
|
||||
|
||||
let interns = Interns {
|
||||
module_ids,
|
||||
|
|
@ -2755,12 +2812,16 @@ fn finish(
|
|||
.into_inner()
|
||||
.into_module_ids();
|
||||
|
||||
// Steal the derived symbols and put them in the global ident ids
|
||||
let derived_ident_ids = state.derived_symbols.lock().unwrap().steal();
|
||||
ModuleId::DERIVED.register_debug_idents(&derived_ident_ids);
|
||||
// Associate the ident IDs from the derived synth module
|
||||
let (_, derived_synth_ident_ids) = Arc::try_unwrap(state.derived_module)
|
||||
.unwrap_or_else(|_| internal_error!("Outstanding references to the derived module"))
|
||||
.into_inner()
|
||||
.unwrap()
|
||||
.decompose();
|
||||
ModuleId::DERIVED_SYNTH.register_debug_idents(&derived_synth_ident_ids);
|
||||
state
|
||||
.constrained_ident_ids
|
||||
.insert(ModuleId::DERIVED, derived_ident_ids);
|
||||
.insert(ModuleId::DERIVED_SYNTH, derived_synth_ident_ids);
|
||||
|
||||
let interns = Interns {
|
||||
module_ids,
|
||||
|
|
@ -2847,7 +2908,7 @@ fn load_platform_module<'a>(
|
|||
// make a `platform` module that ultimately exposes `main` to the host
|
||||
let platform_module_msg = fabricate_platform_module(
|
||||
arena,
|
||||
shorthand,
|
||||
Some(shorthand),
|
||||
Some(app_module_id),
|
||||
filename.to_path_buf(),
|
||||
parser_state,
|
||||
|
|
@ -3245,19 +3306,17 @@ fn parse_header<'a>(
|
|||
To::NewPackage(_package_name) => Ok((module_id, app_module_header_msg)),
|
||||
}
|
||||
}
|
||||
Ok((ast::Module::Platform { header }, parse_state)) => {
|
||||
Ok(fabricate_platform_module(
|
||||
arena,
|
||||
"", // Use a shorthand of "" - it will be fine for `roc check` and bindgen
|
||||
None,
|
||||
filename,
|
||||
parse_state,
|
||||
module_ids.clone(),
|
||||
ident_ids_by_module,
|
||||
&header,
|
||||
module_timing,
|
||||
))
|
||||
}
|
||||
Ok((ast::Module::Platform { header }, parse_state)) => Ok(fabricate_platform_module(
|
||||
arena,
|
||||
None,
|
||||
None,
|
||||
filename,
|
||||
parse_state,
|
||||
module_ids.clone(),
|
||||
ident_ids_by_module,
|
||||
&header,
|
||||
module_timing,
|
||||
)),
|
||||
|
||||
Err(fail) => Err(LoadingProblem::ParsingFailed(
|
||||
fail.map_problem(SyntaxError::Header)
|
||||
|
|
@ -3542,7 +3601,7 @@ fn send_header<'a>(
|
|||
struct PlatformHeaderInfo<'a> {
|
||||
filename: PathBuf,
|
||||
is_root_module: bool,
|
||||
shorthand: &'a str,
|
||||
opt_shorthand: Option<&'a str>,
|
||||
opt_app_module_id: Option<ModuleId>,
|
||||
packages: &'a [Loc<PackageEntry<'a>>],
|
||||
provides: &'a [Loc<ExposedName<'a>>],
|
||||
|
|
@ -3562,7 +3621,7 @@ fn send_header_two<'a>(
|
|||
) -> (ModuleId, Msg<'a>) {
|
||||
let PlatformHeaderInfo {
|
||||
filename,
|
||||
shorthand,
|
||||
opt_shorthand,
|
||||
is_root_module,
|
||||
opt_app_module_id,
|
||||
packages,
|
||||
|
|
@ -3617,7 +3676,10 @@ fn send_header_two<'a>(
|
|||
let mut module_ids = (*module_ids).lock();
|
||||
let mut ident_ids_by_module = (*ident_ids_by_module).lock();
|
||||
|
||||
let name = PQModuleName::Qualified(shorthand, declared_name);
|
||||
let name = match opt_shorthand {
|
||||
Some(shorthand) => PQModuleName::Qualified(shorthand, declared_name),
|
||||
None => PQModuleName::Unqualified(declared_name),
|
||||
};
|
||||
home = module_ids.get_or_insert(&name);
|
||||
|
||||
// Ensure this module has an entry in the exposed_ident_ids map.
|
||||
|
|
@ -3631,8 +3693,13 @@ fn send_header_two<'a>(
|
|||
for (qualified_module_name, exposed_idents, region) in imported.into_iter() {
|
||||
let cloned_module_name = qualified_module_name.module.clone();
|
||||
let pq_module_name = match qualified_module_name.opt_package {
|
||||
None => PQModuleName::Qualified(shorthand, qualified_module_name.module),
|
||||
Some(package) => PQModuleName::Qualified(package, cloned_module_name.clone()),
|
||||
None => match opt_shorthand {
|
||||
Some(shorthand) => {
|
||||
PQModuleName::Qualified(shorthand, qualified_module_name.module)
|
||||
}
|
||||
None => PQModuleName::Unqualified(qualified_module_name.module),
|
||||
},
|
||||
Some(package) => PQModuleName::Qualified(package, cloned_module_name),
|
||||
};
|
||||
|
||||
let module_id = module_ids.get_or_insert(&pq_module_name);
|
||||
|
|
@ -3741,7 +3808,8 @@ fn send_header_two<'a>(
|
|||
};
|
||||
|
||||
let extra = HeaderFor::Platform {
|
||||
config_shorthand: shorthand,
|
||||
// A config_shorthand of "" should be fine
|
||||
config_shorthand: opt_shorthand.unwrap_or_default(),
|
||||
platform_main_type: requires[0].value,
|
||||
main_for_host,
|
||||
};
|
||||
|
|
@ -3798,7 +3866,7 @@ impl<'a> BuildTask<'a> {
|
|||
dep_idents: IdentIdsByModule,
|
||||
declarations: Declarations,
|
||||
cached_subs: CachedSubs,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> Self {
|
||||
let exposed_by_module = exposed_types.retain_modules(imported_modules.keys());
|
||||
|
||||
|
|
@ -3818,7 +3886,7 @@ impl<'a> BuildTask<'a> {
|
|||
dep_idents,
|
||||
module_timing,
|
||||
cached_subs,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3866,7 +3934,7 @@ pub fn add_imports(
|
|||
my_module: ModuleId,
|
||||
subs: &mut Subs,
|
||||
mut pending_abilities: PendingAbilitiesStore,
|
||||
mut exposed_for_module: ExposedForModule,
|
||||
exposed_for_module: &ExposedForModule,
|
||||
def_types: &mut Vec<(Symbol, Loc<roc_types::types::Type>)>,
|
||||
rigid_vars: &mut Vec<Variable>,
|
||||
) -> (Vec<Variable>, AbilitiesStore) {
|
||||
|
|
@ -3879,7 +3947,7 @@ pub fn add_imports(
|
|||
macro_rules! import_var_for_symbol {
|
||||
($subs:expr, $exposed_by_module:expr, $symbol:ident, $break:stmt) => {
|
||||
let module_id = $symbol.module_id();
|
||||
match $exposed_by_module.get_mut(&module_id) {
|
||||
match $exposed_by_module.get(&module_id) {
|
||||
Some(ExposedModuleTypes {
|
||||
exposed_types_storage_subs: exposed_types,
|
||||
resolved_specializations: _,
|
||||
|
|
@ -3922,7 +3990,7 @@ pub fn add_imports(
|
|||
}
|
||||
}
|
||||
|
||||
for symbol in exposed_for_module.imported_values {
|
||||
for &symbol in &exposed_for_module.imported_values {
|
||||
import_var_for_symbol!(subs, exposed_for_module.exposed_by_module, symbol, continue);
|
||||
}
|
||||
|
||||
|
|
@ -3948,14 +4016,14 @@ pub fn add_imports(
|
|||
|
||||
struct Ctx<'a> {
|
||||
subs: &'a mut Subs,
|
||||
exposed_by_module: &'a mut ExposedByModule,
|
||||
exposed_by_module: &'a ExposedByModule,
|
||||
}
|
||||
|
||||
let abilities_store = pending_abilities.resolve_for_module(
|
||||
my_module,
|
||||
&mut Ctx {
|
||||
subs,
|
||||
exposed_by_module: &mut exposed_for_module.exposed_by_module,
|
||||
exposed_by_module: &exposed_for_module.exposed_by_module,
|
||||
},
|
||||
|ctx, symbol| match cached_symbol_vars.get(&symbol).copied() {
|
||||
Some(var) => var,
|
||||
|
|
@ -3969,7 +4037,7 @@ pub fn add_imports(
|
|||
*cached_symbol_vars.get(&symbol).unwrap()
|
||||
}
|
||||
},
|
||||
|ctx, module, lset_var| match ctx.exposed_by_module.get_mut(&module) {
|
||||
|ctx, module, lset_var| match ctx.exposed_by_module.get(&module) {
|
||||
Some(ExposedModuleTypes {
|
||||
exposed_types_storage_subs: exposed_types,
|
||||
resolved_specializations: _,
|
||||
|
|
@ -4000,7 +4068,7 @@ fn run_solve_solve(
|
|||
pending_derives: PendingDerives,
|
||||
var_store: VarStore,
|
||||
module: Module,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> (
|
||||
Solved<Subs>,
|
||||
ResolvedSpecializations,
|
||||
|
|
@ -4025,7 +4093,7 @@ fn run_solve_solve(
|
|||
module.module_id,
|
||||
&mut subs,
|
||||
pending_abilities,
|
||||
exposed_for_module,
|
||||
&exposed_for_module,
|
||||
&mut def_types,
|
||||
&mut rigid_vars,
|
||||
);
|
||||
|
|
@ -4040,7 +4108,10 @@ fn run_solve_solve(
|
|||
}
|
||||
|
||||
let (solved_subs, solved_specializations, exposed_vars_by_symbol, problems, abilities_store) = {
|
||||
let module_id = module.module_id;
|
||||
|
||||
let (solved_subs, solved_env, problems, abilities_store) = roc_solve::module::run_solve(
|
||||
module_id,
|
||||
&constraints,
|
||||
actual_constraint,
|
||||
rigid_variables,
|
||||
|
|
@ -4048,10 +4119,10 @@ fn run_solve_solve(
|
|||
solve_aliases,
|
||||
abilities_store,
|
||||
pending_derives,
|
||||
derived_symbols,
|
||||
&exposed_for_module.exposed_by_module,
|
||||
derived_module,
|
||||
);
|
||||
|
||||
let module_id = module.module_id;
|
||||
// Figure out what specializations belong to this module
|
||||
let solved_specializations: ResolvedSpecializations = abilities_store
|
||||
.iter_specializations()
|
||||
|
|
@ -4104,7 +4175,7 @@ fn run_solve<'a>(
|
|||
decls: Declarations,
|
||||
dep_idents: IdentIdsByModule,
|
||||
cached_subs: CachedSubs,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> Msg<'a> {
|
||||
let solve_start = SystemTime::now();
|
||||
|
||||
|
|
@ -4123,7 +4194,7 @@ fn run_solve<'a>(
|
|||
pending_derives,
|
||||
var_store,
|
||||
module,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
),
|
||||
Some((subs, exposed_vars_by_symbol)) => {
|
||||
(
|
||||
|
|
@ -4145,7 +4216,7 @@ fn run_solve<'a>(
|
|||
pending_derives,
|
||||
var_store,
|
||||
module,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
|
@ -4195,7 +4266,7 @@ fn unspace<'a, T: Copy>(arena: &'a Bump, items: &[Loc<Spaced<'a, T>>]) -> &'a [L
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
fn fabricate_platform_module<'a>(
|
||||
arena: &'a Bump,
|
||||
shorthand: &'a str,
|
||||
opt_shorthand: Option<&'a str>,
|
||||
opt_app_module_id: Option<ModuleId>,
|
||||
filename: PathBuf,
|
||||
parse_state: roc_parse::state::State<'a>,
|
||||
|
|
@ -4211,7 +4282,7 @@ fn fabricate_platform_module<'a>(
|
|||
let info = PlatformHeaderInfo {
|
||||
filename,
|
||||
is_root_module,
|
||||
shorthand,
|
||||
opt_shorthand,
|
||||
opt_app_module_id,
|
||||
packages: &[],
|
||||
provides: unspace(arena, header.provides.items),
|
||||
|
|
@ -4507,7 +4578,8 @@ fn make_specializations<'a>(
|
|||
mut module_timing: ModuleTiming,
|
||||
target_info: TargetInfo,
|
||||
world_abilities: WorldAbilities,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> Msg<'a> {
|
||||
let make_specializations_start = SystemTime::now();
|
||||
let mut update_mode_ids = UpdateModeIds::new();
|
||||
|
|
@ -4521,8 +4593,9 @@ fn make_specializations<'a>(
|
|||
update_mode_ids: &mut update_mode_ids,
|
||||
// call_specialization_counter=0 is reserved
|
||||
call_specialization_counter: 1,
|
||||
abilities: AbilitiesView::World(world_abilities),
|
||||
derived_symbols: &derived_symbols,
|
||||
abilities: AbilitiesView::World(&world_abilities),
|
||||
exposed_by_module,
|
||||
derived_module: &derived_module,
|
||||
};
|
||||
|
||||
let mut procs = Procs::new_in(arena);
|
||||
|
|
@ -4584,8 +4657,9 @@ fn build_pending_specializations<'a>(
|
|||
mut layout_cache: LayoutCache<'a>,
|
||||
target_info: TargetInfo,
|
||||
exposed_to_host: ExposedToHost,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
abilities_store: AbilitiesStore,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
derived_module: SharedDerivedModule,
|
||||
) -> Msg<'a> {
|
||||
let find_specializations_start = SystemTime::now();
|
||||
|
||||
|
|
@ -4615,7 +4689,8 @@ fn build_pending_specializations<'a>(
|
|||
// to know the types and abilities in our modules. Only for building *all* specializations
|
||||
// do we need a global view.
|
||||
abilities: AbilitiesView::Module(&abilities_store),
|
||||
derived_symbols: &derived_symbols,
|
||||
exposed_by_module,
|
||||
derived_module: &derived_module,
|
||||
};
|
||||
|
||||
// Add modules' decls to Procs
|
||||
|
|
@ -4913,6 +4988,100 @@ fn build_pending_specializations<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Loads derived ability members up for specialization into the Derived module, prior to making
|
||||
/// their specializations.
|
||||
// TODO: right now, this runs sequentially, and no other modules are mono'd in parallel to the
|
||||
// derived module.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn load_derived_partial_procs<'a>(
|
||||
home: ModuleId,
|
||||
arena: &'a Bump,
|
||||
subs: &mut Subs,
|
||||
ident_ids: &mut IdentIds,
|
||||
derived_module: &SharedDerivedModule,
|
||||
module_timing: &mut ModuleTiming,
|
||||
target_info: TargetInfo,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
procs_base: &mut ProcsBase<'a>,
|
||||
world_abilities: &mut WorldAbilities,
|
||||
) {
|
||||
debug_assert_eq!(home, ModuleId::DERIVED_GEN);
|
||||
|
||||
let load_derived_procs_start = SystemTime::now();
|
||||
|
||||
let mut new_module_thunks = bumpalo::collections::Vec::new_in(arena);
|
||||
|
||||
let mut update_mode_ids = UpdateModeIds::new();
|
||||
|
||||
let derives_to_add = {
|
||||
let mut derived_module = derived_module.lock().unwrap();
|
||||
|
||||
derived_module.iter_load_for_gen_module(subs, |symbol| {
|
||||
!procs_base.partial_procs.contains_key(&symbol)
|
||||
})
|
||||
};
|
||||
|
||||
// TODO: we can be even lazier here if we move `add_def_to_module` to happen in mono. Also, the
|
||||
// timings would be more accurate.
|
||||
for (derived_symbol, derived_expr) in derives_to_add.into_iter() {
|
||||
let mut mono_env = roc_mono::ir::Env {
|
||||
arena,
|
||||
subs,
|
||||
home,
|
||||
ident_ids,
|
||||
target_info,
|
||||
update_mode_ids: &mut update_mode_ids,
|
||||
// call_specialization_counter=0 is reserved
|
||||
call_specialization_counter: 1,
|
||||
// NB: for getting pending specializations the module view is enough because we only need
|
||||
// to know the types and abilities in our modules. Only for building *all* specializations
|
||||
// do we need a global view.
|
||||
abilities: AbilitiesView::World(world_abilities),
|
||||
exposed_by_module,
|
||||
derived_module,
|
||||
};
|
||||
|
||||
let partial_proc = match derived_expr {
|
||||
roc_can::expr::Expr::Closure(roc_can::expr::ClosureData {
|
||||
function_type,
|
||||
arguments,
|
||||
loc_body,
|
||||
captured_symbols,
|
||||
return_type,
|
||||
recursive,
|
||||
..
|
||||
}) => {
|
||||
debug_assert!(captured_symbols.is_empty());
|
||||
PartialProc::from_named_function(
|
||||
&mut mono_env,
|
||||
function_type,
|
||||
arguments.clone(),
|
||||
*loc_body,
|
||||
CapturedSymbols::None,
|
||||
recursive.is_recursive(),
|
||||
return_type,
|
||||
)
|
||||
}
|
||||
_ => internal_error!("Expected only functions to be derived"),
|
||||
};
|
||||
|
||||
procs_base
|
||||
.partial_procs
|
||||
.insert(derived_symbol, partial_proc);
|
||||
}
|
||||
|
||||
if !new_module_thunks.is_empty() {
|
||||
new_module_thunks.extend(procs_base.module_thunks);
|
||||
procs_base.module_thunks = new_module_thunks.into_bump_slice();
|
||||
}
|
||||
|
||||
let load_derived_procs_end = SystemTime::now();
|
||||
|
||||
module_timing.find_specializations = load_derived_procs_end
|
||||
.duration_since(load_derived_procs_start)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn run_task<'a>(
|
||||
task: BuildTask<'a>,
|
||||
arena: &'a Bump,
|
||||
|
|
@ -4972,7 +5141,7 @@ fn run_task<'a>(
|
|||
declarations,
|
||||
dep_idents,
|
||||
cached_subs,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
} => Ok(run_solve(
|
||||
module,
|
||||
ident_ids,
|
||||
|
|
@ -4985,7 +5154,7 @@ fn run_task<'a>(
|
|||
declarations,
|
||||
dep_idents,
|
||||
cached_subs,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
)),
|
||||
BuildPendingSpecializations {
|
||||
module_id,
|
||||
|
|
@ -4997,7 +5166,8 @@ fn run_task<'a>(
|
|||
imported_module_thunks,
|
||||
exposed_to_host,
|
||||
abilities_store,
|
||||
derived_symbols,
|
||||
exposed_by_module,
|
||||
derived_module,
|
||||
} => Ok(build_pending_specializations(
|
||||
arena,
|
||||
solved_subs,
|
||||
|
|
@ -5009,8 +5179,9 @@ fn run_task<'a>(
|
|||
layout_cache,
|
||||
target_info,
|
||||
exposed_to_host,
|
||||
&exposed_by_module,
|
||||
abilities_store,
|
||||
derived_symbols,
|
||||
derived_module,
|
||||
)),
|
||||
MakeSpecializations {
|
||||
module_id,
|
||||
|
|
@ -5021,7 +5192,8 @@ fn run_task<'a>(
|
|||
specializations_we_must_make,
|
||||
module_timing,
|
||||
world_abilities,
|
||||
derived_symbols,
|
||||
exposed_by_module,
|
||||
derived_module,
|
||||
} => Ok(make_specializations(
|
||||
arena,
|
||||
module_id,
|
||||
|
|
@ -5033,7 +5205,8 @@ fn run_task<'a>(
|
|||
module_timing,
|
||||
target_info,
|
||||
world_abilities,
|
||||
derived_symbols,
|
||||
&exposed_by_module,
|
||||
derived_module,
|
||||
)),
|
||||
}?;
|
||||
|
||||
|
|
|
|||
|
|
@ -39,16 +39,87 @@ enum Job<'a> {
|
|||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct MakeSpecializationInfo {
|
||||
/// Modules to make specializations for after they are made for this module
|
||||
succ: MutSet<ModuleId>,
|
||||
/// Whether this module depends on specializations being made for another module
|
||||
has_pred: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MakeSpecializationsDependents(MutMap<ModuleId, MakeSpecializationInfo>);
|
||||
|
||||
impl MakeSpecializationsDependents {
|
||||
/// Gets the info entry for a module, or creates a default one.
|
||||
fn entry(&mut self, module_id: ModuleId) -> &mut MakeSpecializationInfo {
|
||||
self.0.entry(module_id).or_default()
|
||||
}
|
||||
|
||||
fn mark_has_pred(&mut self, module_id: ModuleId) {
|
||||
self.entry(module_id).has_pred = true;
|
||||
}
|
||||
|
||||
fn add_succ(&mut self, module_id: ModuleId, succ: impl IntoIterator<Item = ModuleId>) {
|
||||
// Add make specialization dependents
|
||||
let entry = self.entry(module_id);
|
||||
debug_assert!(
|
||||
entry.succ.is_empty(),
|
||||
"already added successors for this module"
|
||||
);
|
||||
|
||||
entry.succ.extend(succ.into_iter());
|
||||
|
||||
// The module for derives implicitly depends on every other module
|
||||
entry.succ.insert(ModuleId::DERIVED_GEN);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MakeSpecializationsDependents {
|
||||
fn default() -> Self {
|
||||
let mut map: MutMap<ModuleId, MakeSpecializationInfo> = Default::default();
|
||||
|
||||
// The module for derives is always at the base as the last module to specialize
|
||||
map.insert(
|
||||
ModuleId::DERIVED_GEN,
|
||||
MakeSpecializationInfo {
|
||||
succ: Default::default(),
|
||||
// NB: invariant - the derived module depends on every other module, and
|
||||
// work can never be initiated for just the derived module!
|
||||
has_pred: true,
|
||||
},
|
||||
);
|
||||
|
||||
Self(map)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Dependencies<'a> {
|
||||
waiting_for: MutMap<Job<'a>, MutSet<Job<'a>>>,
|
||||
notifies: MutMap<Job<'a>, MutSet<Job<'a>>>,
|
||||
status: MutMap<Job<'a>, Status>,
|
||||
|
||||
/// module -> modules to make specializations after, whether a module comes before us
|
||||
make_specializations_dependents: MutMap<ModuleId, (MutSet<ModuleId>, bool)>,
|
||||
make_specializations_dependents: MakeSpecializationsDependents,
|
||||
}
|
||||
|
||||
impl<'a> Dependencies<'a> {
|
||||
pub fn new(goal_phase: Phase) -> Self {
|
||||
let mut deps = Self {
|
||||
waiting_for: Default::default(),
|
||||
notifies: Default::default(),
|
||||
status: Default::default(),
|
||||
make_specializations_dependents: Default::default(),
|
||||
};
|
||||
|
||||
if goal_phase >= Phase::MakeSpecializations {
|
||||
// Module for deriving is always implicitly loaded into the work graph, but it only
|
||||
// comes into play for make specializations.
|
||||
deps.add_to_status_for_phase(ModuleId::DERIVED_GEN, Phase::MakeSpecializations);
|
||||
}
|
||||
|
||||
deps
|
||||
}
|
||||
|
||||
/// Add all the dependencies for a module, return (module, phase) pairs that can make progress
|
||||
pub fn add_module(
|
||||
&mut self,
|
||||
|
|
@ -86,24 +157,19 @@ impl<'a> Dependencies<'a> {
|
|||
|
||||
if goal_phase >= MakeSpecializations {
|
||||
self.add_dependency(dep, module_id, Phase::MakeSpecializations);
|
||||
// The module for derives implicitly depends on every other module
|
||||
self.add_dependency(ModuleId::DERIVED_GEN, module_id, Phase::MakeSpecializations);
|
||||
|
||||
let dep_entry = self
|
||||
.make_specializations_dependents
|
||||
.entry(dep)
|
||||
.or_insert((MutSet::default(), false));
|
||||
dep_entry.1 = true;
|
||||
// `dep` depends on `module_id` making specializations first
|
||||
self.make_specializations_dependents.mark_has_pred(dep);
|
||||
}
|
||||
}
|
||||
|
||||
// Add make specialization dependents
|
||||
let entry = self
|
||||
.make_specializations_dependents
|
||||
.entry(module_id)
|
||||
.or_insert((MutSet::default(), false));
|
||||
debug_assert!(entry.0.is_empty(), "already seen this dep");
|
||||
entry
|
||||
.0
|
||||
.extend(dependencies.iter().map(|dep| *dep.as_inner()));
|
||||
if goal_phase >= MakeSpecializations {
|
||||
// Add make specialization dependents
|
||||
self.make_specializations_dependents
|
||||
.add_succ(module_id, dependencies.iter().map(|dep| *dep.as_inner()));
|
||||
}
|
||||
|
||||
// add dependencies for self
|
||||
// phase i + 1 of a file always depends on phase i being completed
|
||||
|
|
@ -115,20 +181,26 @@ impl<'a> Dependencies<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
self.add_to_status(module_id, goal_phase);
|
||||
self.add_to_status_for_all_phases(module_id, goal_phase);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn add_to_status(&mut self, module_id: ModuleId, goal_phase: Phase) {
|
||||
/// Adds a status for the given module for exactly one phase.
|
||||
fn add_to_status_for_phase(&mut self, module_id: ModuleId, phase: Phase) {
|
||||
if let Entry::Vacant(entry) = self.status.entry(Job::Step(module_id, phase)) {
|
||||
entry.insert(Status::NotStarted);
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a status for the given module for all phases up to and including the goal phase.
|
||||
fn add_to_status_for_all_phases(&mut self, module_id: ModuleId, goal_phase: Phase) {
|
||||
for phase in PHASES.iter() {
|
||||
if *phase > goal_phase {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Entry::Vacant(entry) = self.status.entry(Job::Step(module_id, *phase)) {
|
||||
entry.insert(Status::NotStarted);
|
||||
}
|
||||
self.add_to_status_for_phase(module_id, *phase);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -305,13 +377,14 @@ impl<'a> Dependencies<'a> {
|
|||
pub fn reload_make_specialization_pass(&mut self) -> MutSet<(ModuleId, Phase)> {
|
||||
let mut output = MutSet::default();
|
||||
|
||||
let mut make_specializations_dependents = Default::default();
|
||||
let mut make_specializations_dependents = MakeSpecializationsDependents::default();
|
||||
let default_make_specializations_dependents_len = make_specializations_dependents.0.len();
|
||||
std::mem::swap(
|
||||
&mut self.make_specializations_dependents,
|
||||
&mut make_specializations_dependents,
|
||||
);
|
||||
|
||||
for (&module, _) in make_specializations_dependents.iter() {
|
||||
for (&module, _) in make_specializations_dependents.0.iter() {
|
||||
let job = Job::Step(module, Phase::MakeSpecializations);
|
||||
let status = self.status.get_mut(&job).unwrap();
|
||||
debug_assert!(
|
||||
|
|
@ -324,12 +397,14 @@ impl<'a> Dependencies<'a> {
|
|||
// `add_dependency` borrows self as mut so we move `make_specializations_dependents` out
|
||||
// for our local use. `add_dependency` should never grow the make specializations
|
||||
// dependency graph.
|
||||
for (&module, (succ, has_pred)) in make_specializations_dependents.iter() {
|
||||
for (&module, MakeSpecializationInfo { succ, has_pred }) in
|
||||
make_specializations_dependents.0.iter()
|
||||
{
|
||||
for &dependent in succ {
|
||||
self.add_dependency(dependent, module, Phase::MakeSpecializations);
|
||||
}
|
||||
|
||||
self.add_to_status(module, Phase::MakeSpecializations);
|
||||
self.add_to_status_for_phase(module, Phase::MakeSpecializations);
|
||||
if !has_pred {
|
||||
output.insert((module, Phase::MakeSpecializations));
|
||||
}
|
||||
|
|
@ -339,9 +414,11 @@ impl<'a> Dependencies<'a> {
|
|||
&mut self.make_specializations_dependents,
|
||||
&mut make_specializations_dependents,
|
||||
);
|
||||
debug_assert!(
|
||||
make_specializations_dependents.is_empty(),
|
||||
"more modules were added to the graph"
|
||||
debug_assert_eq!(
|
||||
make_specializations_dependents.0.len(),
|
||||
default_make_specializations_dependents_len,
|
||||
"more modules were added to the graph: {:?}",
|
||||
make_specializations_dependents
|
||||
);
|
||||
|
||||
output
|
||||
|
|
|
|||
|
|
@ -35,13 +35,12 @@ use std::path::PathBuf;
|
|||
fn load_and_typecheck(
|
||||
arena: &Bump,
|
||||
filename: PathBuf,
|
||||
src_dir: PathBuf,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<LoadedModule, LoadingProblem> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, src_dir, filename, RenderTarget::Generic)?;
|
||||
let load_start = LoadStart::from_path(arena, filename, RenderTarget::Generic)?;
|
||||
|
||||
match roc_load_internal::file::load(
|
||||
arena,
|
||||
|
|
@ -163,13 +162,7 @@ fn multiple_modules_help<'a>(
|
|||
writeln!(file, "{}", source)?;
|
||||
file_handles.push(file);
|
||||
|
||||
load_and_typecheck(
|
||||
arena,
|
||||
full_file_path,
|
||||
dir.path().to_path_buf(),
|
||||
Default::default(),
|
||||
TARGET_INFO,
|
||||
)
|
||||
load_and_typecheck(arena, full_file_path, Default::default(), TARGET_INFO)
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
|
|
@ -183,7 +176,7 @@ fn load_fixture(
|
|||
let src_dir = fixtures_dir().join(dir_name);
|
||||
let filename = src_dir.join(format!("{}.roc", module_name));
|
||||
let arena = Bump::new();
|
||||
let loaded = load_and_typecheck(&arena, filename, src_dir, subs_by_module, TARGET_INFO);
|
||||
let loaded = load_and_typecheck(&arena, filename, subs_by_module, TARGET_INFO);
|
||||
let mut loaded_module = match loaded {
|
||||
Ok(x) => x,
|
||||
Err(roc_load_internal::file::LoadingProblem::FormattedReport(report)) => {
|
||||
|
|
@ -339,7 +332,7 @@ fn interface_with_deps() {
|
|||
let src_dir = fixtures_dir().join("interface_with_deps");
|
||||
let filename = src_dir.join("Primary.roc");
|
||||
let arena = Bump::new();
|
||||
let loaded = load_and_typecheck(&arena, filename, src_dir, subs_by_module, TARGET_INFO);
|
||||
let loaded = load_and_typecheck(&arena, filename, subs_by_module, TARGET_INFO);
|
||||
|
||||
let mut loaded_module = loaded.expect("Test module failed to load");
|
||||
let home = loaded_module.module_id;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue