LYR-SEM0165
a 'throws' behind a task or coroutine return type is ambiguous
A function's return type is a Task<…> or Coroutine<…> (possibly under ?) without a thrown set of its own, followed by throws without parentheses, so the clause could be the task's or the function's.
Explanation
A task and a coroutine may carry a thrown set of their own. In fn launch(): Task<int> throws Oops the clause could say that the task may end in Oops or that launch itself throws it, and the two mean different things to every caller. The compiler does not guess.
Write (Task<int> throws Oops) for a task that may end in the error, or (Task<int>) throws Oops for a function that throws itself.
Wrong
import std.task { spawn, Task };
enum Oops :: [Error] {
Bad;
fn message(): string { return "oops"; }
}
fn risky(fail: bool): int throws Oops {
if (fail) { throw Oops.Bad; }
return 7;
}
fn launch(): Task<int> throws Oops {
return spawn(() => try risky(false));
}
fn main(): void {
}
Right
import std.task { spawn, Task };
enum Oops :: [Error] {
Bad;
fn message(): string { return "oops"; }
}
fn risky(fail: bool): int throws Oops {
if (fail) { throw Oops.Bad; }
return 7;
}
fn _launch(): (Task<int> throws Oops) {
return spawn(() => try risky(false));
}
fn main(): void {
}