I would actually prefer Option 3:
fn regular_func() -> T { ... }
fn throwing_func() -> Result<U, E> { /* 1) */ }
fn generator_func() -> |T| => U { /* 2) */ }
fn async_func() -> |T| => () -> U { /* 2) */ }
fn stream_func() -> |T| => U -> V { /* 2) */ }
let regular_closure = |T| -> U { ... }
let throwing_closure = |T| -> Result<U, E> { ... }
let generator_closure = |T| => U { ... }
let async_closure = |T| => () -> U { ... }
let stream_closure = |T| => U -> V { ... }
The syntax should be self-explanatory: a closure taking some initial parameters |T|, yielding => 0-n times a value of type U, finally returning -> a value of type ‘V’.
ad 1) I don’t believe that Ok-wrapping is a sufficient reason for special-casing Return return types. That said, a natural extension to above proposal could be:
fn throwing_func() -> T? { ... }
mimicking the ? in code used to exit early. However, may be confusing with optional values in other languages.
ad 2) This is for functions returning a closure. Functions that themselves are closure-like should either be assigned as closure let closure = |T| => U -> V. Alternatively, for top-level declarations, combining closure and fn:
fn closure_like_func |T| => U -> V