My current thinking is to actually wrap the entire idiom in a new builtin operator, analogous to withoutActuallyEscaping
. Basically we want something like this:
/// Calls `fn` with a closure that evaluates `inner`, and saves the
/// result. Then after `fn` returns, forces the result.
///
/// \param fn A function taking a no-parameter, no-result closure as
/// an argument. This function must call its argument at
/// least once.
/// \param inner A function that can throw or return a 'T'.
///
/// \returns Whatever `inner` returned, or throws an error if `inner`
/// throws an error.
///
/// \fatal A fatal trap occurs if `fn` does not invoke its argument
/// at least once.
func withRethrownError<T>(_ fn: (() -> ()) -> (),
_ inner: () throws -> T) rethrows -> T {
var result: Result<T, Error>!
fn {
result = Result(catching: inner)
}
return try result.get()
}
The idea is that withRethrownError
is rethrows(unsafe)
, but it would be the only place where you'd need rethrows(unsafe)
(making it an implementation detail of the compiler; either withRethrownError
would be a builtin intrinsic, or it would use an underscored attribute specially for this purpose).