How to use `autoreleasepool` with typed throws

Minimum reproducible code:

struct AError: Error {}

func a() throws(AError) {}

func b() throws(AError) {
    try autoreleasepool { // Thrown expression type 'any Error' cannot be converted to error type 'AError'
        try a()
    }
}

while the function signature of autoreleasepool seems to be support typed throws:

@available(macOS 10.0, iOS 1.0, tvOS 1.0, watchOS 1.0, *)
public func autoreleasepool<E, Result>(invoking body: () throws(E) -> Result) throws(E) -> Result where E : Error, Result : ~Copyable
1 Like

There's currently a limitation of error type inference for closures, here's the reference.

The workaround is to explicitly specify the thrown type:

func b() throws(AError) {
    try autoreleasepool { () throws(AError) in
        try a()
    }
}
3 Likes

I don't see how the linked section SE-0431 ∕ Closure thrown type inference explains the error @Saafo is seeing here.

That section says that plain throw statements in a closure body will be inferred to throw any Error. But importantly, it doesn't say the same about a try statement calling a function that uses typed throws, as in @Saafo's example. In fact, the proposal explicitly says that this situation should result in an inferred closure type with a typed error (emphasis mine):

With the rule specified here, it will be inferred as throws(CatError). 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. This way, one can only infer a more specific thrown error type in a closure when the try operations are calling functions that make use of typed errors.

As far as I can tell, the behavior @Saafo describes here is not covered by the type inference limitations/shortcuts documented in SE-0431. And the same goes for @Saafo's other example discussed here: How to catch typed throws in clousures. I think both of these should compile as-is according to SE-0431.

2 Likes

With all due respect, the behavior you described did not get implemented.

From the Introduction section:

Note: the originally accepted version of this proposal included type inference changes intended for Swift 6.0 that were behind the upcoming feature flag FullTypedThrows . These type inference changes did not get implemented in Swift 6.0, and have therefore been removed from this proposal and placed into "Future Directions" so they can be revisited once implemented.

The actual behavior stayed unchanged, just as the example from the linked section shows:

{ throw E() } // throws

{ try call() } // throws
1 Like

I acknowledge that the section we're referring to is under Future Directions, but that's not how I read it.

The way I understand it, the proposed FullTypedThrows feature refers only to full typed throws type inference from throws statements, which the proposal repeatedly notes (not only in Future Directions) as a potential source compatibility issue.

But apparently you're right and I'm wrong.