Closure property that throws Typed Error in Swift 6 result in compiling error

I was trying out Swift 6 to play with its new features like the Typed throws introduced with SE-0413, and ran into an unexpected compiling error when using the typed throws closure as instance properties. Here is the code:

enum TypedError: Error {
    case failed
}

struct Example {
    var fail: () async throws(TypedError) -> Void
}

let example = Example(fail: { throw TypedError.failed })
// error: Invalid conversion of thrown error type 'any Error' to 'TypedError'

And the error occurred at the last line saying:

Invalid conversion of thrown error type 'any Error' to 'TypedError'

It looks like a bug to me because it seems that the TypedError is erased to any Error implicitly discarding the type declaration.

Update:
It seems that I have to declare typed throws again explicitly to get the compiler happy:

let example = Example { () async throws(TypedError) -> Void in
    throw TypedError.failed
}

This doesn't seem right, for it should be able to derive the type automatically.

2 Likes

From the proposal text:

This could break some code that depends on the precisely inferred type. To prevent this from becoming a source compatibility problem, we apply the same rule as for do...catch statements to limit inference: throw statements within the closure body are treated as having the type any Error in Swift 5.

Have you either opted into the Swift 6 language mode (it's not the default when you use the Swift 6.0 compiler) or enabled the upcoming feature flag FullTypedThrows?

There are problems with implicit typing. The Swift 6 Language Mode does not help. But so far, I've found that you can get around them with explicitness.

let example = Example { () throws(TypedError) in throw .failed }

Nice find. I can already see various throws and typed throws bugs filed against Swift 6, so hopefully they get fixed by the time it releases.

2 Likes

I tried with the upcoming feature swift settings in the package, but the error still persists.

IIUC, it should be an either or situation: either you build in Swift 5 mode with the experimental (it doesn't show up in Xcode 16's upcoming toggles) flag or in Swift 6 mode with no flags.

Yeah right. I was adding that just in case. The whole package is created by Xcode 16 beta 1:

// swift-tools-version:6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.