I am trying to use typed throws from an async function but the compiler can’t seem to infer the type. I get the error Type ‘_ErrorCodeProtocol’ has no member ‘one’
if I do the same code not async it works. What am I doing wrong?
enum MyError: Error {
case one
}
struct MyTest {
func test() async throws(MyError) {}
func anotherTest() {
Task {
do {
try await test()
} catch {
switch error {
case .one:
print("one")
}
}
}
}
}
0
The issue doesn’t seem to be related to Tasks, but with closures.
The following code has the same issue.
let closure = {
do {
try await test()
} catch {
switch error {
case .one:
print("one")
}
}
}
Another (stil not nice) workaround seems to be to use a func instead
func anotherTest() {
func taskOperation() async {
do {
try await test()
} catch {
switch error {
case .one:
print("one")
}
}
}
Task(operation: taskOperation)
}
Ivan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
1
Task
has a generic, Failure
, which is defined as an existential any Error
, which appears to interfere with the typed throwing inference logic. (Interesting, Xcode’s “Quick help” seems to understand that error
is MyError
, but the compiler does not.)
You can get around this if you explicitly specify that the do
block throws(MyError)
:
func foo() {
Task {
do throws(MyError) {
try await test()
} catch {
switch error {
case .one: print("one")
}
}
}
}
This is a bit clumsy, but gets around your immediate problem.
Probably needless to say, this explicit typing of the do
–catch
block is not needed if you are just writing an async
function, but only appears to be necessary when embedding this in a closure, such as when introducing unstructured concurrency with the Task
initializer.
The other alternative to do throws(…)
–catch
is do
–catch let error as …
:
func bar() {
Task {
do {
try await funcWithTypedThrow()
} catch let error as MyError {
switch error {
case .one: print("one")
}
}
}
}
It is a subtle point, but this is not quite the same thing as do throws(…)
–catch
. In Xcode 16 and Swift 6, this catch let error as MyError
in bar
is (incorrectly) understood to have uncaught errors, and will make this a throwing Task
. You won’t notice this unless you save the Task
to a property or ivar for our cancelation handling, but it is something to note.
7