Get load::file compiling.

This commit is contained in:
Richard Feldman 2020-08-02 20:53:38 -04:00
parent 8434af4e63
commit 406087970b

View file

@ -1,7 +1,7 @@
use bumpalo::Bump; use bumpalo::Bump;
use crossbeam::channel::{bounded, Receiver, RecvError, SendError, Sender}; use crossbeam::channel::{bounded, Sender};
use crossbeam::deque::{Injector, Stealer, Worker}; use crossbeam::deque::{Injector, Stealer, Worker};
use crossbeam::thread::{self, Scope}; use crossbeam::thread;
use roc_builtins::std::{Mode, StdLib}; use roc_builtins::std::{Mode, StdLib};
use roc_can::constraint::Constraint; use roc_can::constraint::Constraint;
use roc_can::def::Declaration; use roc_can::def::Declaration;
@ -21,7 +21,7 @@ use roc_solve::module::SolvedModule;
use roc_solve::solve; use roc_solve::solve;
use roc_types::solved_types::Solved; use roc_types::solved_types::Solved;
use roc_types::subs::{Subs, VarStore, Variable}; use roc_types::subs::{Subs, VarStore, Variable};
use roc_types::types::{Alias, Type}; use roc_types::types::Alias;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fs; use std::fs;
use std::io; use std::io;
@ -195,7 +195,6 @@ type SharedModules<'a, 'b> = MaybeShared<'a, 'b, ModuleIds, IdentIdsByModule>;
type IdentIdsByModule = MutMap<ModuleId, IdentIds>; type IdentIdsByModule = MutMap<ModuleId, IdentIds>;
type MsgSender<'a> = Sender<Msg<'a>>; type MsgSender<'a> = Sender<Msg<'a>>;
type MsgReceiver<'a> = Receiver<Msg<'a>>;
/// Add a task to the queue, and notify all the listeners. /// Add a task to the queue, and notify all the listeners.
fn enqueue_task<'a, 'b>( fn enqueue_task<'a, 'b>(
@ -258,12 +257,10 @@ fn enqueue_task<'a, 'b>(
/// specializations, so if none of their specializations changed, we don't even need /// 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.) /// to rebuild the module and can link in the cached one directly.)
// #[allow(clippy::cognitive_complexity)] // #[allow(clippy::cognitive_complexity)]
fn load( pub fn load(
filename: PathBuf, filename: PathBuf,
stdlib: &StdLib, stdlib: &StdLib,
src_dir: &Path, src_dir: &Path,
arc_modules: Arc<Mutex<ModuleIds>>,
ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>,
exposed_types: SubsByModule, exposed_types: SubsByModule,
) -> Result<LoadedModule, LoadingProblem> { ) -> Result<LoadedModule, LoadingProblem> {
use self::MaybeShared::*; use self::MaybeShared::*;
@ -286,15 +283,18 @@ fn load(
let ident_ids_by_module = Arc::new(Mutex::new(root_exposed_ident_ids)); let ident_ids_by_module = Arc::new(Mutex::new(root_exposed_ident_ids));
// Load the root module synchronously; we can't proceed until we have its id. // Load the root module synchronously; we can't proceed until we have its id.
let root_id = load_filename( let (root_id, root_msg) = load_filename(
&arena, &arena,
filename, filename,
msg_tx.clone(),
Shared(Arc::clone(&arc_modules), Arc::clone(&ident_ids_by_module)), Shared(Arc::clone(&arc_modules), Arc::clone(&ident_ids_by_module)),
// TODO FIXME go back to using Unique here, not Shared // TODO FIXME go back to using Unique here, not Shared
// Unique(&mut module_ids, &mut root_exposed_ident_ids), // Unique(&mut module_ids, &mut root_exposed_ident_ids),
)?; )?;
msg_tx
.send(root_msg)
.map_err(|_| LoadingProblem::MsgChannelDied)?;
// We'll add tasks to this, and then worker threads will take tasks from it. // We'll add tasks to this, and then worker threads will take tasks from it.
let injector = Injector::new(); let injector = Injector::new();
@ -382,7 +382,8 @@ fn load(
// queue - and run it. // queue - and run it.
match find_task(&worker, injector, stealers) { match find_task(&worker, injector, stealers) {
Some(task) => { Some(task) => {
run_task(task, worker_arena, src_dir, msg_tx.clone(), stdlib); run_task(task, worker_arena, src_dir, msg_tx.clone(), stdlib)
.expect("Msg channel closed unexpectedly.");
} }
None => { None => {
// No tasks to work on! This might be because // No tasks to work on! This might be because
@ -656,7 +657,6 @@ fn update<'a>(
constraint, constraint,
var_store, var_store,
imported_modules, imported_modules,
msg_tx.clone(),
&mut state.exposed_types, &mut state.exposed_types,
stdlib, stdlib,
), ),
@ -738,7 +738,6 @@ fn update<'a>(
constraint, constraint,
var_store, var_store,
imported_modules, imported_modules,
msg_tx.clone(),
&mut state.exposed_types, &mut state.exposed_types,
stdlib, stdlib,
), ),
@ -792,9 +791,8 @@ fn load_module<'a>(
arena: &'a Bump, arena: &'a Bump,
src_dir: &Path, src_dir: &Path,
module_name: ModuleName, module_name: ModuleName,
msg_tx: MsgSender<'a>,
module_ids: SharedModules<'a, '_>, module_ids: SharedModules<'a, '_>,
) -> Result<ModuleId, LoadingProblem> { ) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
let mut filename = PathBuf::new(); let mut filename = PathBuf::new();
filename.push(src_dir); filename.push(src_dir);
@ -807,7 +805,7 @@ fn load_module<'a>(
// End with .roc // End with .roc
filename.set_extension(ROC_FILE_EXTENSION); filename.set_extension(ROC_FILE_EXTENSION);
load_filename(arena, filename, msg_tx, module_ids) load_filename(arena, filename, module_ids)
} }
/// Find a task according to the following algorithm: /// Find a task according to the following algorithm:
@ -839,63 +837,45 @@ fn find_task<T>(local: &Worker<T>, global: &Injector<T>, stealers: &[Stealer<T>]
fn parse_src<'a>( fn parse_src<'a>(
arena: &'a Bump, arena: &'a Bump,
filename: PathBuf, filename: PathBuf,
msg_tx: MsgSender<'a>,
module_ids: SharedModules<'_, '_>, module_ids: SharedModules<'_, '_>,
src_bytes: &'a [u8], src_bytes: &'a [u8],
) -> Result<ModuleId, LoadingProblem> { ) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
let parse_state = parser::State::new(src_bytes, Attempting::Module); let parse_state = parser::State::new(src_bytes, Attempting::Module);
// TODO figure out if there's a way to address this clippy error match roc_parse::module::header().parse(&arena, parse_state) {
// without introducing a borrow error. ("let and return" is literally Ok((ast::Module::Interface { header }, parse_state)) => Ok(send_header(
// what the borrow checker suggested using here to fix the problem, so...)
#[allow(clippy::let_and_return)]
let answer = match roc_parse::module::header().parse(&arena, parse_state) {
Ok((ast::Module::Interface { header }, parse_state)) => {
let module_id = send_header(
header.name, header.name,
header.exposes.into_bump_slice(), header.exposes.into_bump_slice(),
header.imports.into_bump_slice(), header.imports.into_bump_slice(),
parse_state, parse_state,
module_ids, module_ids,
msg_tx, )),
);
Ok(module_id)
}
Ok((ast::Module::App { header }, parse_state)) => match module_ids { Ok((ast::Module::App { header }, parse_state)) => match module_ids {
MaybeShared::Shared(_, _) => { MaybeShared::Shared(_, _) => {
// If this is Shared, it means we're trying to import // If this is Shared, it means we're trying to import
// an app module which is not the root. Not alllowed! // an app module which is not the root. Not alllowed!
Err(LoadingProblem::TriedToImportAppModule) Err(LoadingProblem::TriedToImportAppModule)
} }
unique_modules @ MaybeShared::Unique(_, _) => { unique_modules @ MaybeShared::Unique(_, _) => Ok(send_header(
let module_id = send_header(
header.name, header.name,
header.provides.into_bump_slice(), header.provides.into_bump_slice(),
header.imports.into_bump_slice(), header.imports.into_bump_slice(),
parse_state, parse_state,
unique_modules, unique_modules,
msg_tx, )),
);
Ok(module_id)
}
}, },
Err((fail, _)) => Err(LoadingProblem::ParsingFailed { filename, fail }), Err((fail, _)) => Err(LoadingProblem::ParsingFailed { filename, fail }),
}; }
answer
} }
/// Load a module by its filename /// Load a module by its filename
fn load_filename<'a>( fn load_filename<'a>(
arena: &'a Bump, arena: &'a Bump,
filename: PathBuf, filename: PathBuf,
msg_tx: MsgSender<'a>,
module_ids: SharedModules<'a, '_>, module_ids: SharedModules<'a, '_>,
) -> Result<ModuleId, LoadingProblem> { ) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
match fs::read(&filename) { match fs::read(&filename) {
Ok(bytes) => parse_src(arena, filename, msg_tx, module_ids, arena.alloc(bytes)), Ok(bytes) => parse_src(arena, filename, module_ids, arena.alloc(bytes)),
Err(err) => Err(LoadingProblem::FileProblem { Err(err) => Err(LoadingProblem::FileProblem {
filename, filename,
error: err.kind(), error: err.kind(),
@ -909,8 +889,7 @@ fn send_header<'a>(
imports: &'a [Located<ImportsEntry<'a>>], imports: &'a [Located<ImportsEntry<'a>>],
parse_state: parser::State<'a>, parse_state: parser::State<'a>,
shared_modules: SharedModules<'_, '_>, shared_modules: SharedModules<'_, '_>,
msg_tx: MsgSender<'a>, ) -> (ModuleId, Msg<'a>) {
) -> ModuleId {
use MaybeShared::*; use MaybeShared::*;
let declared_name: ModuleName = name.value.as_str().into(); let declared_name: ModuleName = name.value.as_str().into();
@ -1070,8 +1049,9 @@ fn send_header<'a>(
// to decrement its "pending" count. // to decrement its "pending" count.
// Send the header the main thread for processing, // Send the header the main thread for processing,
msg_tx (
.send(Msg::Header(ModuleHeader { home,
Msg::Header(ModuleHeader {
module_id: home, module_id: home,
exposed_ident_ids: ident_ids, exposed_ident_ids: ident_ids,
module_name: declared_name, module_name: declared_name,
@ -1080,10 +1060,8 @@ fn send_header<'a>(
exposes: exposed, exposes: exposed,
src: parse_state.bytes, src: parse_state.bytes,
exposed_imports: scope, exposed_imports: scope,
})) }),
.unwrap_or_else(|_| panic!("Failed to send Header message for module ID: {:?}", home)); )
home
} }
fn add_exposed_to_scope( fn add_exposed_to_scope(
@ -1111,9 +1089,8 @@ impl<'a, 'b> BuildTask<'a, 'b> {
module: Module, module: Module,
src: &'a str, src: &'a str,
constraint: Constraint, constraint: Constraint,
mut var_store: VarStore, var_store: VarStore,
imported_modules: MutSet<ModuleId>, imported_modules: MutSet<ModuleId>,
msg_tx: MsgSender,
exposed_types: &mut SubsByModule, exposed_types: &mut SubsByModule,
stdlib: &StdLib, stdlib: &StdLib,
) -> Self { ) -> Self {
@ -1261,85 +1238,80 @@ fn run_solve<'a>(
} }
} }
///// Parse the module, canonicalize it, and generate constraints for it. /// Parse the module, canonicalize it, and generate constraints for it.
//fn parse_and_constrain( fn parse_and_constrain<'a>(
// header: ModuleHeader, header: ModuleHeader<'a>,
// mode: Mode, mode: Mode,
// module_ids: ModuleIds, module_ids: ModuleIds,
// dep_idents: IdentIdsByModule, dep_idents: IdentIdsByModule,
// exposed_symbols: MutSet<Symbol>, exposed_symbols: MutSet<Symbol>,
// msg_tx: MsgSender, ) -> Result<Msg<'a>, LoadingProblem> {
//) { let module_id = header.module_id;
// let module_id = header.module_id; let mut var_store = VarStore::default();
// let mut var_store = VarStore::default(); let arena = Bump::new();
// let arena = Bump::new(); let parse_state = parser::State::new(&header.src, Attempting::Module);
// let parse_state = parser::State::new(&header.src, Attempting::Module);
// let (parsed_defs, _) = module_defs() let (parsed_defs, _) = module_defs()
// .parse(&arena, parse_state) .parse(&arena, parse_state)
// .expect("TODO gracefully handle parse error on module defs. IMPORTANT: Bail out entirely if there are any BadUtf8 problems! That means the whole source file is not valid UTF-8 and any other errors we report may get mis-reported. We rely on this for safety in an `unsafe` block later on in this function."); .expect("TODO gracefully handle parse error on module defs. IMPORTANT: Bail out entirely if there are any BadUtf8 problems! That means the whole source file is not valid UTF-8 and any other errors we report may get mis-reported. We rely on this for safety in an `unsafe` block later on in this function.");
// let (module, declarations, ident_ids, constraint, problems) = match canonicalize_module_defs( let (module, declarations, ident_ids, constraint, problems) = match canonicalize_module_defs(
// &arena, &arena,
// parsed_defs, parsed_defs,
// module_id, module_id,
// &module_ids, &module_ids,
// header.exposed_ident_ids, header.exposed_ident_ids,
// dep_idents, dep_idents,
// header.exposed_imports, header.exposed_imports,
// exposed_symbols, exposed_symbols,
// &mut var_store, &mut var_store,
// ) { ) {
// Ok(module_output) => { Ok(module_output) => {
// let constraint = constrain_module(&module_output, module_id, mode, &mut var_store); let constraint = constrain_module(&module_output, module_id, mode, &mut var_store);
// let module = Module { let module = Module {
// module_id, module_id,
// exposed_imports: module_output.exposed_imports, exposed_imports: module_output.exposed_imports,
// exposed_vars_by_symbol: module_output.exposed_vars_by_symbol, exposed_vars_by_symbol: module_output.exposed_vars_by_symbol,
// references: module_output.references, references: module_output.references,
// aliases: module_output.aliases, aliases: module_output.aliases,
// rigid_variables: module_output.rigid_variables, rigid_variables: module_output.rigid_variables,
// }; };
// ( (
// module, module,
// module_output.declarations, module_output.declarations,
// module_output.ident_ids, module_output.ident_ids,
// constraint, constraint,
// module_output.problems, module_output.problems,
// ) )
// } }
// Err(runtime_error) => { Err(runtime_error) => {
// panic!( panic!(
// "TODO gracefully handle module canonicalization error {:?}", "TODO gracefully handle module canonicalization error {:?}",
// runtime_error runtime_error
// ); );
// } }
// }; };
// let imported_modules = header.imported_modules; let imported_modules = header.imported_modules;
// // SAFETY: By this point we've already incrementally verified that there // SAFETY: By this point we've already incrementally verified that there
// // are no UTF-8 errors in these bytes. If there had been any UTF-8 errors, // are no UTF-8 errors in these bytes. If there had been any UTF-8 errors,
// // we'd have bailed out before now. // we'd have bailed out before now.
// let src: Box<str> = unsafe { from_utf8_unchecked(header.src.as_ref()).to_string().into() }; let src = unsafe { from_utf8_unchecked(header.src.as_ref()) };
// thread_scope.spawn(move |_| { // Send the constraint to the main thread for processing.
// // Send the constraint to the main thread for processing. Ok(Msg::Constrained {
// msg_tx module,
// .send(Msg::Constrained { src,
// module, declarations,
// src, imported_modules,
// declarations, ident_ids,
// imported_modules, constraint,
// ident_ids, problems,
// constraint, var_store,
// problems, })
// var_store, }
// })
// .unwrap_or_else(|_| panic!("Failed to send Constrained message"));
// });
//}
fn exposed_from_import(entry: &ImportsEntry<'_>) -> (ModuleName, Vec<Ident>) { fn exposed_from_import(entry: &ImportsEntry<'_>) -> (ModuleName, Vec<Ident>) {
use roc_parse::ast::ImportsEntry::*; use roc_parse::ast::ImportsEntry::*;
@ -1380,26 +1352,18 @@ fn run_task<'a, 'b>(
) -> Result<(), LoadingProblem> { ) -> Result<(), LoadingProblem> {
use BuildTask::*; use BuildTask::*;
match task { let msg = match task {
LoadModule { LoadModule {
module_name, module_name,
module_ids, module_ids,
} => { } => load_module(arena, src_dir, module_name, module_ids).map(|(_, msg)| msg),
let module_id = load_module(arena, src_dir, module_name, msg_tx, module_ids)?;
Ok(())
}
ParseAndConstrain { ParseAndConstrain {
header, header,
mode, mode,
module_ids, module_ids,
dep_idents, dep_idents,
exposed_symbols, exposed_symbols,
} => { } => parse_and_constrain(header, mode, module_ids, dep_idents, exposed_symbols),
//TODO
Ok(())
}
Solve { Solve {
module, module,
imported_symbols, imported_symbols,
@ -1407,8 +1371,7 @@ fn run_task<'a, 'b>(
constraint, constraint,
var_store, var_store,
src, src,
} => { } => Ok(run_solve(
let msg = run_solve(
module, module,
stdlib, stdlib,
imported_symbols, imported_symbols,
@ -1416,9 +1379,12 @@ fn run_task<'a, 'b>(
constraint, constraint,
var_store, var_store,
src, src,
); )),
}?;
msg_tx
.send(msg)
.map_err(|_| LoadingProblem::MsgChannelDied)?;
Ok(()) Ok(())
} }
}
}