Skip to content

Commit 92fccf9

Browse files
author
Itai Ferber
committed
Fix coding error bridging to NSError
CustomNSError briding only works when the CustomNSError conformance is in the same module as the original error declaration. We need to sink these down into the standard library.
1 parent 8f38678 commit 92fccf9

File tree

3 files changed

+85
-69
lines changed

3 files changed

+85
-69
lines changed

stdlib/public/SDK/Foundation/Codable.swift

Lines changed: 3 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,59 +14,9 @@
1414
// Errors
1515
//===----------------------------------------------------------------------===//
1616

17-
// Adding the following extensions to EncodingError and DecodingError allows them to bridge to NSErrors implicitly.
18-
19-
fileprivate let NSCodingPathErrorKey = "NSCodingPath"
20-
fileprivate let NSDebugDescriptionErrorKey = "NSDebugDescription"
21-
22-
extension EncodingError : CustomNSError {
23-
public static var errorDomain: String = NSCocoaErrorDomain
24-
25-
public var errorCode: Int {
26-
switch self {
27-
case .invalidValue(_, _): return CocoaError.coderInvalidValue.rawValue
28-
}
29-
}
30-
31-
public var errorUserInfo: [String : Any] {
32-
let context: Context
33-
switch self {
34-
case .invalidValue(_, let c): context = c
35-
}
36-
37-
return [NSCodingPathErrorKey: context.codingPath,
38-
NSDebugDescriptionErrorKey: context.debugDescription]
39-
}
40-
}
41-
42-
extension DecodingError : CustomNSError {
43-
public static var errorDomain: String = NSCocoaErrorDomain
44-
45-
public var errorCode: Int {
46-
switch self {
47-
case .valueNotFound(_, _): fallthrough
48-
case .keyNotFound(_, _):
49-
return CocoaError._coderValueNotFound.rawValue
50-
51-
case .typeMismatch(_, _): fallthrough
52-
case .dataCorrupted(_):
53-
return CocoaError._coderReadCorrupt.rawValue
54-
}
55-
}
56-
57-
public var errorUserInfo: [String : Any]? {
58-
let context: Context
59-
switch self {
60-
case .typeMismatch(_, let c): context = c
61-
case .valueNotFound(_, let c): context = c
62-
case .keyNotFound(_, let c): context = c
63-
case .dataCorrupted(let c): context = c
64-
}
65-
66-
return [NSCodingPathErrorKey: context.codingPath,
67-
NSDebugDescriptionErrorKey: context.debugDescription]
68-
}
69-
}
17+
// Both of these error types bridge to NSError, and through the entry points they use, no further work is needed to make them localized.
18+
extension EncodingError : LocalizedError {}
19+
extension DecodingError : LocalizedError {}
7020

7121
//===----------------------------------------------------------------------===//
7222
// Error Utilities

