Merge pull request #10706 from itaiferber/swift-4.0-branch
[4.0] Optionality updates to Codable API
diff --git a/lib/Sema/TypeCheckSwitchStmt.cpp b/lib/Sema/TypeCheckSwitchStmt.cpp
index 3b67caf..fdb2b39 100644
--- a/lib/Sema/TypeCheckSwitchStmt.cpp
+++ b/lib/Sema/TypeCheckSwitchStmt.cpp
@@ -1104,7 +1104,7 @@
}
}
- TC.diagnose(startLoc, diag::non_exhaustive_switch);
+ TC.diagnose(startLoc, mainDiagType);
TC.diagnose(startLoc, diag::missing_several_cases, false)
.fixItInsert(endLoc, buffer.str());
} else {
diff --git a/stdlib/public/SDK/Foundation/Codable.swift b/stdlib/public/SDK/Foundation/Codable.swift
index 4410933..200cbb1 100644
--- a/stdlib/public/SDK/Foundation/Codable.swift
+++ b/stdlib/public/SDK/Foundation/Codable.swift
@@ -14,59 +14,9 @@
// Errors
//===----------------------------------------------------------------------===//
-// Adding the following extensions to EncodingError and DecodingError allows them to bridge to NSErrors implicitly.
-
-fileprivate let NSCodingPathErrorKey = "NSCodingPath"
-fileprivate let NSDebugDescriptionErrorKey = "NSDebugDescription"
-
-extension EncodingError : CustomNSError {
- public static var errorDomain: String = NSCocoaErrorDomain
-
- public var errorCode: Int {
- switch self {
- case .invalidValue(_, _): return CocoaError.coderInvalidValue.rawValue
- }
- }
-
- public var errorUserInfo: [String : Any] {
- let context: Context
- switch self {
- case .invalidValue(_, let c): context = c
- }
-
- return [NSCodingPathErrorKey: context.codingPath,
- NSDebugDescriptionErrorKey: context.debugDescription]
- }
-}
-
-extension DecodingError : CustomNSError {
- public static var errorDomain: String = NSCocoaErrorDomain
-
- public var errorCode: Int {
- switch self {
- case .valueNotFound(_, _): fallthrough
- case .keyNotFound(_, _):
- return CocoaError._coderValueNotFound.rawValue
-
- case .typeMismatch(_, _): fallthrough
- case .dataCorrupted(_):
- return CocoaError._coderReadCorrupt.rawValue
- }
- }
-
- public var errorUserInfo: [String : Any]? {
- let context: Context
- switch self {
- case .typeMismatch(_, let c): context = c
- case .valueNotFound(_, let c): context = c
- case .keyNotFound(_, let c): context = c
- case .dataCorrupted(let c): context = c
- }
-
- return [NSCodingPathErrorKey: context.codingPath,
- NSDebugDescriptionErrorKey: context.debugDescription]
- }
-}
+// Both of these error types bridge to NSError, and through the entry points they use, no further work is needed to make them localized.
+extension EncodingError : LocalizedError {}
+extension DecodingError : LocalizedError {}
//===----------------------------------------------------------------------===//
// Error Utilities
diff --git a/stdlib/public/SDK/Foundation/JSONEncoder.swift b/stdlib/public/SDK/Foundation/JSONEncoder.swift
index 14e38d9..65a5e54 100644
--- a/stdlib/public/SDK/Foundation/JSONEncoder.swift
+++ b/stdlib/public/SDK/Foundation/JSONEncoder.swift
@@ -62,8 +62,11 @@
/// The strategy to use for encoding `Data` values.
public enum DataEncodingStrategy {
+ /// Defer to `Data` for choosing an encoding.
+ case deferredToData
+
/// Encoded the `Data` as a Base64-encoded string. This is the default strategy.
- case base64Encode
+ case base64
/// Encode the `Data` as a custom value encoded by the given closure.
///
@@ -86,8 +89,8 @@
/// The strategy to use in encoding dates. Defaults to `.deferredToDate`.
open var dateEncodingStrategy: DateEncodingStrategy = .deferredToDate
- /// The strategy to use in encoding binary data. Defaults to `.base64Encode`.
- open var dataEncodingStrategy: DataEncodingStrategy = .base64Encode
+ /// The strategy to use in encoding binary data. Defaults to `.base64`.
+ open var dataEncodingStrategy: DataEncodingStrategy = .base64
/// The strategy to use in encoding non-conforming numbers. Defaults to `.throw`.
open var nonConformingFloatEncodingStrategy: NonConformingFloatEncodingStrategy = .throw
@@ -142,7 +145,11 @@
}
let writingOptions = JSONSerialization.WritingOptions(rawValue: self.outputFormatting.rawValue)
- return try JSONSerialization.data(withJSONObject: topLevel, options: writingOptions)
+ do {
+ return try JSONSerialization.data(withJSONObject: topLevel, options: writingOptions)
+ } catch {
+ throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Unable to encode the given top-level value to JSON.", underlyingError: error))
+ }
}
}
@@ -663,7 +670,12 @@
fileprivate func box(_ data: Data) throws -> NSObject {
switch self.options.dataEncodingStrategy {
- case .base64Encode:
+ case .deferredToData:
+ // Must be called with a surrounding with(pushedKey:) call.
+ try data.encode(to: self)
+ return self.storage.popContainer()
+
+ case .base64:
return NSString(string: data.base64EncodedString())
case .custom(let closure):
@@ -815,8 +827,11 @@
/// The strategy to use for decoding `Data` values.
public enum DataDecodingStrategy {
+ /// Defer to `Data` for decoding.
+ case deferredToData
+
/// Decode the `Data` from a Base64-encoded string. This is the default strategy.
- case base64Decode
+ case base64
/// Decode the `Data` as a custom value decoded by the given closure.
case custom((_ decoder: Decoder) throws -> Data)
@@ -834,8 +849,8 @@
/// The strategy to use in decoding dates. Defaults to `.deferredToDate`.
open var dateDecodingStrategy: DateDecodingStrategy = .deferredToDate
- /// The strategy to use in decoding binary data. Defaults to `.base64Decode`.
- open var dataDecodingStrategy: DataDecodingStrategy = .base64Decode
+ /// The strategy to use in decoding binary data. Defaults to `.base64`.
+ open var dataDecodingStrategy: DataDecodingStrategy = .base64
/// The strategy to use in decoding non-conforming numbers. Defaults to `.throw`.
open var nonConformingFloatDecodingStrategy: NonConformingFloatDecodingStrategy = .throw
@@ -874,7 +889,13 @@
/// - throws: `DecodingError.dataCorrupted` if values requested from the payload are corrupted, or if the given data is not valid JSON.
/// - throws: An error if any value throws an error during decoding.
open func decode<T : Decodable>(_ type: T.Type, from data: Data) throws -> T {
- let topLevel = try JSONSerialization.jsonObject(with: data)
+ let topLevel: Any
+ do {
+ topLevel = try JSONSerialization.jsonObject(with: data)
+ } catch {
+ throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: error))
+ }
+
let decoder = _JSONDecoder(referencing: topLevel, options: self.options)
return try T(from: decoder)
}
@@ -2037,7 +2058,13 @@
guard !(value is NSNull) else { return nil }
switch self.options.dataDecodingStrategy {
- case .base64Decode:
+ case .deferredToData:
+ self.storage.push(container: value)
+ let data = try Data(from: self)
+ self.storage.popContainer()
+ return data
+
+ case .base64:
guard let string = value as? String else {
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
diff --git a/stdlib/public/SDK/Foundation/NSError.swift b/stdlib/public/SDK/Foundation/NSError.swift
index 768fb26..3b3c585 100644
--- a/stdlib/public/SDK/Foundation/NSError.swift
+++ b/stdlib/public/SDK/Foundation/NSError.swift
@@ -850,19 +850,11 @@
@available(OSX, introduced: 10.11) @available(iOS, introduced: 9.0)
public static var coderReadCorrupt: CocoaError.Code {
- return _coderReadCorrupt
- }
-
- internal static var _coderReadCorrupt: CocoaError.Code {
return CocoaError.Code(rawValue: 4864)
}
@available(OSX, introduced: 10.11) @available(iOS, introduced: 9.0)
public static var coderValueNotFound: CocoaError.Code {
- return _coderValueNotFound
- }
-
- internal static var _coderValueNotFound: CocoaError.Code {
return CocoaError.Code(rawValue: 4865)
}
@@ -1301,19 +1293,11 @@
@available(OSX, introduced: 10.11) @available(iOS, introduced: 9.0)
public static var coderReadCorrupt: CocoaError.Code {
- return _coderReadCorrupt
- }
-
- public static var _coderReadCorrupt: CocoaError.Code {
return CocoaError.Code(rawValue: 4864)
}
@available(OSX, introduced: 10.11) @available(iOS, introduced: 9.0)
public static var coderValueNotFound: CocoaError.Code {
- return _coderValueNotFound
- }
-
- internal static var _coderValueNotFound: CocoaError.Code {
return CocoaError.Code(rawValue: 4865)
}
diff --git a/stdlib/public/SDK/Foundation/PlistEncoder.swift b/stdlib/public/SDK/Foundation/PlistEncoder.swift
index 35cfdfd..b7e4d2f 100644
--- a/stdlib/public/SDK/Foundation/PlistEncoder.swift
+++ b/stdlib/public/SDK/Foundation/PlistEncoder.swift
@@ -74,7 +74,11 @@
debugDescription: "Top-level \(Value.self) encoded as date property list fragment."))
}
- return try PropertyListSerialization.data(fromPropertyList: topLevel, format: self.outputFormat, options: 0)
+ do {
+ return try PropertyListSerialization.data(fromPropertyList: topLevel, format: self.outputFormat, options: 0)
+ } catch {
+ throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Unable to encode the given top-level value as a property list", underlyingError: error))
+ }
}
}
@@ -642,7 +646,12 @@
/// - throws: `DecodingError.dataCorrupted` if values requested from the payload are corrupted, or if the given data is not a valid property list.
/// - throws: An error if any value throws an error during decoding.
open func decode<T : Decodable>(_ type: T.Type, from data: Data, format: inout PropertyListSerialization.PropertyListFormat) throws -> T {
- let topLevel = try PropertyListSerialization.propertyList(from: data, options: [], format: &format)
+ let topLevel: Any
+ do {
+ topLevel = try PropertyListSerialization.propertyList(from: data, options: [], format: &format)
+ } catch {
+ throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "The given data was not a valid property list.", underlyingError: error))
+ }
let decoder = _PlistDecoder(referencing: topLevel, options: self.options)
return try T(from: decoder)
}
diff --git a/stdlib/public/core/Codable.swift b/stdlib/public/core/Codable.swift
index 6d437d7..1cd4209 100644
--- a/stdlib/public/core/Codable.swift
+++ b/stdlib/public/core/Codable.swift
@@ -2096,6 +2096,10 @@
/// A container that can support the storage and direct encoding of a single
/// non-keyed value.
public protocol SingleValueEncodingContainer {
+ /// The path of coding keys taken to get to this point in encoding.
+ /// A `nil` value indicates an unkeyed container.
+ var codingPath: [CodingKey?] { get }
+
/// Encodes a null value.
///
/// - throws: `EncodingError.invalidValue` if a null value is invalid in the current context for this format.
@@ -2210,6 +2214,10 @@
/// A `SingleValueDecodingContainer` is a container which can support the storage and direct decoding of a single non-keyed value.
public protocol SingleValueDecodingContainer {
+ /// The path of coding keys taken to get to this point in encoding.
+ /// A `nil` value indicates an unkeyed container.
+ var codingPath: [CodingKey?] { get }
+
/// Decodes a null value.
///
/// - returns: Whether the encountered value was null.
@@ -2382,13 +2390,18 @@
/// A description of what went wrong, for debugging purposes.
public let debugDescription: String
+ /// The underlying error which caused this error, if any.
+ public let underlyingError: Error?
+
/// Initializes `self` with the given path of `CodingKey`s and a description of what went wrong.
///
/// - parameter codingPath: The path of `CodingKey`s taken to get to the point of the failing encode call.
/// - parameter debugDescription: A description of what went wrong, for debugging purposes.
- public init(codingPath: [CodingKey?], debugDescription: String) {
+ /// - parameter underlyingError: The underlying error which caused this error, if any.
+ public init(codingPath: [CodingKey?], debugDescription: String, underlyingError: Error? = nil) {
self.codingPath = codingPath
self.debugDescription = debugDescription
+ self.underlyingError = underlyingError
}
}
@@ -2396,6 +2409,44 @@
///
/// Contains the attempted value, along with context for debugging.
case invalidValue(Any, Context)
+
+ // MARK: - NSError Bridging
+
+ // CustomNSError bridging applies only when the CustomNSError conformance is applied in the same module as the declared error type.
+ // Since we cannot access CustomNSError (which is defined in Foundation) from here, we can use the "hidden" entry points.
+
+ public var _domain: String {
+ return "NSCocoaErrorDomain"
+ }
+
+ public var _code: Int {
+ switch self {
+ case .invalidValue(_, _): return 4866
+ }
+ }
+
+ public var _userInfo: AnyObject? {
+ // The error dictionary must be returned as an AnyObject. We can do this only on platforms with bridging, unfortunately.
+ #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+ let context: Context
+ switch self {
+ case .invalidValue(_, let c): context = c
+ }
+
+ var userInfo: [String : Any] = [
+ "NSCodingPath": context.codingPath,
+ "NSDebugDescription": context.debugDescription
+ ]
+
+ if let underlyingError = context.underlyingError {
+ userInfo["NSUnderlyingError"] = underlyingError
+ }
+
+ return userInfo as AnyObject
+ #else
+ return nil
+ #endif
+ }
}
/// An error that occurs during the decoding of a value.
@@ -2408,13 +2459,18 @@
/// A description of what went wrong, for debugging purposes.
public let debugDescription: String
+ /// The underlying error which caused this error, if any.
+ public let underlyingError: Error?
+
/// Initializes `self` with the given path of `CodingKey`s and a description of what went wrong.
///
/// - parameter codingPath: The path of `CodingKey`s taken to get to the point of the failing decode call.
/// - parameter debugDescription: A description of what went wrong, for debugging purposes.
- public init(codingPath: [CodingKey?], debugDescription: String) {
+ /// - parameter underlyingError: The underlying error which caused this error, if any.
+ public init(codingPath: [CodingKey?], debugDescription: String, underlyingError: Error? = nil) {
self.codingPath = codingPath
self.debugDescription = debugDescription
+ self.underlyingError = underlyingError
}
}
@@ -2437,6 +2493,91 @@
///
/// Contains context for debugging.
case dataCorrupted(Context)
+
+ // MARK: - NSError Bridging
+
+ // CustomNSError bridging applies only when the CustomNSError conformance is applied in the same module as the declared error type.
+ // Since we cannot access CustomNSError (which is defined in Foundation) from here, we can use the "hidden" entry points.
+
+ public var _domain: String {
+ return "NSCocoaErrorDomain"
+ }
+
+ public var _code: Int {
+ switch self {
+ case .keyNotFound(_, _): fallthrough
+ case .valueNotFound(_, _): return 4865
+ case .typeMismatch(_, _): fallthrough
+ case .dataCorrupted(_): return 4864
+ }
+ }
+
+ public var _userInfo: AnyObject? {
+ // The error dictionary must be returned as an AnyObject. We can do this only on platforms with bridging, unfortunately.
+ #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+ let context: Context
+ switch self {
+ case .keyNotFound(_, let c): context = c
+ case .valueNotFound(_, let c): context = c
+ case .typeMismatch(_, let c): context = c
+ case .dataCorrupted( let c): context = c
+ }
+
+ var userInfo: [String : Any] = [
+ "NSCodingPath": context.codingPath,
+ "NSDebugDescription": context.debugDescription
+ ]
+
+ if let underlyingError = context.underlyingError {
+ userInfo["NSUnderlyingError"] = underlyingError
+ }
+
+ return userInfo as AnyObject
+ #else
+ return nil
+ #endif
+ }
+}
+
+// The following extensions allow for easier error construction.
+
+public extension DecodingError {
+ /// A convenience method which creates a new .dataCorrupted error using a constructed coding path and the given debug description.
+ ///
+ /// Constructs a coding path by appending the given key to the given container's coding path.
+ ///
+ /// - param key: The key which caused the failure.
+ /// - param container: The container in which the corrupted data was accessed.
+ /// - param debugDescription: A description of the error to aid in debugging.
+ static func dataCorruptedError<C : KeyedDecodingContainerProtocol>(forKey key: C.Key, in container: C, debugDescription: String) -> DecodingError {
+ let context = DecodingError.Context(codingPath: container.codingPath + [key],
+ debugDescription: debugDescription)
+ return .dataCorrupted(context)
+ }
+
+ /// A convenience method which creates a new .dataCorrupted error using a constructed coding path and the given debug description.
+ ///
+ /// Constructs a coding path by appending a nil key to the given container's coding path.
+ ///
+ /// - param container: The container in which the corrupted data was accessed.
+ /// - param debugDescription: A description of the error to aid in debugging.
+ static func dataCorruptedError(in container: UnkeyedDecodingContainer, debugDescription: String) -> DecodingError {
+ let context = DecodingError.Context(codingPath: container.codingPath + [nil],
+ debugDescription: debugDescription)
+ return .dataCorrupted(context)
+ }
+
+ /// A convenience method which creates a new .dataCorrupted error using a constructed coding path and the given debug description.
+ ///
+ /// Uses the given container's coding path as the constructed path.
+ ///
+ /// - param container: The container in which the corrupted data was accessed.
+ /// - param debugDescription: A description of the error to aid in debugging.
+ static func dataCorruptedError(in container: SingleValueDecodingContainer, debugDescription: String) -> DecodingError {
+ let context = DecodingError.Context(codingPath: container.codingPath,
+ debugDescription: debugDescription)
+ return .dataCorrupted(context)
+ }
}
//===----------------------------------------------------------------------===//
diff --git a/test/stdlib/TestJSONEncoder.swift b/test/stdlib/TestJSONEncoder.swift
index f6218a6..9362421 100644
--- a/test/stdlib/TestJSONEncoder.swift
+++ b/test/stdlib/TestJSONEncoder.swift
@@ -134,7 +134,7 @@
// MARK: - Date Strategy Tests
func testEncodingDate() {
- // We can't encode a top-level Date, so it'll be wrapped in an array.
+ // We can't encode a top-level Date, so it'll be wrapped in a dictionary.
_testRoundTrip(of: TopLevelWrapper(Date()))
}
@@ -143,7 +143,7 @@
let seconds = 1000.0
let expectedJSON = "{\"value\":1000}".data(using: .utf8)!
- // We can't encode a top-level Date, so it'll be wrapped in an array.
+ // We can't encode a top-level Date, so it'll be wrapped in a dictionary.
_testRoundTrip(of: TopLevelWrapper(Date(timeIntervalSince1970: seconds)),
expectedJSON: expectedJSON,
dateEncodingStrategy: .secondsSince1970,
@@ -155,7 +155,7 @@
let seconds = 1000.0
let expectedJSON = "{\"value\":1000000}".data(using: .utf8)!
- // We can't encode a top-level Date, so it'll be wrapped in an array.
+ // We can't encode a top-level Date, so it'll be wrapped in a dictionary.
_testRoundTrip(of: TopLevelWrapper(Date(timeIntervalSince1970: seconds)),
expectedJSON: expectedJSON,
dateEncodingStrategy: .millisecondsSince1970,
@@ -170,7 +170,7 @@
let timestamp = Date(timeIntervalSince1970: 1000)
let expectedJSON = "{\"value\":\"\(formatter.string(from: timestamp))\"}".data(using: .utf8)!
- // We can't encode a top-level Date, so it'll be wrapped in an array.
+ // We can't encode a top-level Date, so it'll be wrapped in a dictionary.
_testRoundTrip(of: TopLevelWrapper(timestamp),
expectedJSON: expectedJSON,
dateEncodingStrategy: .iso8601,
@@ -186,7 +186,7 @@
let timestamp = Date(timeIntervalSince1970: 1000)
let expectedJSON = "{\"value\":\"\(formatter.string(from: timestamp))\"}".data(using: .utf8)!
- // We can't encode a top-level Date, so it'll be wrapped in an array.
+ // We can't encode a top-level Date, so it'll be wrapped in a dictionary.
_testRoundTrip(of: TopLevelWrapper(timestamp),
expectedJSON: expectedJSON,
dateEncodingStrategy: .formatted(formatter),
@@ -203,7 +203,7 @@
}
let decode = { (_: Decoder) throws -> Date in return timestamp }
- // We can't encode a top-level Date, so it'll be wrapped in an array.
+ // We can't encode a top-level Date, so it'll be wrapped in a dictionary.
let expectedJSON = "{\"value\":42}".data(using: .utf8)!
_testRoundTrip(of: TopLevelWrapper(timestamp),
expectedJSON: expectedJSON,
@@ -218,7 +218,7 @@
let encode = { (_: Date, _: Encoder) throws -> Void in }
let decode = { (_: Decoder) throws -> Date in return timestamp }
- // We can't encode a top-level Date, so it'll be wrapped in an array.
+ // We can't encode a top-level Date, so it'll be wrapped in a dictionary.
let expectedJSON = "{\"value\":{}}".data(using: .utf8)!
_testRoundTrip(of: TopLevelWrapper(timestamp),
expectedJSON: expectedJSON,
@@ -227,10 +227,21 @@
}
// MARK: - Data Strategy Tests
+ func testEncodingData() {
+ let data = Data(bytes: [0xDE, 0xAD, 0xBE, 0xEF])
+
+ // We can't encode a top-level Data, so it'll be wrapped in a dictionary.
+ let expectedJSON = "{\"value\":[222,173,190,239]}".data(using: .utf8)!
+ _testRoundTrip(of: TopLevelWrapper(data),
+ expectedJSON: expectedJSON,
+ dataEncodingStrategy: .deferredToData,
+ dataDecodingStrategy: .deferredToData)
+ }
+
func testEncodingBase64Data() {
let data = Data(bytes: [0xDE, 0xAD, 0xBE, 0xEF])
- // We can't encode a top-level Data, so it'll be wrapped in an array.
+ // We can't encode a top-level Data, so it'll be wrapped in a dictionary.
let expectedJSON = "{\"value\":\"3q2+7w==\"}".data(using: .utf8)!
_testRoundTrip(of: TopLevelWrapper(data), expectedJSON: expectedJSON)
}
@@ -243,7 +254,7 @@
}
let decode = { (_: Decoder) throws -> Data in return Data() }
- // We can't encode a top-level Data, so it'll be wrapped in an array.
+ // We can't encode a top-level Data, so it'll be wrapped in a dictionary.
let expectedJSON = "{\"value\":42}".data(using: .utf8)!
_testRoundTrip(of: TopLevelWrapper(Data()),
expectedJSON: expectedJSON,
@@ -256,7 +267,7 @@
let encode = { (_: Data, _: Encoder) throws -> Void in }
let decode = { (_: Decoder) throws -> Data in return Data() }
- // We can't encode a top-level Data, so it'll be wrapped in an array.
+ // We can't encode a top-level Data, so it'll be wrapped in a dictionary.
let expectedJSON = "{\"value\":{}}".data(using: .utf8)!
_testRoundTrip(of: TopLevelWrapper(Data()),
expectedJSON: expectedJSON,
@@ -363,8 +374,8 @@
outputFormatting: JSONEncoder.OutputFormatting = [],
dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .deferredToDate,
dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate,
- dataEncodingStrategy: JSONEncoder.DataEncodingStrategy = .base64Encode,
- dataDecodingStrategy: JSONDecoder.DataDecodingStrategy = .base64Decode,
+ dataEncodingStrategy: JSONEncoder.DataEncodingStrategy = .base64,
+ dataDecodingStrategy: JSONDecoder.DataDecodingStrategy = .base64,
nonConformingFloatEncodingStrategy: JSONEncoder.NonConformingFloatEncodingStrategy = .throw,
nonConformingFloatDecodingStrategy: JSONDecoder.NonConformingFloatDecodingStrategy = .throw) where T : Codable, T : Equatable {
var payload: Data! = nil
@@ -919,6 +930,7 @@
JSONEncoderTests.test("testEncodingDateFormatted") { TestJSONEncoder().testEncodingDateFormatted() }
JSONEncoderTests.test("testEncodingDateCustom") { TestJSONEncoder().testEncodingDateCustom() }
JSONEncoderTests.test("testEncodingDateCustomEmpty") { TestJSONEncoder().testEncodingDateCustomEmpty() }
+JSONEncoderTests.test("testEncodingData") { TestJSONEncoder().testEncodingData() }
JSONEncoderTests.test("testEncodingBase64Data") { TestJSONEncoder().testEncodingBase64Data() }
JSONEncoderTests.test("testEncodingCustomData") { TestJSONEncoder().testEncodingCustomData() }
JSONEncoderTests.test("testEncodingCustomDataEmpty") { TestJSONEncoder().testEncodingCustomDataEmpty() }
diff --git a/test/stmt/nonexhaustive_switch_stmt_editor.swift b/test/stmt/nonexhaustive_switch_stmt_editor.swift
new file mode 100644
index 0000000..ee5d862
--- /dev/null
+++ b/test/stmt/nonexhaustive_switch_stmt_editor.swift
@@ -0,0 +1,29 @@
+// RUN: %target-typecheck-verify-swift -diagnostics-editor-mode
+
+typealias TimeInterval = Double
+
+let NSEC_PER_USEC : UInt64 = 1000
+let NSEC_PER_SEC : UInt64 = 1000000000
+
+public enum TemporalProxy {
+ case seconds(Int)
+ case milliseconds(Int)
+ case microseconds(Int)
+ case nanoseconds(Int)
+ @_downgrade_exhaustivity_check
+ case never
+}
+
+func unproxify(t : TemporalProxy) -> TimeInterval {
+ switch t { // expected-warning {{switch must be exhaustive}}
+ // expected-note@-1 {{do you want to add missing cases?}}
+ case let .seconds(s):
+ return TimeInterval(s)
+ case let .milliseconds(ms):
+ return TimeInterval(TimeInterval(ms) / 1000.0)
+ case let .microseconds(us):
+ return TimeInterval( UInt64(us) * NSEC_PER_USEC ) / TimeInterval(NSEC_PER_SEC)
+ case let .nanoseconds(ns):
+ return TimeInterval(ns) / TimeInterval(NSEC_PER_SEC)
+ }
+}