mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 15:03:46 +00:00
Merge branch 'main' of https://github.com/roc-lang/roc into list-splitting
This commit is contained in:
commit
35f221d9de
28 changed files with 295 additions and 370 deletions
|
@ -525,7 +525,7 @@ fn gen_from_mono_module_dev_wasm32<'a>(
|
|||
|
||||
let host_bytes = std::fs::read(built_host_path).unwrap_or_else(|_| {
|
||||
internal_error!(
|
||||
"Failed to read host object file {}! Try omitting --prebuilt-platform",
|
||||
"Failed to read host object file {}!",
|
||||
built_host_path.display()
|
||||
)
|
||||
});
|
||||
|
|
|
@ -482,7 +482,6 @@ pub fn find_type_def_symbols(
|
|||
AssignedField::LabelOnly(_) => {}
|
||||
AssignedField::SpaceBefore(inner, _)
|
||||
| AssignedField::SpaceAfter(inner, _) => inner_stack.push(inner),
|
||||
AssignedField::Malformed(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -507,7 +506,6 @@ pub fn find_type_def_symbols(
|
|||
Tag::SpaceBefore(inner, _) | Tag::SpaceAfter(inner, _) => {
|
||||
inner_stack.push(inner)
|
||||
}
|
||||
Tag::Malformed(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1355,7 +1353,7 @@ fn can_assigned_fields<'a>(
|
|||
// field names we've seen so far in this record
|
||||
let mut seen = std::collections::HashMap::with_capacity(fields.len());
|
||||
|
||||
'outer: for loc_field in fields.iter() {
|
||||
for loc_field in fields.iter() {
|
||||
let mut field = &loc_field.value;
|
||||
|
||||
// use this inner loop to unwrap the SpaceAfter/SpaceBefore
|
||||
|
@ -1430,12 +1428,6 @@ fn can_assigned_fields<'a>(
|
|||
field = nested;
|
||||
continue 'inner;
|
||||
}
|
||||
Malformed(string) => {
|
||||
malformed(env, region, string);
|
||||
|
||||
// completely skip this element, advance to the next tag
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1522,7 +1514,7 @@ fn can_tags<'a>(
|
|||
// tag names we've seen so far in this tag union
|
||||
let mut seen = std::collections::HashMap::with_capacity(tags.len());
|
||||
|
||||
'outer: for loc_tag in tags.iter() {
|
||||
for loc_tag in tags.iter() {
|
||||
let mut tag = &loc_tag.value;
|
||||
|
||||
// use this inner loop to unwrap the SpaceAfter/SpaceBefore
|
||||
|
@ -1561,12 +1553,6 @@ fn can_tags<'a>(
|
|||
tag = nested;
|
||||
continue 'inner;
|
||||
}
|
||||
Tag::Malformed(string) => {
|
||||
malformed(env, region, string);
|
||||
|
||||
// completely skip this element, advance to the next tag
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -715,10 +715,6 @@ fn canonicalize_claimed_ability_impl<'a>(
|
|||
});
|
||||
Err(())
|
||||
}
|
||||
AssignedField::Malformed(_) => {
|
||||
// An error will already have been reported
|
||||
Err(())
|
||||
}
|
||||
AssignedField::SpaceBefore(_, _)
|
||||
| AssignedField::SpaceAfter(_, _)
|
||||
| AssignedField::IgnoredValue(_, _, _) => {
|
||||
|
|
|
@ -407,7 +407,6 @@ pub fn desugar_expr<'a>(
|
|||
| AccessorFunction(_)
|
||||
| Underscore { .. }
|
||||
| MalformedIdent(_, _)
|
||||
| MalformedClosure
|
||||
| MalformedSuffixed(..)
|
||||
| PrecedenceConflict { .. }
|
||||
| EmptyRecordBuilder(_)
|
||||
|
@ -712,7 +711,6 @@ pub fn desugar_expr<'a>(
|
|||
AssignedField::SpaceBefore(_, _) | AssignedField::SpaceAfter(_, _) => {
|
||||
unreachable!("Should have been desugared in `desugar_field`")
|
||||
}
|
||||
AssignedField::Malformed(_name) => continue,
|
||||
};
|
||||
|
||||
field_data.push(FieldData {
|
||||
|
@ -1316,8 +1314,6 @@ fn desugar_field<'a>(
|
|||
}
|
||||
SpaceBefore(field, _spaces) => desugar_field(env, scope, field),
|
||||
SpaceAfter(field, _spaces) => desugar_field(env, scope, field),
|
||||
|
||||
Malformed(string) => Malformed(string),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1391,10 +1391,6 @@ pub fn canonicalize_expr<'a>(
|
|||
Output::default(),
|
||||
)
|
||||
}
|
||||
ast::Expr::MalformedClosure => {
|
||||
use roc_problem::can::RuntimeError::*;
|
||||
(RuntimeError(MalformedClosure(region)), Output::default())
|
||||
}
|
||||
ast::Expr::MalformedIdent(name, bad_ident) => {
|
||||
use roc_problem::can::RuntimeError::*;
|
||||
|
||||
|
@ -1976,10 +1972,6 @@ fn canonicalize_field<'a>(
|
|||
SpaceBefore(sub_field, _) | SpaceAfter(sub_field, _) => {
|
||||
canonicalize_field(env, var_store, scope, sub_field)
|
||||
}
|
||||
|
||||
Malformed(_string) => {
|
||||
internal_error!("TODO canonicalize malformed record field");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2568,8 +2560,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
| ast::Expr::Underscore(_)
|
||||
| ast::Expr::MalformedIdent(_, _)
|
||||
| ast::Expr::Tag(_)
|
||||
| ast::Expr::OpaqueRef(_)
|
||||
| ast::Expr::MalformedClosure => true,
|
||||
| ast::Expr::OpaqueRef(_) => true,
|
||||
// Newlines are disallowed inside interpolation, and these all require newlines
|
||||
ast::Expr::DbgStmt(_, _)
|
||||
| ast::Expr::LowLevelDbg(_, _, _)
|
||||
|
@ -2604,7 +2595,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
| ast::AssignedField::IgnoredValue(_label, loc_comments, loc_val) => {
|
||||
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
|
||||
}
|
||||
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
|
||||
ast::AssignedField::LabelOnly(_) => true,
|
||||
ast::AssignedField::SpaceBefore(_, _) | ast::AssignedField::SpaceAfter(_, _) => false,
|
||||
}),
|
||||
ast::Expr::Tuple(fields) => fields
|
||||
|
@ -2655,7 +2646,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
| ast::AssignedField::IgnoredValue(_label, loc_comments, loc_val) => {
|
||||
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
|
||||
}
|
||||
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
|
||||
ast::AssignedField::LabelOnly(_) => true,
|
||||
ast::AssignedField::SpaceBefore(_, _)
|
||||
| ast::AssignedField::SpaceAfter(_, _) => false,
|
||||
})
|
||||
|
@ -2668,7 +2659,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
| ast::AssignedField::IgnoredValue(_label, loc_comments, loc_val) => {
|
||||
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
|
||||
}
|
||||
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
|
||||
ast::AssignedField::LabelOnly(_) => true,
|
||||
ast::AssignedField::SpaceBefore(_, _)
|
||||
| ast::AssignedField::SpaceAfter(_, _) => false,
|
||||
})
|
||||
|
|
|
@ -438,7 +438,6 @@ fn is_multiline_assigned_field_help<T: Formattable>(afield: &AssignedField<'_, T
|
|||
| IgnoredValue(_, spaces, ann) => !spaces.is_empty() || ann.value.is_multiline(),
|
||||
LabelOnly(_) => false,
|
||||
AssignedField::SpaceBefore(_, _) | AssignedField::SpaceAfter(_, _) => true,
|
||||
Malformed(text) => text.chars().any(|c| c == '\n'),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,9 +521,6 @@ fn format_assigned_field_help<T>(
|
|||
format_assigned_field_help(sub_field, buf, indent, separator_spaces, is_multiline);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
Malformed(raw) => {
|
||||
buf.push_str(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,7 +531,6 @@ impl<'a> Formattable for Tag<'a> {
|
|||
match self {
|
||||
Apply { args, .. } => args.iter().any(|arg| arg.value.is_multiline()),
|
||||
Tag::SpaceBefore(_, _) | Tag::SpaceAfter(_, _) => true,
|
||||
Malformed(text) => text.chars().any(|c| c == '\n'),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -572,10 +567,6 @@ impl<'a> Formattable for Tag<'a> {
|
|||
}
|
||||
}
|
||||
Tag::SpaceBefore(_, _) | Tag::SpaceAfter(_, _) => unreachable!(),
|
||||
Tag::Malformed(raw) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ impl<'a> Formattable for Expr<'a> {
|
|||
| Var { .. }
|
||||
| Underscore { .. }
|
||||
| MalformedIdent(_, _)
|
||||
| MalformedClosure
|
||||
| Tag(_)
|
||||
| OpaqueRef(_)
|
||||
| Crash
|
||||
|
@ -557,7 +556,6 @@ impl<'a> Formattable for Expr<'a> {
|
|||
buf.indent(indent);
|
||||
loc_expr.format_with_options(buf, parens, newlines, indent);
|
||||
}
|
||||
MalformedClosure => {}
|
||||
PrecedenceConflict { .. } => {}
|
||||
EmptyRecordBuilder { .. } => {}
|
||||
SingleFieldRecordBuilder { .. } => {}
|
||||
|
@ -1646,9 +1644,6 @@ fn format_assigned_field_multiline<T>(
|
|||
format_assigned_field_multiline(buf, sub_field, indent, separator_prefix);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Top, indent);
|
||||
}
|
||||
Malformed(raw) => {
|
||||
buf.push_str(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -476,7 +476,7 @@ fn contains_unexposed_type(
|
|||
return true;
|
||||
}
|
||||
}
|
||||
AssignedField::Malformed(_) | AssignedField::LabelOnly(_) => {
|
||||
AssignedField::LabelOnly(_) => {
|
||||
// contains no unexposed types, so continue
|
||||
}
|
||||
AssignedField::SpaceBefore(field, _) | AssignedField::SpaceAfter(field, _) => {
|
||||
|
@ -524,9 +524,6 @@ fn contains_unexposed_type(
|
|||
}
|
||||
}
|
||||
}
|
||||
Tag::Malformed(_) => {
|
||||
// contains no unexposed types, so continue
|
||||
}
|
||||
Tag::SpaceBefore(tag, _) | Tag::SpaceAfter(tag, _) => {
|
||||
tags_to_process.push(*tag);
|
||||
}
|
||||
|
@ -728,7 +725,7 @@ fn record_field_to_doc(
|
|||
AssignedField::LabelOnly(label) => Some(RecordField::LabelOnly {
|
||||
name: label.value.to_string(),
|
||||
}),
|
||||
AssignedField::Malformed(_) | AssignedField::IgnoredValue(_, _, _) => None,
|
||||
AssignedField::IgnoredValue(_, _, _) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -749,7 +746,6 @@ fn tag_to_doc(in_func_ann: bool, tag: ast::Tag) -> Option<Tag> {
|
|||
}),
|
||||
ast::Tag::SpaceBefore(&sub_tag, _) => tag_to_doc(in_func_ann, sub_tag),
|
||||
ast::Tag::SpaceAfter(&sub_tag, _) => tag_to_doc(in_func_ann, sub_tag),
|
||||
ast::Tag::Malformed(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ use roc_solve_problem::TypeError;
|
|||
use roc_target::Target;
|
||||
use roc_types::subs::{CopiedImport, ExposedTypesStorageSubs, Subs, VarStore, Variable};
|
||||
use roc_types::types::{Alias, Types};
|
||||
use roc_worker::{ChannelProblem, WorkerMsg};
|
||||
use roc_worker::ChannelProblem;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
|
@ -1035,14 +1035,14 @@ type MsgSender<'a> = Sender<Msg<'a>>;
|
|||
/// Add a task to the queue, and notify all the listeners.
|
||||
fn enqueue_task<'a>(
|
||||
injector: &Injector<BuildTask<'a>>,
|
||||
listeners: &[Sender<WorkerMsg>],
|
||||
listeners: &[Sender<()>],
|
||||
task: BuildTask<'a>,
|
||||
) -> Result<(), LoadingProblem<'a>> {
|
||||
injector.push(task);
|
||||
|
||||
for listener in listeners {
|
||||
listener
|
||||
.send(WorkerMsg::TaskAdded)
|
||||
.send(())
|
||||
.map_err(|_| LoadingProblem::ChannelProblem(ChannelProblem::FailedToEnqueueTask))?;
|
||||
}
|
||||
|
||||
|
@ -1569,9 +1569,9 @@ pub fn load_single_threaded<'a>(
|
|||
// We'll add tasks to this, and then worker threads will take tasks from it.
|
||||
let injector = Injector::new();
|
||||
|
||||
let (worker_msg_tx, worker_msg_rx) = bounded(1024);
|
||||
let worker_listener = worker_msg_tx;
|
||||
let worker_listeners = arena.alloc([worker_listener]);
|
||||
let (worker_wakup_tx, worker_wakup_rx) = bounded(1024);
|
||||
let worker_waker = worker_wakup_tx;
|
||||
let worker_wakers = [worker_waker];
|
||||
|
||||
let worker = Worker::new_fifo();
|
||||
let stealer = worker.stealer();
|
||||
|
@ -1579,7 +1579,7 @@ pub fn load_single_threaded<'a>(
|
|||
|
||||
// now we just manually interleave stepping the state "thread" and the worker "thread"
|
||||
loop {
|
||||
match state_thread_step(arena, state, worker_listeners, &injector, &msg_tx, &msg_rx) {
|
||||
match state_thread_step(arena, state, &worker_wakers, &injector, &msg_tx, &msg_rx) {
|
||||
Ok(ControlFlow::Break(done)) => return Ok(done),
|
||||
Ok(ControlFlow::Continue(new_state)) => {
|
||||
state = new_state;
|
||||
|
@ -1589,7 +1589,7 @@ pub fn load_single_threaded<'a>(
|
|||
|
||||
// then check if the worker can step
|
||||
let control_flow =
|
||||
roc_worker::worker_task_step(&worker, &injector, stealers, &worker_msg_rx, |task| {
|
||||
roc_worker::worker_task_step(&worker, &injector, stealers, &worker_wakup_rx, |task| {
|
||||
run_task(task, arena, &src_dir, msg_tx.clone(), roc_cache_dir, target)
|
||||
});
|
||||
|
||||
|
@ -1606,7 +1606,7 @@ pub fn load_single_threaded<'a>(
|
|||
fn state_thread_step<'a>(
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
worker_listeners: &'a [Sender<WorkerMsg>],
|
||||
worker_wakers: &[Sender<()>],
|
||||
injector: &Injector<BuildTask<'a>>,
|
||||
msg_tx: &crossbeam::channel::Sender<Msg<'a>>,
|
||||
msg_rx: &crossbeam::channel::Receiver<Msg<'a>>,
|
||||
|
@ -1712,14 +1712,8 @@ fn state_thread_step<'a>(
|
|||
let render = state.render;
|
||||
let palette = state.palette;
|
||||
|
||||
let res_state = update(
|
||||
state,
|
||||
msg,
|
||||
msg_tx.clone(),
|
||||
injector,
|
||||
worker_listeners,
|
||||
arena,
|
||||
);
|
||||
let res_state =
|
||||
update(state, msg, msg_tx.clone(), injector, worker_wakers, arena);
|
||||
|
||||
match res_state {
|
||||
Ok(new_state) => Ok(ControlFlow::Continue(new_state)),
|
||||
|
@ -1993,15 +1987,21 @@ fn load_multi_threaded<'a>(
|
|||
|
||||
{
|
||||
let thread_result = thread::scope(|thread_scope| {
|
||||
let mut worker_listeners =
|
||||
bumpalo::collections::Vec::with_capacity_in(num_workers, arena);
|
||||
// Careful! It's important that worker listeners aren't allocated in the arena,
|
||||
// since they need to be correctly dropped if we have a panic in this thread::scope code.
|
||||
// Making sure they're owned means they'll be dropped correctly on either normal exit
|
||||
// of this thread::scope block or on panicking. When they're dropped, the worker threads
|
||||
// will correctly exit their message processing loops.
|
||||
// If these were allocated in the arena, we might panic without shutting down the worker threads,
|
||||
// causing the thread::scope block to hang while it waits for the worker threads to exit.
|
||||
let mut worker_wakers = Vec::with_capacity(num_workers);
|
||||
|
||||
for worker_arena in it {
|
||||
let msg_tx = msg_tx.clone();
|
||||
let worker = worker_queues.pop().unwrap();
|
||||
|
||||
let (worker_msg_tx, worker_msg_rx) = bounded(1024);
|
||||
worker_listeners.push(worker_msg_tx);
|
||||
let (worker_wakup_tx, worker_wakup_rx) = bounded(1024);
|
||||
worker_wakers.push(worker_wakup_tx);
|
||||
|
||||
// We only want to move a *reference* to the main task queue's
|
||||
// injector in the thread, not the injector itself
|
||||
|
@ -2015,16 +2015,22 @@ fn load_multi_threaded<'a>(
|
|||
.stack_size(EXPANDED_STACK_SIZE)
|
||||
.spawn(move |_| {
|
||||
// will process messages until we run out
|
||||
roc_worker::worker_task(worker, injector, stealers, worker_msg_rx, |task| {
|
||||
run_task(
|
||||
task,
|
||||
worker_arena,
|
||||
src_dir,
|
||||
msg_tx.clone(),
|
||||
roc_cache_dir,
|
||||
target,
|
||||
)
|
||||
})
|
||||
roc_worker::worker_task(
|
||||
worker,
|
||||
injector,
|
||||
stealers,
|
||||
worker_wakup_rx,
|
||||
|task| {
|
||||
run_task(
|
||||
task,
|
||||
worker_arena,
|
||||
src_dir,
|
||||
msg_tx.clone(),
|
||||
roc_cache_dir,
|
||||
target,
|
||||
)
|
||||
},
|
||||
)
|
||||
});
|
||||
|
||||
res_join_handle.unwrap_or_else(|_| {
|
||||
|
@ -2039,31 +2045,13 @@ fn load_multi_threaded<'a>(
|
|||
|
||||
// Grab a reference to these Senders outside the loop, so we can share
|
||||
// it across each iteration of the loop.
|
||||
let worker_listeners = worker_listeners.into_bump_slice();
|
||||
let msg_tx = msg_tx.clone();
|
||||
|
||||
macro_rules! shut_down_worker_threads {
|
||||
() => {
|
||||
for listener in worker_listeners {
|
||||
// We intentionally don't propagate this Result, because even if
|
||||
// shutting down a worker failed (which can happen if a a panic
|
||||
// occurred on that thread), we want to continue shutting down
|
||||
// the others regardless.
|
||||
if listener.send(WorkerMsg::Shutdown).is_err() {
|
||||
log!("There was an error trying to shutdown a worker thread. One reason this can happen is if the thread panicked.");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// The root module will have already queued up messages to process,
|
||||
// and processing those messages will in turn queue up more messages.
|
||||
loop {
|
||||
match state_thread_step(arena, state, worker_listeners, &injector, &msg_tx, &msg_rx)
|
||||
{
|
||||
match state_thread_step(arena, state, &worker_wakers, &injector, &msg_tx, &msg_rx) {
|
||||
Ok(ControlFlow::Break(load_result)) => {
|
||||
shut_down_worker_threads!();
|
||||
|
||||
return Ok(load_result);
|
||||
}
|
||||
Ok(ControlFlow::Continue(new_state)) => {
|
||||
|
@ -2071,8 +2059,6 @@ fn load_multi_threaded<'a>(
|
|||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
shut_down_worker_threads!();
|
||||
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
@ -2111,13 +2097,13 @@ fn start_tasks<'a>(
|
|||
state: &mut State<'a>,
|
||||
work: MutSet<(ModuleId, Phase)>,
|
||||
injector: &Injector<BuildTask<'a>>,
|
||||
worker_listeners: &'a [Sender<WorkerMsg>],
|
||||
worker_wakers: &[Sender<()>],
|
||||
) -> Result<(), LoadingProblem<'a>> {
|
||||
for (module_id, phase) in work {
|
||||
let tasks = start_phase(module_id, phase, arena, state);
|
||||
|
||||
for task in tasks {
|
||||
enqueue_task(injector, worker_listeners, task)?
|
||||
enqueue_task(injector, worker_wakers, task)?
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2179,7 +2165,7 @@ fn update<'a>(
|
|||
msg: Msg<'a>,
|
||||
msg_tx: MsgSender<'a>,
|
||||
injector: &Injector<BuildTask<'a>>,
|
||||
worker_listeners: &'a [Sender<WorkerMsg>],
|
||||
worker_wakers: &[Sender<()>],
|
||||
arena: &'a Bump,
|
||||
) -> Result<State<'a>, LoadingProblem<'a>> {
|
||||
use self::Msg::*;
|
||||
|
@ -2305,7 +2291,7 @@ fn update<'a>(
|
|||
work.extend(state.dependencies.notify(home, Phase::LoadHeader));
|
||||
work.insert((home, Phase::Parse));
|
||||
|
||||
start_tasks(arena, &mut state, work, injector, worker_listeners)?;
|
||||
start_tasks(arena, &mut state, work, injector, worker_wakers)?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
@ -2382,7 +2368,7 @@ fn update<'a>(
|
|||
}
|
||||
};
|
||||
|
||||
start_tasks(arena, &mut state, work, injector, worker_listeners)?;
|
||||
start_tasks(arena, &mut state, work, injector, worker_wakers)?;
|
||||
|
||||
state
|
||||
.module_cache
|
||||
|
@ -2393,7 +2379,7 @@ fn update<'a>(
|
|||
|
||||
let work = state.dependencies.notify(module_id, Phase::Parse);
|
||||
|
||||
start_tasks(arena, &mut state, work, injector, worker_listeners)?;
|
||||
start_tasks(arena, &mut state, work, injector, worker_wakers)?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
@ -2445,7 +2431,7 @@ fn update<'a>(
|
|||
.dependencies
|
||||
.notify(module_id, Phase::CanonicalizeAndConstrain);
|
||||
|
||||
start_tasks(arena, &mut state, work, injector, worker_listeners)?;
|
||||
start_tasks(arena, &mut state, work, injector, worker_wakers)?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
@ -2652,7 +2638,7 @@ fn update<'a>(
|
|||
work
|
||||
};
|
||||
|
||||
start_tasks(arena, &mut state, work, injector, worker_listeners)?;
|
||||
start_tasks(arena, &mut state, work, injector, worker_wakers)?;
|
||||
}
|
||||
|
||||
Ok(state)
|
||||
|
@ -2700,7 +2686,7 @@ fn update<'a>(
|
|||
.dependencies
|
||||
.notify(module_id, Phase::FindSpecializations);
|
||||
|
||||
start_tasks(arena, &mut state, work, injector, worker_listeners)?;
|
||||
start_tasks(arena, &mut state, work, injector, worker_wakers)?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
@ -2990,13 +2976,13 @@ fn update<'a>(
|
|||
|
||||
let work = state.dependencies.reload_make_specialization_pass();
|
||||
|
||||
start_tasks(arena, &mut state, work, injector, worker_listeners)?;
|
||||
start_tasks(arena, &mut state, work, injector, worker_wakers)?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
NextStep::MakingInPhase => {
|
||||
start_tasks(arena, &mut state, work, injector, worker_listeners)?;
|
||||
start_tasks(arena, &mut state, work, injector, worker_wakers)?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
|
|
@ -539,7 +539,6 @@ pub enum Expr<'a> {
|
|||
|
||||
// Problems
|
||||
MalformedIdent(&'a str, crate::ident::BadIdent),
|
||||
MalformedClosure,
|
||||
MalformedSuffixed(&'a Loc<Expr<'a>>),
|
||||
// Both operators were non-associative, e.g. (True == False == False).
|
||||
// We should tell the author to disambiguate by grouping them with parens.
|
||||
|
@ -687,7 +686,6 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
|||
Expr::SpaceBefore(a, _) => is_expr_suffixed(a),
|
||||
Expr::SpaceAfter(a, _) => is_expr_suffixed(a),
|
||||
Expr::MalformedIdent(_, _) => false,
|
||||
Expr::MalformedClosure => false,
|
||||
Expr::MalformedSuffixed(_) => false,
|
||||
Expr::PrecedenceConflict(_) => false,
|
||||
Expr::EmptyRecordBuilder(_) => false,
|
||||
|
@ -713,7 +711,6 @@ fn is_assigned_value_suffixed<'a>(value: &AssignedField<'a, Expr<'a>>) -> bool {
|
|||
AssignedField::SpaceBefore(a, _) | AssignedField::SpaceAfter(a, _) => {
|
||||
is_assigned_value_suffixed(a)
|
||||
}
|
||||
AssignedField::Malformed(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -889,7 +886,7 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
| OptionalValue(_, _, loc_val)
|
||||
| IgnoredValue(_, _, loc_val) => break expr_stack.push(&loc_val.value),
|
||||
SpaceBefore(next, _) | SpaceAfter(next, _) => current = *next,
|
||||
LabelOnly(_) | Malformed(_) => break,
|
||||
LabelOnly(_) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1038,7 +1035,6 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
| Tag(_)
|
||||
| OpaqueRef(_)
|
||||
| MalformedIdent(_, _)
|
||||
| MalformedClosure
|
||||
| PrecedenceConflict(_)
|
||||
| MalformedSuffixed(_) => { /* terminal */ }
|
||||
}
|
||||
|
@ -1614,9 +1610,6 @@ pub enum Tag<'a> {
|
|||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
SpaceBefore(&'a Tag<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a Tag<'a>, &'a [CommentOrNewline<'a>]),
|
||||
|
||||
/// A malformed tag, which will code gen to a runtime error
|
||||
Malformed(&'a str),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
|
@ -1639,9 +1632,6 @@ pub enum AssignedField<'a, Val> {
|
|||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
SpaceBefore(&'a AssignedField<'a, Val>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a AssignedField<'a, Val>, &'a [CommentOrNewline<'a>]),
|
||||
|
||||
/// A malformed assigned field, which will code gen to a runtime error
|
||||
Malformed(&'a str),
|
||||
}
|
||||
|
||||
impl<'a, Val> AssignedField<'a, Val> {
|
||||
|
@ -1653,7 +1643,7 @@ impl<'a, Val> AssignedField<'a, Val> {
|
|||
Self::RequiredValue(_, _, val)
|
||||
| Self::OptionalValue(_, _, val)
|
||||
| Self::IgnoredValue(_, _, val) => break Some(val),
|
||||
Self::LabelOnly(_) | Self::Malformed(_) => break None,
|
||||
Self::LabelOnly(_) => break None,
|
||||
Self::SpaceBefore(next, _) | Self::SpaceAfter(next, _) => current = *next,
|
||||
}
|
||||
}
|
||||
|
@ -2518,7 +2508,6 @@ impl<'a> Malformed for Expr<'a> {
|
|||
ParensAround(expr) => expr.is_malformed(),
|
||||
|
||||
MalformedIdent(_, _) |
|
||||
MalformedClosure |
|
||||
MalformedSuffixed(..) |
|
||||
PrecedenceConflict(_) |
|
||||
EmptyRecordBuilder(_) |
|
||||
|
@ -2593,7 +2582,6 @@ impl<'a, T: Malformed> Malformed for AssignedField<'a, T> {
|
|||
AssignedField::SpaceBefore(field, _) | AssignedField::SpaceAfter(field, _) => {
|
||||
field.is_malformed()
|
||||
}
|
||||
AssignedField::Malformed(_) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2815,7 +2803,6 @@ impl<'a> Malformed for Tag<'a> {
|
|||
match self {
|
||||
Tag::Apply { name: _, args } => args.iter().any(|arg| arg.is_malformed()),
|
||||
Tag::SpaceBefore(tag, _) | Tag::SpaceAfter(tag, _) => tag.is_malformed(),
|
||||
Tag::Malformed(_) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2180,7 +2180,6 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
| Expr::DbgStmt(_, _)
|
||||
| Expr::LowLevelDbg(_, _, _)
|
||||
| Expr::Return(_, _)
|
||||
| Expr::MalformedClosure
|
||||
| Expr::MalformedSuffixed(..)
|
||||
| Expr::PrecedenceConflict { .. }
|
||||
| Expr::EmptyRecordBuilder(_)
|
||||
|
@ -2254,7 +2253,6 @@ fn assigned_expr_field_to_pattern_help<'a>(
|
|||
arena.alloc(assigned_expr_field_to_pattern_help(arena, nested)?),
|
||||
spaces,
|
||||
),
|
||||
AssignedField::Malformed(string) => Pattern::Malformed(string),
|
||||
AssignedField::IgnoredValue(_, _, _) => return Err(()),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -556,7 +556,6 @@ impl<'a, T: Normalize<'a> + Copy + std::fmt::Debug> Normalize<'a> for AssignedFi
|
|||
arena.alloc(c.normalize(arena)),
|
||||
),
|
||||
AssignedField::LabelOnly(a) => AssignedField::LabelOnly(a.normalize(arena)),
|
||||
AssignedField::Malformed(a) => AssignedField::Malformed(a),
|
||||
AssignedField::SpaceBefore(a, _) => a.normalize(arena),
|
||||
AssignedField::SpaceAfter(a, _) => a.normalize(arena),
|
||||
}
|
||||
|
@ -784,7 +783,6 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
a.normalize(arena)
|
||||
}
|
||||
Expr::MalformedIdent(a, b) => Expr::MalformedIdent(a, remove_spaces_bad_ident(b)),
|
||||
Expr::MalformedClosure => Expr::MalformedClosure,
|
||||
Expr::MalformedSuffixed(a) => Expr::MalformedSuffixed(a),
|
||||
Expr::PrecedenceConflict(a) => Expr::PrecedenceConflict(a),
|
||||
Expr::SpaceBefore(a, _) => a.normalize(arena),
|
||||
|
@ -938,7 +936,6 @@ impl<'a> Normalize<'a> for Tag<'a> {
|
|||
name: name.normalize(arena),
|
||||
args: args.normalize(arena),
|
||||
},
|
||||
Tag::Malformed(a) => Tag::Malformed(a),
|
||||
Tag::SpaceBefore(a, _) => a.normalize(arena),
|
||||
Tag::SpaceAfter(a, _) => a.normalize(arena),
|
||||
}
|
||||
|
|
|
@ -435,7 +435,6 @@ impl Problem {
|
|||
| Problem::RuntimeError(RuntimeError::InvalidPrecedence(_, region))
|
||||
| Problem::RuntimeError(RuntimeError::MalformedIdentifier(_, _, region))
|
||||
| Problem::RuntimeError(RuntimeError::MalformedTypeName(_, region))
|
||||
| Problem::RuntimeError(RuntimeError::MalformedClosure(region))
|
||||
| Problem::RuntimeError(RuntimeError::MalformedSuffixed(region))
|
||||
| Problem::RuntimeError(RuntimeError::InvalidRecordUpdate { region })
|
||||
| Problem::RuntimeError(RuntimeError::InvalidFloat(_, region, _))
|
||||
|
@ -678,7 +677,6 @@ pub enum RuntimeError {
|
|||
InvalidPrecedence(PrecedenceProblem, Region),
|
||||
MalformedIdentifier(Box<str>, roc_parse::ident::BadIdent, Region),
|
||||
MalformedTypeName(Box<str>, Region),
|
||||
MalformedClosure(Region),
|
||||
InvalidRecordUpdate {
|
||||
region: Region,
|
||||
},
|
||||
|
@ -750,7 +748,6 @@ impl RuntimeError {
|
|||
| RuntimeError::InvalidPrecedence(_, region)
|
||||
| RuntimeError::MalformedIdentifier(_, _, region)
|
||||
| RuntimeError::MalformedTypeName(_, region)
|
||||
| RuntimeError::MalformedClosure(region)
|
||||
| RuntimeError::MalformedSuffixed(region)
|
||||
| RuntimeError::InvalidRecordUpdate { region }
|
||||
| RuntimeError::InvalidFloat(_, region, _)
|
||||
|
|
|
@ -7,12 +7,6 @@ use roc_module::symbol::ModuleId;
|
|||
use roc_work::Phase;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum WorkerMsg {
|
||||
Shutdown,
|
||||
TaskAdded,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ChannelProblem {
|
||||
FailedToSendRootMsg,
|
||||
|
@ -29,41 +23,31 @@ pub fn worker_task_step<Task>(
|
|||
worker: &Worker<Task>,
|
||||
injector: &Injector<Task>,
|
||||
stealers: &[Stealer<Task>],
|
||||
worker_msg_rx: &Receiver<WorkerMsg>,
|
||||
worker_wakeup_rx: &Receiver<()>,
|
||||
run_task: impl Fn(Task) -> Result<(), ChannelProblem>,
|
||||
) -> Result<ControlFlow<(), ()>, ChannelProblem> {
|
||||
match worker_msg_rx.try_recv() {
|
||||
Ok(msg) => {
|
||||
match msg {
|
||||
WorkerMsg::Shutdown => {
|
||||
// We've finished all our work. It's time to
|
||||
// shut down the thread, so when the main thread
|
||||
// blocks on joining with all the worker threads,
|
||||
// it can finally exit too!
|
||||
Ok(ControlFlow::Break(()))
|
||||
}
|
||||
WorkerMsg::TaskAdded => {
|
||||
// Find a task - either from this thread's queue,
|
||||
// or from the main queue, or from another worker's
|
||||
// queue - and run it.
|
||||
//
|
||||
// There might be no tasks to work on! That could
|
||||
// happen if another thread is working on a task
|
||||
// which will later result in more tasks being
|
||||
// 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(task)?;
|
||||
}
|
||||
|
||||
Ok(ControlFlow::Continue(()))
|
||||
}
|
||||
match worker_wakeup_rx.try_recv() {
|
||||
Ok(()) => {
|
||||
// Find a task - either from this thread's queue,
|
||||
// or from the main queue, or from another worker's
|
||||
// queue - and run it.
|
||||
//
|
||||
// There might be no tasks to work on! That could
|
||||
// happen if another thread is working on a task
|
||||
// which will later result in more tasks being
|
||||
// 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(task)?;
|
||||
}
|
||||
|
||||
Ok(ControlFlow::Continue(()))
|
||||
}
|
||||
Err(err) => match err {
|
||||
crossbeam::channel::TryRecvError::Empty => Ok(ControlFlow::Continue(())),
|
||||
crossbeam::channel::TryRecvError::Disconnected => {
|
||||
Err(ChannelProblem::ChannelDisconnected)
|
||||
// The channel sender has been dropped, which means we want to shut down
|
||||
Ok(ControlFlow::Break(()))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -73,33 +57,22 @@ pub fn worker_task<Task>(
|
|||
worker: Worker<Task>,
|
||||
injector: &Injector<Task>,
|
||||
stealers: &[Stealer<Task>],
|
||||
worker_msg_rx: crossbeam::channel::Receiver<WorkerMsg>,
|
||||
worker_wakeup_rx: crossbeam::channel::Receiver<()>,
|
||||
run_task: impl Fn(Task) -> Result<(), ChannelProblem>,
|
||||
) -> Result<(), ChannelProblem> {
|
||||
// Keep listening until we receive a Shutdown msg
|
||||
for msg in worker_msg_rx.iter() {
|
||||
match msg {
|
||||
WorkerMsg::Shutdown => {
|
||||
// We've finished all our work. It's time to
|
||||
// shut down the thread, so when the main thread
|
||||
// blocks on joining with all the worker threads,
|
||||
// it can finally exit too!
|
||||
return Ok(());
|
||||
}
|
||||
WorkerMsg::TaskAdded => {
|
||||
// Find a task - either from this thread's queue,
|
||||
// or from the main queue, or from another worker's
|
||||
// queue - and run it.
|
||||
//
|
||||
// There might be no tasks to work on! That could
|
||||
// happen if another thread is working on a task
|
||||
// which will later result in more tasks being
|
||||
// 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(task)?;
|
||||
}
|
||||
}
|
||||
for () in worker_wakeup_rx.iter() {
|
||||
// Find a task - either from this thread's queue,
|
||||
// or from the main queue, or from another worker's
|
||||
// queue - and run it.
|
||||
//
|
||||
// There might be no tasks to work on! That could
|
||||
// happen if another thread is working on a task
|
||||
// which will later result in more tasks being
|
||||
// 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(task)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,17 +83,17 @@ pub fn start_tasks<State, Task, Tasks: IntoIterator<Item = Task>>(
|
|||
state: &mut State,
|
||||
work: MutSet<(ModuleId, Phase)>,
|
||||
injector: &Injector<Task>,
|
||||
worker_listeners: &[Sender<WorkerMsg>],
|
||||
worker_wakers: &[Sender<()>],
|
||||
mut start_phase: impl FnMut(ModuleId, Phase, &mut State) -> Tasks,
|
||||
) -> Result<(), SendError<WorkerMsg>> {
|
||||
) -> Result<(), SendError<()>> {
|
||||
for (module_id, phase) in work {
|
||||
let tasks = start_phase(module_id, phase, state);
|
||||
|
||||
for task in tasks {
|
||||
injector.push(task);
|
||||
|
||||
for listener in worker_listeners {
|
||||
listener.send(WorkerMsg::TaskAdded)?;
|
||||
for listener in worker_wakers {
|
||||
listener.send(())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue