This is absolutely right. See the past discussion here: Pitch: Fix rethrows checking and add rethrows(unsafe)
Fixing the soundness hole with rethrows Classicâ„¢ is a source break, and requires a new escape hatch mechanism to make certain idioms work:
func f(fn: () throws -> T) rethrows {
var result: Result<T, Error>? = nil
someNonThrowingThing {
do {
result = .success(try fn()) // call to conditionally-throwing closure here
} catch {
result = .failure(error)
}
try result.get() // this throws unconditionally from the type checker's POV
}
Several libraries already use the local function workaround to make the above type check, so we'd need a rethrows(unsafe)
to express it, but that's gross.
With typed throws, you don't need the escape hatch at all. Parameterizing everything over E expresses this idiom safely:
func f<T, E>(fn: () throws(E) -> T) throws(E) {
var result: Result<T, E>? = nil
someNonThrowingThing {
do {
result = .success(try fn()) // call to closure that throws E
} catch {
result = .failure(error)
}
try result.get() // if this throws, it throws E, so it's fine
}
So in my opinion, we should freeze rethrows as-is, and not try to invent a rethrows(E)
for typed throws.