This situation is a common occurrence with typed throws. Is there an intended solution, or has not enough thought and effort been put into it yet?
A function may throw an error.
enum FunctionsError: Error { }
The function accepts a closure, and may also throw that closure's error. This cannot be modeled in the type system, so must utilize untyped throws and documentation, like we used to have to do with everything.
The problem is, when Error is Never, throws does not "automatically become" (à la rethrows) throws(FunctionsError), as it is then statically known to be. Casting works fine, if you add in some spelling difference so it's not a real overload…
Have you considered adding a case (with payload) to FunctionsError to wrap the closure's error in, instead of going all the way to throwing an any Error?
Yes. I think there's room for the language to support such unions better in the future—people have some good ideas about them—perhaps if Never as associated values made cases not need to be checked…? I don’t see a related solution at present. FunctionsError can’t actually be assumed to be tied to the function, or a closure.
That's …one error type? That overload has to account for all errors that are not Never, not one specific type in particular.
enum OuterError<Inner: Error>: Error {
case fooError
case closureError(Inner)
}
func f<E>(_: () throws(E) -> ()) throws(OuterError<E>) -> () {}
Also it appears that exhaustivity checking is smart enough to ignore the uninhabited case:
func f(_ e: OuterError<Never>) {
switch e { // ok
case .foo: print("Hi")
}
}
Ah I see, yeah, there might not be a way to call the other overload in this case. However if you use typed errors instead of any Error, you don't need the second overload, so that's another argument in favor of that approach.