stdlib/public/SDK/Foundation/NSError.swift

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -850,19 +850,11 @@ extension CocoaError.Code {
850850

851851
@available(OSX, introduced: 10.11) @available(iOS, introduced: 9.0)
852852
public static var coderReadCorrupt: CocoaError.Code {
853-
return _coderReadCorrupt
854-
}
855-
856-
internal static var _coderReadCorrupt: CocoaError.Code {
857853
return CocoaError.Code(rawValue: 4864)
858854
}
859855

860856
@available(OSX, introduced: 10.11) @available(iOS, introduced: 9.0)
861857
public static var coderValueNotFound: CocoaError.Code {
862-
return _coderValueNotFound
863-
}
864-
865-
internal static var _coderValueNotFound: CocoaError.Code {
866858
return CocoaError.Code(rawValue: 4865)
867859
}
868860

@@ -1301,19 +1293,11 @@ extension CocoaError {
13011293

13021294
@available(OSX, introduced: 10.11) @available(iOS, introduced: 9.0)
13031295
public static var coderReadCorrupt: CocoaError.Code {
1304-
return _coderReadCorrupt
1305-
}
1306-
1307-
public static var _coderReadCorrupt: CocoaError.Code {
13081296
return CocoaError.Code(rawValue: 4864)
13091297
}
13101298

13111299
@available(OSX, introduced: 10.11) @available(iOS, introduced: 9.0)
13121300
public static var coderValueNotFound: CocoaError.Code {
1313-
return _coderValueNotFound
1314-
}
1315-
1316-
internal static var _coderValueNotFound: CocoaError.Code {
13171301
return CocoaError.Code(rawValue: 4865)
13181302
}
13191303

stdlib/public/core/Codable.swift

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2045,6 +2045,44 @@ public enum EncodingError : Error {
20452045
///
20462046
/// Contains the attempted value, along with context for debugging.
20472047
case invalidValue(Any, Context)
2048+
2049+
// MARK: - NSError Bridging
2050+
2051+
// CustomNSError bridging applies only when the CustomNSError conformance is applied in the same module as the declared error type.
2052+
// Since we cannot access CustomNSError (which is defined in Foundation) from here, we can use the "hidden" entry points.
2053+
2054+
public var _domain: String {
2055+
return "NSCocoaErrorDomain"
2056+
}
2057+
2058+
public var _code: Int {
2059+
switch self {
2060+
case .invalidValue(_, _): return 4866
2061+
}
2062+
}
2063+
2064+
public var _userInfo: AnyObject? {
2065+
// The error dictionary must be returned as an AnyObject. We can do this only on platforms with bridging, unfortunately.
2066+
#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
2067+
let context: Context
2068+
switch self {
2069+
case .invalidValue(_, let c): context = c
2070+
}
2071+
2072+
var userInfo: [String : Any] = [
2073+
"NSCodingPath": context.codingPath,
2074+
"NSDebugDescription": context.debugDescription
2075+
]
2076+
2077+
if let underlyingError = context.underlyingError {
2078+
userInfo["NSUnderlyingError"] = underlyingError
2079+
}
2080+
2081+
return userInfo as AnyObject
2082+
#else
2083+
return nil
2084+
#endif
2085+
}
20482086
}
20492087

20502088
/// An error that occurs during the decoding of a value.
@@ -2091,6 +2129,50 @@ public enum DecodingError : Error {
20912129
///
20922130
/// Contains context for debugging.
20932131
case dataCorrupted(Context)
2132+
2133+
// MARK: - NSError Bridging
2134+
2135+
// CustomNSError bridging applies only when the CustomNSError conformance is applied in the same module as the declared error type.
2136+
// Since we cannot access CustomNSError (which is defined in Foundation) from here, we can use the "hidden" entry points.
2137+
2138+
public var _domain: String {
2139+
return "NSCocoaErrorDomain"
2140+
}
2141+
2142+
public var _code: Int {
2143+
switch self {
2144+
case .keyNotFound(_, _): fallthrough
2145+
case .valueNotFound(_, _): return 4865
2146+
case .typeMismatch(_, _): fallthrough
2147+
case .dataCorrupted(_): return 4864
2148+
}
2149+
}
2150+
2151+
public var _userInfo: AnyObject? {
2152+
// The error dictionary must be returned as an AnyObject. We can do this only on platforms with bridging, unfortunately.
2153+
#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
2154+
let context: Context
2155+
switch self {
2156+
case .keyNotFound(_, let c): context = c
2157+
case .valueNotFound(_, let c): context = c
2158+
case .typeMismatch(_, let c): context = c
2159+
case .dataCorrupted( let c): context = c
2160+
}
2161+
2162+
var userInfo: [String : Any] = [
2163+
"NSCodingPath": context.codingPath,
2164+
"NSDebugDescription": context.debugDescription
2165+
]
2166+
2167+
if let underlyingError = context.underlyingError {
2168+
userInfo["NSUnderlyingError"] = underlyingError
2169+
}
2170+
2171+
return userInfo as AnyObject
2172+
#else
2173+
return nil
2174+
#endif
2175+
}
20942176
}
20952177

20962178
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)