Open and answer this issue on GitHub.
ready · opened 2026-10-14 · updated 2026-10-14 · 0 comments
Nikaia accepts this program, and the Rust it lowers to is refused by rustc (Part III C.1). Checked on develop 0.0.964.
enum Bad { Oops }
enum Worse { Boom }
impl Error for Bad { fn message(ref self) -> String { return "oops".clone() } }
impl Error for Worse { fn message(ref self) -> String { return "boom".clone() } }
struct Task { run: fn() throws }
struct Registry { tasks: Vec[Task] }
impl Registry {
fn register(ref mut self, t: Task) { self.tasks.push(t) }
fn fire(ref self) throws { for t in self.tasks { t.run() } }
}
fn fail() throws { throw Bad::Oops }
fn worse() throws { throw Worse::Boom }
fn main() {
let mut r = Registry { tasks: [] }
r.register(Task { run: fail })
r.register(Task { run: worse })
r.fire() catch {
match error {
Bad::Oops => println("oops"),
Worse::Boom => println("boom"),
else => println("other"),
}
}
}
rustc reports Mismatched types at match error twice: expected Box<dyn std::error::Error>, found Bad, and the same for Worse.
fire lowers to async fn fire(&self) -> Result<(), Box<dyn std::error::Error>>, because the stored code’s channel is the box. The catch at the caller is lowered as if the error were the sum: match error { Bad::Oops => …, Worse::Boom => …, _ => … }. It does not open the box by the type each arm names. The opening that exists for a call through a field or a name of code (0.0.956, check_boxes.nika) does not reach a call to a method whose body calls stored code.
catch over a call whose callee’s channel is the box opens it by the type each arm names (downcast), whatever path made the callee boxed. A method, a free function and a call through a value should all go through the same path.oops.Related: #620 (ADR-351; this is the registry case discussed there, and #620 may lower it without the box). Independent of how #620’s open question is decided, Nikaia must not accept a program that rustc refuses.