mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[SE-0413] Adopt typed throws in Result
Make `init(catching:)` and `get()` use typed throws. The former infers the `Failure` type from the closure provided (once full type inference is in place) and the latter only throws errors of the `Failure` type.
This commit is contained in:
@@ -161,8 +161,9 @@ public enum Result<Success, Failure: Error> {
|
||||
///
|
||||
/// - Returns: The success value, if the instance represents a success.
|
||||
/// - Throws: The failure value, if the instance represents a failure.
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public func get() throws -> Success {
|
||||
public func get() throws(Failure) -> Success {
|
||||
switch self {
|
||||
case let .success(success):
|
||||
return success
|
||||
@@ -172,13 +173,42 @@ public enum Result<Success, Failure: Error> {
|
||||
}
|
||||
}
|
||||
|
||||
extension Result where Failure == Swift.Error {
|
||||
extension Result {
|
||||
/// Creates a new result by evaluating a 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: () throws -> Success) {
|
||||
/// - Parameter body: A potentially throwing closure to evaluate.
|
||||
@_alwaysEmitIntoClient
|
||||
@inlinable
|
||||
public init(catching body: () throws(Failure) -> Success) {
|
||||
do {
|
||||
self = .success(try body())
|
||||
} catch {
|
||||
self = .failure(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Result {
|
||||
/// ABI: Historical get() throws
|
||||
@_silgen_name("$ss6ResultO3getxyKF")
|
||||
@usableFromInline
|
||||
func __abi_get() throws -> Success {
|
||||
switch self {
|
||||
case let .success(success):
|
||||
return success
|
||||
case let .failure(failure):
|
||||
throw failure
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Result where Failure == Swift.Error {
|
||||
/// ABI: Historical init(catching:)
|
||||
@_silgen_name("$ss6ResultOss5Error_pRs_rlE8catchingAByxsAC_pGxyKXE_tcfCa")
|
||||
@usableFromInline
|
||||
init(__abi_catching body: () throws(Failure) -> Success) {
|
||||
do {
|
||||
self = .success(try body())
|
||||
} catch {
|
||||
|
||||
@@ -26,6 +26,8 @@ Func Unicode.UTF32.Parser.parseScalar(from:) has generic signature change from <
|
||||
Func Unicode.UTF32.decode(_:) has generic signature change from <I where I : Swift.IteratorProtocol, I.Element == Swift.Unicode.UTF32.CodeUnit> to <I where I : Swift.IteratorProtocol, I.Element == Swift.UInt32>
|
||||
Func Unicode.UTF8.decode(_:) has generic signature change from <I where I : Swift.IteratorProtocol, I.Element == Swift.Unicode.UTF8.CodeUnit> to <I where I : Swift.IteratorProtocol, I.Element == Swift.UInt8>
|
||||
Constructor Mirror.init(_:children:displayStyle:ancestorRepresentation:) has generic signature change from <Subject, C where C : Swift.Collection, C.Element == Swift.Mirror.Child> to <Subject, C where C : Swift.Collection, C.Element == (label: Swift.String?, value: Any)>
|
||||
|
||||
// Generalizations due to typed throws.
|
||||
Func AnyBidirectionalCollection.map(_:) has generic signature change from <Element, T> to <Element, T, E where E : Swift.Error>
|
||||
Func AnyBidirectionalCollection.map(_:) is now without @rethrows
|
||||
Func AnyCollection.map(_:) has generic signature change from <Element, T> to <Element, T, E where E : Swift.Error>
|
||||
@@ -38,5 +40,6 @@ Func Collection.map(_:) has generic signature change from <Self, T where Self :
|
||||
Func Collection.map(_:) is now without @rethrows
|
||||
Func Sequence.map(_:) has generic signature change from <Self, T where Self : Swift.Sequence> to <Self, T, E where Self : Swift.Sequence, E : Swift.Error>
|
||||
Func Sequence.map(_:) is now without @rethrows
|
||||
Constructor Result.init(catching:) has generic signature change from <Success, Failure where Failure == any Swift.Error> to <Success, Failure where Failure : Swift.Error>
|
||||
|
||||
Protocol SIMDScalar has generic signature change from <Self == Self.SIMD16Storage.Scalar, Self.SIMD16Storage : Swift.SIMDStorage, Self.SIMD2Storage : Swift.SIMDStorage, Self.SIMD32Storage : Swift.SIMDStorage, Self.SIMD4Storage : Swift.SIMDStorage, Self.SIMD64Storage : Swift.SIMDStorage, Self.SIMD8Storage : Swift.SIMDStorage, Self.SIMDMaskScalar : Swift.FixedWidthInteger, Self.SIMDMaskScalar : Swift.SIMDScalar, Self.SIMDMaskScalar : Swift.SignedInteger, Self.SIMD16Storage.Scalar == Self.SIMD2Storage.Scalar, Self.SIMD2Storage.Scalar == Self.SIMD32Storage.Scalar, Self.SIMD32Storage.Scalar == Self.SIMD4Storage.Scalar, Self.SIMD4Storage.Scalar == Self.SIMD64Storage.Scalar, Self.SIMD64Storage.Scalar == Self.SIMD8Storage.Scalar> to <Self == Self.SIMD16Storage.Scalar, Self.SIMD16Storage : Swift.SIMDStorage, Self.SIMD2Storage : Swift.SIMDStorage, Self.SIMD32Storage : Swift.SIMDStorage, Self.SIMD4Storage : Swift.SIMDStorage, Self.SIMD64Storage : Swift.SIMDStorage, Self.SIMD8Storage : Swift.SIMDStorage, Self.SIMDMaskScalar : Swift.FixedWidthInteger, Self.SIMDMaskScalar : Swift.SIMDScalar, Self.SIMDMaskScalar : Swift.SignedInteger, Self.SIMDMaskScalar == Self.SIMDMaskScalar.SIMDMaskScalar, Self.SIMD16Storage.Scalar == Self.SIMD2Storage.Scalar, Self.SIMD2Storage.Scalar == Self.SIMD32Storage.Scalar, Self.SIMD32Storage.Scalar == Self.SIMD4Storage.Scalar, Self.SIMD4Storage.Scalar == Self.SIMD64Storage.Scalar, Self.SIMD64Storage.Scalar == Self.SIMD8Storage.Scalar>
|
||||
|
||||
@@ -75,6 +75,8 @@ Constructor _SmallString.init(taggedCocoa:) has return type change from Swift._S
|
||||
Enum Never has added a conformance to an existing protocol Decodable
|
||||
Enum Never has added a conformance to an existing protocol Encodable
|
||||
Enum Never has added a conformance to an existing protocol Identifiable
|
||||
|
||||
// These functions haven't actually changed ABI, but are using @_silgen_name tricks to maintain the old ABI while moving to typed throws.
|
||||
Func AnyBidirectionalCollection.map(_:) has been renamed to Func __rethrows_map(_:)
|
||||
Func AnyBidirectionalCollection.map(_:) has mangled name changing from 'Swift.AnyBidirectionalCollection.map<A>((A) throws -> A1) throws -> Swift.Array<A1>' to 'Swift.AnyBidirectionalCollection.__rethrows_map<A>((A) throws -> A1) throws -> Swift.Array<A1>'
|
||||
Func AnyBidirectionalCollection.map(_:) is now without @rethrows
|
||||
@@ -87,14 +89,16 @@ Func AnyRandomAccessCollection.map(_:) is now without @rethrows
|
||||
Func AnySequence.map(_:) has been renamed to Func __rethrows_map(_:)
|
||||
Func AnySequence.map(_:) has mangled name changing from 'Swift.AnySequence.map<A>((A) throws -> A1) throws -> Swift.Array<A1>' to 'Swift.AnySequence.__rethrows_map<A>((A) throws -> A1) throws -> Swift.Array<A1>'
|
||||
Func AnySequence.map(_:) is now without @rethrows
|
||||
|
||||
// These are using
|
||||
Func Sequence.map(_:) has been renamed to Func __rethrows_map(_:)
|
||||
Func Sequence.map(_:) has mangled name changing from '(extension in Swift):Swift.Sequence.map<A>((A.Element) throws -> A1) throws -> Swift.Array<A1>' to '(extension in Swift):Swift.Sequence.__rethrows_map<A>((A.Element) throws -> A1) throws -> Swift.Array<A1>'
|
||||
Func Sequence.map(_:) is now without @rethrows
|
||||
Func Collection.map(_:) has been renamed to Func __rethrows_map(_:)
|
||||
Func Collection.map(_:) has mangled name changing from '(extension in Swift):Swift.Collection.map<A>((A.Element) throws -> A1) throws -> Swift.Array<A1>' to '(extension in Swift):Swift.Collection.__rethrows_map<A>((A.Element) throws -> A1) throws -> Swift.Array<A1>'
|
||||
Func Collection.map(_:) is now without @rethrows
|
||||
Constructor Result.init(__abi_catching:) is a new API without @available attribute
|
||||
Constructor Result.init(catching:) has been removed
|
||||
Func Result.get() has been renamed to Func __abi_get()
|
||||
Func Result.get() has mangled name changing from 'Swift.Result.get() throws -> A' to 'Swift.Result.__abi_get() throws -> A'
|
||||
|
||||
// These haven't actually been removed; they are simply marked unavailable.
|
||||
// This seems to be a false positive in the ABI checker. This is not an ABI
|
||||
|
||||
@@ -67,10 +67,16 @@ ResultTests.test("Throwing Initialization and Unwrapping") {
|
||||
func throwing() throws -> String {
|
||||
throw Err.err
|
||||
}
|
||||
|
||||
|
||||
func throwingTyped() throws(Err) -> String {
|
||||
throw .err
|
||||
}
|
||||
|
||||
func knownNotThrowing() -> String { return string }
|
||||
|
||||
let result1 = Result { try throwing() }
|
||||
let result2 = Result { try notThrowing() }
|
||||
|
||||
|
||||
expectEqual(result1.failure as? Err, Err.err)
|
||||
expectEqual(result2.success, string)
|
||||
|
||||
@@ -98,6 +104,22 @@ ResultTests.test("Throwing Initialization and Unwrapping") {
|
||||
} catch {
|
||||
expectUnreachable()
|
||||
}
|
||||
|
||||
// Test strongly typed error via closure.
|
||||
// FIXME: Type inference should eliminate the need for the throws(Err)
|
||||
// annotations below.
|
||||
let result4 = Result { () throws(Err) in try throwingTyped() }
|
||||
let _: Result<String, Err> = result4 // check the type
|
||||
expectEqual(result4.failure, .err)
|
||||
do throws(Err) {
|
||||
_ = try result4.get()
|
||||
} catch let error {
|
||||
expectEqual(error, .err)
|
||||
}
|
||||
|
||||
let result5 = Result { knownNotThrowing() }
|
||||
let _: Result<String, Never> = result5 // check the type
|
||||
_ = result5.get() // no need for 'try'
|
||||
}
|
||||
|
||||
ResultTests.test("Functional Transforms") {
|
||||
|
||||
Reference in New Issue
Block a user