Merge remote-tracking branch 'origin/trunk' into dict

This commit is contained in:
Folkert 2021-02-10 15:02:53 +01:00
commit 0ed87828e5
76 changed files with 4113 additions and 8034 deletions

View file

@ -27,7 +27,7 @@ use roc_parse::header::{
ExposesEntry, ImportsEntry, PackageEntry, PackageOrPath, PlatformHeader, To, TypedIdent,
};
use roc_parse::module::module_defs;
use roc_parse::parser::{self, Fail, Parser};
use roc_parse::parser::{self, ParseProblem, Parser, SyntaxError};
use roc_region::all::{Located, Region};
use roc_solve::module::SolvedModule;
use roc_solve::solve;
@ -762,6 +762,8 @@ enum Msg<'a> {
subs: Subs,
exposed_to_host: MutMap<Symbol, Variable>,
},
FailedToParse(ParseProblem<'a, SyntaxError<'a>>),
}
#[derive(Debug)]
@ -968,20 +970,20 @@ enum WorkerMsg {
}
#[derive(Debug)]
pub enum LoadingProblem {
pub enum LoadingProblem<'a> {
FileProblem {
filename: PathBuf,
error: io::ErrorKind,
msg: &'static str,
},
ParsingFailed {
filename: PathBuf,
fail: Fail,
},
ParsingFailed(ParseProblem<'a, SyntaxError<'a>>),
UnexpectedHeader(String),
MsgChannelDied,
ErrJoiningWorkerThreads,
TriedToImportAppModule,
/// a formatted report of parsing failure
ParsingFailedReport(String),
}
pub enum Phases {
@ -998,7 +1000,7 @@ fn enqueue_task<'a>(
injector: &Injector<BuildTask<'a>>,
listeners: &[Sender<WorkerMsg>],
task: BuildTask<'a>,
) -> Result<(), LoadingProblem> {
) -> Result<(), LoadingProblem<'a>> {
injector.push(task);
for listener in listeners {
@ -1010,15 +1012,15 @@ fn enqueue_task<'a>(
Ok(())
}
pub fn load_and_typecheck<F>(
arena: &Bump,
pub fn load_and_typecheck<'a, F>(
arena: &'a Bump,
filename: PathBuf,
stdlib: &StdLib,
stdlib: &'a StdLib,
src_dir: &Path,
exposed_types: SubsByModule,
ptr_bytes: u32,
look_up_builtin: F,
) -> Result<LoadedModule, LoadingProblem>
) -> Result<LoadedModule, LoadingProblem<'a>>
where
F: Fn(Symbol, &mut VarStore) -> Option<Def> + 'static + Send + Copy,
{
@ -1049,7 +1051,7 @@ pub fn load_and_monomorphize<'a, F>(
exposed_types: SubsByModule,
ptr_bytes: u32,
look_up_builtin: F,
) -> Result<MonomorphizedModule<'a>, LoadingProblem>
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>>
where
F: Fn(Symbol, &mut VarStore) -> Option<Def> + 'static + Send + Copy,
{
@ -1082,7 +1084,7 @@ pub fn load_and_monomorphize_from_str<'a, F>(
exposed_types: SubsByModule,
ptr_bytes: u32,
look_up_builtin: F,
) -> Result<MonomorphizedModule<'a>, LoadingProblem>
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>>
where
F: Fn(Symbol, &mut VarStore) -> Option<Def> + 'static + Send + Copy,
{
@ -1117,7 +1119,7 @@ impl<'a> LoadStart<'a> {
arena: &'a Bump,
filename: PathBuf,
mode: Mode,
) -> Result<Self, LoadingProblem> {
) -> 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));
@ -1150,7 +1152,7 @@ impl<'a> LoadStart<'a> {
filename: PathBuf,
src: &'a str,
mode: Mode,
) -> Result<Self, LoadingProblem> {
) -> 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));
@ -1238,7 +1240,7 @@ fn load<'a, F>(
goal_phase: Phase,
ptr_bytes: u32,
look_up_builtins: F,
) -> Result<LoadResult<'a>, LoadingProblem>
) -> Result<LoadResult<'a>, LoadingProblem<'a>>
where
F: Fn(Symbol, &mut VarStore) -> Option<Def> + 'static + Send + Copy,
{
@ -1329,7 +1331,7 @@ where
let injector = &injector;
// Record this thread's handle so the main thread can join it later.
thread_scope
let res_join_handle = thread_scope
.builder()
.stack_size(EXPANDED_STACK_SIZE)
.spawn(move |_| {
@ -1342,7 +1344,7 @@ where
// shut down the thread, so when the main thread
// blocks on joining with all the worker threads,
// it can finally exit too!
return;
return Ok(());
}
WorkerMsg::TaskAdded => {
// Find a task - either from this thread's queue,
@ -1355,15 +1357,27 @@ where
// added. In that case, do nothing, and keep waiting
// until we receive a Shutdown message.
if let Some(task) = find_task(&worker, injector, stealers) {
run_task(
let result = run_task(
task,
worker_arena,
src_dir,
msg_tx.clone(),
ptr_bytes,
look_up_builtins,
)
.expect("Msg channel closed unexpectedly.");
);
match result {
Ok(()) => {}
Err(LoadingProblem::MsgChannelDied) => {
panic!("Msg channel closed unexpectedly.")
}
Err(LoadingProblem::ParsingFailed(problem)) => {
msg_tx.send(Msg::FailedToParse(problem)).unwrap();
}
Err(other) => {
return Err(other);
}
}
}
}
}
@ -1372,8 +1386,11 @@ where
// Needed to prevent a borrow checker error about this closure
// outliving its enclosing function.
drop(worker_msg_rx);
})
.unwrap();
Ok(())
});
res_join_handle.unwrap();
}
let mut state = State {
@ -1461,6 +1478,51 @@ where
exposed_to_host,
)));
}
Msg::FailedToParse(problem) => {
// Shut down all the worker threads.
for listener in worker_listeners {
listener
.send(WorkerMsg::Shutdown)
.map_err(|_| LoadingProblem::MsgChannelDied)?;
}
use roc_reporting::report::{
parse_problem, RocDocAllocator, DEFAULT_PALETTE,
};
// TODO this is not in fact safe
let src = unsafe { from_utf8_unchecked(problem.bytes) };
let src_lines: Vec<&str> = src.split('\n').collect();
let palette = DEFAULT_PALETTE;
let mut module_ids = Arc::try_unwrap(state.arc_modules)
.unwrap_or_else(|_| {
panic!("There were still outstanding Arc references to module_ids")
})
.into_inner()
.into_module_ids();
let module_id =
module_ids.get_or_insert(&"find module name somehow?".into());
let interns = Interns {
module_ids,
all_ident_ids: state.constrained_ident_ids,
};
// Report parsing and canonicalization problems
let alloc = RocDocAllocator::new(&src_lines, module_id, &interns);
let starting_line = 0;
let report =
parse_problem(&alloc, problem.filename.clone(), starting_line, problem);
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
return Err(LoadingProblem::ParsingFailedReport(buf));
}
msg => {
// This is where most of the main thread's work gets done.
// Everything up to this point has been setting up the threading
@ -1489,7 +1551,7 @@ fn start_tasks<'a>(
state: &mut State<'a>,
injector: &Injector<BuildTask<'a>>,
worker_listeners: &'a [Sender<WorkerMsg>],
) -> Result<(), LoadingProblem> {
) -> Result<(), LoadingProblem<'a>> {
for (module_id, phase) in work {
for task in start_phase(module_id, phase, state) {
enqueue_task(&injector, worker_listeners, task)?
@ -1506,7 +1568,7 @@ fn update<'a>(
injector: &Injector<BuildTask<'a>>,
worker_listeners: &'a [Sender<WorkerMsg>],
arena: &'a Bump,
) -> Result<State<'a>, LoadingProblem> {
) -> Result<State<'a>, LoadingProblem<'a>> {
use self::Msg::*;
match msg {
@ -1963,6 +2025,9 @@ fn update<'a>(
Msg::FinishedAllSpecialization { .. } => {
unreachable!();
}
Msg::FailedToParse(_) => {
unreachable!();
}
}
}
@ -2085,7 +2150,7 @@ fn load_pkg_config<'a>(
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
mode: Mode,
) -> Result<Msg<'a>, LoadingProblem> {
) -> Result<Msg<'a>, LoadingProblem<'a>> {
let module_start_time = SystemTime::now();
let filename = PathBuf::from(src_dir);
@ -2095,9 +2160,10 @@ fn load_pkg_config<'a>(
let file_io_duration = file_io_start.elapsed().unwrap();
match file {
Ok(bytes) => {
Ok(bytes_vec) => {
let parse_start = SystemTime::now();
let parse_state = parser::State::new(arena.alloc(bytes), Attempting::Module);
let bytes = arena.alloc(bytes_vec);
let parse_state = parser::State::new_in(arena, bytes, Attempting::Module);
let parsed = roc_parse::module::header().parse(&arena, parse_state);
let parse_header_duration = parse_start.elapsed().unwrap();
@ -2112,19 +2178,19 @@ fn load_pkg_config<'a>(
effect_module_timing.parse_header = parse_header_duration;
match parsed {
Ok((ast::Module::Interface { header }, _parse_state)) => {
Ok((_, ast::Module::Interface { header }, _parse_state)) => {
Err(LoadingProblem::UnexpectedHeader(format!(
"expected platform/package module, got Interface with header\n{:?}",
header
)))
}
Ok((ast::Module::App { header }, _parse_state)) => {
Ok((_, ast::Module::App { header }, _parse_state)) => {
Err(LoadingProblem::UnexpectedHeader(format!(
"expected platform/package module, got App with header\n{:?}",
header
)))
}
Ok((ast::Module::Platform { header }, parser_state)) => {
Ok((_, ast::Module::Platform { header }, parser_state)) => {
// make a Pkg-Config module that ultimately exposes `main` to the host
let pkg_config_module_msg = fabricate_pkg_config_module(
arena,
@ -2152,7 +2218,9 @@ fn load_pkg_config<'a>(
Ok(Msg::Many(vec![effects_module_msg, pkg_config_module_msg]))
}
Err((fail, _)) => Err(LoadingProblem::ParsingFailed { filename, fail }),
Err((_, fail, _)) => Err(LoadingProblem::ParsingFailed(
fail.into_parse_problem(filename, bytes),
)),
}
}
@ -2173,7 +2241,7 @@ fn load_module<'a>(
arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageOrPath<'a>>>>,
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
mode: Mode,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
let module_start_time = SystemTime::now();
let mut filename = PathBuf::new();
@ -2261,9 +2329,9 @@ fn parse_header<'a>(
mode: Mode,
src_bytes: &'a [u8],
start_time: SystemTime,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
let parse_start = SystemTime::now();
let parse_state = parser::State::new(src_bytes, Attempting::Module);
let parse_state = parser::State::new_in(arena, src_bytes, Attempting::Module);
let parsed = roc_parse::module::header().parse(&arena, parse_state);
let parse_header_duration = parse_start.elapsed().unwrap();
@ -2274,7 +2342,7 @@ fn parse_header<'a>(
module_timing.parse_header = parse_header_duration;
match parsed {
Ok((ast::Module::Interface { header }, parse_state)) => Ok(send_header(
Ok((_, ast::Module::Interface { header }, parse_state)) => Ok(send_header(
Located {
region: header.name.region,
value: ModuleNameEnum::Interface(header.name.value),
@ -2290,7 +2358,7 @@ fn parse_header<'a>(
ident_ids_by_module,
module_timing,
)),
Ok((ast::Module::App { header }, parse_state)) => {
Ok((_, ast::Module::App { header }, parse_state)) => {
let mut pkg_config_dir = filename.clone();
pkg_config_dir.pop();
@ -2388,7 +2456,7 @@ fn parse_header<'a>(
},
}
}
Ok((ast::Module::Platform { header }, _parse_state)) => fabricate_effects_module(
Ok((_, ast::Module::Platform { header }, _parse_state)) => fabricate_effects_module(
arena,
&"",
module_ids,
@ -2397,7 +2465,9 @@ fn parse_header<'a>(
header,
module_timing,
),
Err((fail, _)) => Err(LoadingProblem::ParsingFailed { filename, fail }),
Err((_, fail, _)) => Err(LoadingProblem::ParsingFailed(
fail.into_parse_problem(filename, src_bytes),
)),
}
}
@ -2410,7 +2480,7 @@ fn load_filename<'a>(
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
module_start_time: SystemTime,
mode: Mode,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
let file_io_start = SystemTime::now();
let file = fs::read(&filename);
let file_io_duration = file_io_start.elapsed().unwrap();
@ -2446,7 +2516,7 @@ fn load_from_str<'a>(
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
module_start_time: SystemTime,
mode: Mode,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
let file_io_start = SystemTime::now();
let file_io_duration = file_io_start.elapsed().unwrap();
@ -3014,7 +3084,7 @@ fn fabricate_pkg_config_module<'a>(
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
header: &PlatformHeader<'a>,
module_timing: ModuleTiming,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
let provides: &'a [Located<ExposesEntry<'a, &'a str>>] =
header.provides.clone().into_bump_slice();
@ -3043,7 +3113,7 @@ fn fabricate_effects_module<'a>(
mode: Mode,
header: PlatformHeader<'a>,
module_timing: ModuleTiming,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
let num_exposes = header.provides.len() + 1;
let mut exposed: Vec<Symbol> = Vec::with_capacity(num_exposes);
@ -3323,7 +3393,7 @@ fn canonicalize_and_constrain<'a, F>(
mode: Mode,
parsed: ParsedModule<'a>,
look_up_builtins: F,
) -> Result<Msg<'a>, LoadingProblem>
) -> Result<Msg<'a>, LoadingProblem<'a>>
where
F: Fn(Symbol, &mut VarStore) -> Option<Def> + 'static + Send + Copy,
{
@ -3408,13 +3478,18 @@ where
}
}
fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, LoadingProblem> {
fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, LoadingProblem<'a>> {
let mut module_timing = header.module_timing;
let parse_start = SystemTime::now();
let parse_state = parser::State::new(&header.src, Attempting::Module);
let (parsed_defs, _) = module_defs()
.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.");
let parse_state = parser::State::new_in(arena, &header.src, Attempting::Module);
let parsed_defs = match module_defs().parse(&arena, parse_state) {
Ok((_, success, _state)) => success,
Err((_, fail, _)) => {
return Err(LoadingProblem::ParsingFailed(
fail.into_parse_problem(header.module_path, header.src),
));
}
};
let parsed_defs = parsed_defs.into_bump_slice();
@ -3795,7 +3870,7 @@ fn run_task<'a, F>(
msg_tx: MsgSender<'a>,
ptr_bytes: u32,
look_up_builtins: F,
) -> Result<(), LoadingProblem>
) -> Result<(), LoadingProblem<'a>>
where
F: Fn(Symbol, &mut VarStore) -> Option<Def> + 'static + Send + Copy,
{