From 3208d870ae28f9ea15ac5d4c9a79618942af8833 Mon Sep 17 00:00:00 2001 From: hyperpolymath Date: Sat, 16 May 2026 15:17:53 +0100 Subject: [PATCH] fix: exhaustive Statement match for concurrency variants (restores build) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `Statement` enum in `src/ast/mod.rs` gained worker/concurrency variants (`WorkerSpawn`, `SendMessage`, `ReceiveMessage`, `AwaitWorker`, `CancelWorker`) but several `match stmt` sites were never updated, producing `error[E0004]` non-exhaustive match and breaking the build. Sites fixed: - src/ast/visitor.rs (walk_statement): `SendMessage` now recurses into its message expression like sibling expr-bearing arms; the name-only variants join the leaf arm with `WorkerSpawn`. - src/interpreter/mod.rs (execute_statement): the four worker-addressed variants return a clear `RuntimeError` (consistent with `Complain` and the loop-context guards) since there is no worker-name-addressed messaging runtime — `WorkerSpawn`'s own comment states workers communicate via channels created in the main scope. - src/sexpr.rs (stmt_to_sexpr, stmt_to_json): real serialization for all four variants, matching the style of neighbouring arms. No silent `_ => {}` catch-all was added, so future Statement variants will still surface as compile errors. Build verification: `cargo build --lib`, `cargo build`, and `cargo test --no-run` all complete with no errors (pre-existing warnings only). Co-Authored-By: Claude Opus 4.7 --- src/ast/visitor.rs | 5 ++++- src/interpreter/mod.rs | 24 ++++++++++++++++++++++++ src/sexpr.rs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/ast/visitor.rs b/src/ast/visitor.rs index 5d902c8..88f5d2a 100644 --- a/src/ast/visitor.rs +++ b/src/ast/visitor.rs @@ -74,7 +74,10 @@ pub fn walk_statement(v: &mut V, stmt: &Statement) { for s in &c.body { v.visit_statement(s); } } Statement::Expression(e) => v.visit_expr(&e.node), - Statement::WorkerSpawn(_) | Statement::Complain(_) + Statement::SendMessage(s) => v.visit_expr(&s.message.node), + Statement::WorkerSpawn(_) | Statement::ReceiveMessage(_) + | Statement::AwaitWorker(_) | Statement::CancelWorker(_) + | Statement::Complain(_) | Statement::Break(_) | Statement::Continue(_) => {} Statement::EmoteAnnotated(e) => v.visit_statement(&e.statement), Statement::Decide(d) => { diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index ca6757c..af16915 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -515,6 +515,30 @@ impl Interpreter { Ok(Value::Unit) } + Statement::SendMessage(send) => Err(RuntimeError::new(format!( + "Worker-addressed message passing is not implemented: cannot `send` to worker '{}'. \ + Use a channel created in the main scope and pass it to the worker instead.", + send.target + ))), + + Statement::ReceiveMessage(recv) => Err(RuntimeError::new(format!( + "Worker-addressed message passing is not implemented: cannot `receive` from worker '{}'. \ + Use a channel created in the main scope and pass it to the worker instead.", + recv.source + ))), + + Statement::AwaitWorker(await_worker) => Err(RuntimeError::new(format!( + "Awaiting a worker by name is not implemented: cannot `await` worker '{}'. \ + Workers run detached; synchronise via a channel created in the main scope.", + await_worker.worker_name + ))), + + Statement::CancelWorker(cancel) => Err(RuntimeError::new(format!( + "Cancelling a worker by name is not implemented: cannot `cancel` worker '{}'. \ + Workers run detached and cannot currently be cancelled.", + cancel.worker_name + ))), + Statement::Complain(complain) => Err(RuntimeError { message: complain.message.clone(), }), diff --git a/src/sexpr.rs b/src/sexpr.rs index d47efb8..0d7cb75 100644 --- a/src/sexpr.rs +++ b/src/sexpr.rs @@ -331,6 +331,20 @@ fn stmt_to_sexpr(stmt: &Statement, out: &mut String, indent: usize) { Statement::WorkerSpawn(w) => { out.push_str(&format!("(spawn-worker \"{}\")", w.worker_name)); } + Statement::SendMessage(s) => { + out.push_str(&format!("(send :to \"{}\" ", s.target)); + expr_to_sexpr(&s.message.node, out, indent + 2); + out.push(')'); + } + Statement::ReceiveMessage(r) => { + out.push_str(&format!("(receive :from \"{}\")", r.source)); + } + Statement::AwaitWorker(a) => { + out.push_str(&format!("(await-worker \"{}\")", a.worker_name)); + } + Statement::CancelWorker(c) => { + out.push_str(&format!("(cancel-worker \"{}\")", c.worker_name)); + } Statement::Complain(c) => { out.push_str(&format!("(complain \"{}\")", c.message)); } @@ -710,6 +724,23 @@ fn stmt_to_json(stmt: &Statement) -> serde_json::Value { "type": "spawn_worker", "name": w.worker_name }), + Statement::SendMessage(s) => serde_json::json!({ + "type": "send_message", + "target": s.target, + "message": expr_to_json(&s.message.node) + }), + Statement::ReceiveMessage(r) => serde_json::json!({ + "type": "receive_message", + "source": r.source + }), + Statement::AwaitWorker(a) => serde_json::json!({ + "type": "await_worker", + "name": a.worker_name + }), + Statement::CancelWorker(c) => serde_json::json!({ + "type": "cancel_worker", + "name": c.worker_name + }), Statement::Complain(c) => serde_json::json!({ "type": "complain", "message": c.message