Improve the syntax of rethrows to allow to indicate which throwing arguments should be considered for the rethrows functionality

If a method is declared with the rethrows keyword then all the closures that throw are considered. There is no way to select only a subset of the throwing arguments.

This proposal extends the rethrows syntax to allow to select which of the throwing arguments should be consider by the rethrows.
The new syntax will include after the rethrows comma separated indexes of the position of the throwing arguments that should be consider for the rethrows. For example:

// The method will throw only if the first closure argument throws
func method(_ aClosure: () throws -> (), aOtherClosure: () throws -> ()) rethrows(0) 

// The method will throw if the first or second closure argument throws
func method(_ aClosure: () throws -> (), aOtherClosure: () throws -> ()) rethrows(0, 1) 

//The above is equivalent with the default behaviour
func method(_ aClosure: () throws -> (), aOtherClosure: () throws -> ()) rethrows

An example of a practical usecase
I want to improve the XCTAssertThrowsError so that when the error handler throws then the XCTAssertThrowsError also throws.
But If I declare the XCTAssertThrowsError with rethrows then it will also throw if the expression closure throws (that is something we do not want since this is error should be handled internally).
With this improvement we should be able to write:

public func XCTAssertThrowsError<T>(_ expression: @autoclosure () throws -> T, 
                                    _ message: @autoclosure () -> String = "", 
                                    file: StaticString = #file, 
                                    line: UInt = #line,
                                    _ errorHandler: (_ error: Swift.Error) throws -> Void = { _ in }) rethrows(0)

Current workaround

One workaround you can currently use the have the same effect is to create a second method that rethrows and overloads the first method by declaring the arguments you want to be consider for the rethrow to throw.
For example:

func foo(f: () throws -> () = {}, g: () -> () = {}) {

func foo(f: () throws -> () = {}, g: () throws -> () = {}) rethrows {

//The above two method will have the same effect as:
func foo(f: () throws -> () = {}, g: () throws -> () = {}) rethrows(1) {
Terms of Service

Privacy Policy

Cookie Policy