Skip to content

Commit

Permalink
Support typed throws (#52)
Browse files Browse the repository at this point in the history
* Support typed throws

* Update Sources/ConcurrencyExtras/Result.swift

Co-authored-by: Stephen Celis <[email protected]>

* Constrain change to compiler(>=6)

* Also gate the test to Swift 6

* Include func g in ifdef

* wip

---------

Co-authored-by: Stephen Celis <[email protected]>
Co-authored-by: Stephen Celis <[email protected]>
  • Loading branch information
3 people authored Dec 16, 2024
1 parent d1e4642 commit f5d0abc
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 12 deletions.
37 changes: 25 additions & 12 deletions Sources/ConcurrencyExtras/Result.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
extension Result where Failure == Swift.Error {
/// Creates a new result by evaluating an async throwing closure, capturing the returned value as
/// a success, or any thrown error as a failure.
///
/// - Parameter body: A throwing closure to evaluate.
@_transparent
public init(catching body: () async throws -> Success) async {
do {
self = .success(try await body())
} catch {
self = .failure(error)
#if compiler(>=6)
extension Result {
/// Creates a new result by evaluating an async throwing closure, capturing the returned value as
/// a success, or any thrown error as a failure.
///
/// - Parameter body: A throwing closure to evaluate.
@_transparent
public init(catching body: () async throws(Failure) -> Success) async {
do {
self = .success(try await body())
} catch {
self = .failure(error)
}
}
}
}
#else
extension Result where Failure == Swift.Error {
@_transparent
public init(catching body: () async throws -> Success) async {
do {
self = .success(try await body())
} catch {
self = .failure(error)
}
}
}
#endif
62 changes: 62 additions & 0 deletions Tests/ConcurrencyExtrasTests/ResultTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import ConcurrencyExtras
import XCTest

final class ResultTests: XCTestCase {
struct SomeError: Error, Equatable { }
func f(_ value: Int) async throws -> Int {
if value == 42 {
return 42
} else {
throw SomeError()
}
}

func testBasics() async {
do {
let res = await Result { try await f(42) }
XCTAssertEqual(try res.get(), 42)
}
do {
let res = await Result { try await f(0) }
do {
_ = try res.get()
} catch let error as SomeError {
XCTAssertEqual(error, SomeError())
} catch {
XCTFail("unexpected error: \(error)")
}
}
}

#if compiler(>=6)
func g(_ value: Int) async throws(SomeError) -> Int {
if value == 42 {
return 42
} else {
throw SomeError()
}
}

func testTypedThrows() async {
let res = await Result { () async throws(SomeError) -> Int in try await g(0) }
do {
_ = try res.get()
} catch {
XCTAssertEqual(error, SomeError())
}
}

func h() async throws(SomeError) -> Int {
throw SomeError()
}

func testTypedThrowsInference() async {
let res = await Result(catching: h)
do {
_ = try res.get()
} catch {
XCTAssertEqual(error, SomeError())
}
}
#endif
}

0 comments on commit f5d0abc

Please sign in to comment.