Skip to content

Commit a5887b7

Browse files
committed
JSONSerialization: Improve number parsing for JSON
- Add _JSONNumber and _NSJSONNumber, an internal subclass of NSNumber, to provide lazy parsing of numbers at time of use. This avoids parsing numbers as Decimal when later bridged to Double/Float and vice-versa which has accuracy issues if converted from one to the other. - Add test cases for SR-7054 and SR-12244
1 parent 99d6439 commit a5887b7

13 files changed

+1180
-196
lines changed

Foundation.xcodeproj/project.pbxproj

+17-1
Original file line numberDiff line numberDiff line change
@@ -398,11 +398,15 @@
398398
B910957B1EEF237800A71930 /* NSString-UTF16-BE-data.txt in Resources */ = {isa = PBXBuildFile; fileRef = B91095791EEF237800A71930 /* NSString-UTF16-BE-data.txt */; };
399399
B91161AA2429860900BD2907 /* DataURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B91161A82429857D00BD2907 /* DataURLProtocol.swift */; };
400400
B91161AD242A363900BD2907 /* TestDataURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B91161AB242A350D00BD2907 /* TestDataURLProtocol.swift */; };
401+
B9292465258E75DD00E24DA5 /* JSONNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9292464258E75DD00E24DA5 /* JSONNumber.swift */; };
402+
B929246F258E772B00E24DA5 /* CMakeLists.txt in Resources */ = {isa = PBXBuildFile; fileRef = B929246E258E772B00E24DA5 /* CMakeLists.txt */; };
401403
B933A79E1F3055F700FE6846 /* NSString-UTF32-BE-data.txt in Resources */ = {isa = PBXBuildFile; fileRef = B933A79C1F3055F600FE6846 /* NSString-UTF32-BE-data.txt */; };
402404
B933A79F1F3055F700FE6846 /* NSString-UTF32-LE-data.txt in Resources */ = {isa = PBXBuildFile; fileRef = B933A79D1F3055F600FE6846 /* NSString-UTF32-LE-data.txt */; };
403405
B940492D223B146800FB4384 /* TestProgressFraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B940492C223B146800FB4384 /* TestProgressFraction.swift */; };
404406
B94B063C23FDE2BD00B244E8 /* SwiftFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5D885D1BBC938800234F36 /* SwiftFoundation.framework */; };
405407
B951B5EC1F4E2A2000D8B332 /* TestNSLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B951B5EB1F4E2A2000D8B332 /* TestNSLock.swift */; };
408+
B959016E25970BE300CACAE3 /* TestJSONNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = B959016D25970BE300CACAE3 /* TestJSONNumber.swift */; };
409+
B95901922597102000CACAE3 /* CMakeLists.txt in Resources */ = {isa = PBXBuildFile; fileRef = B95901912597102000CACAE3 /* CMakeLists.txt */; };
406410
B95FC97622B84B0A005DEA0A /* TestNSSortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 152EF3932283457B001E1269 /* TestNSSortDescriptor.swift */; };
407411
B96C10F625BA1EFD00985A32 /* NSURLComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = B96C10F525BA1EFD00985A32 /* NSURLComponents.swift */; };
408412
B96C110025BA20A600985A32 /* NSURLQueryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B96C10FF25BA20A600985A32 /* NSURLQueryItem.swift */; };
@@ -1109,10 +1113,14 @@
11091113
B91095791EEF237800A71930 /* NSString-UTF16-BE-data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "NSString-UTF16-BE-data.txt"; sourceTree = "<group>"; };
11101114
B91161A82429857D00BD2907 /* DataURLProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataURLProtocol.swift; sourceTree = "<group>"; };
11111115
B91161AB242A350D00BD2907 /* TestDataURLProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDataURLProtocol.swift; sourceTree = "<group>"; };
1116+
B9292464258E75DD00E24DA5 /* JSONNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONNumber.swift; sourceTree = "<group>"; };
1117+
B929246E258E772B00E24DA5 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
11121118
B933A79C1F3055F600FE6846 /* NSString-UTF32-BE-data.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "NSString-UTF32-BE-data.txt"; sourceTree = "<group>"; };
11131119
B933A79D1F3055F600FE6846 /* NSString-UTF32-LE-data.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "NSString-UTF32-LE-data.txt"; sourceTree = "<group>"; };
11141120
B940492C223B146800FB4384 /* TestProgressFraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestProgressFraction.swift; sourceTree = "<group>"; };
11151121
B951B5EB1F4E2A2000D8B332 /* TestNSLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestNSLock.swift; sourceTree = "<group>"; };
1122+
B959016D25970BE300CACAE3 /* TestJSONNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestJSONNumber.swift; sourceTree = "<group>"; };
1123+
B95901912597102000CACAE3 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
11161124
B95FC97222AF0050005DEA0A /* SwiftXCTest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SwiftXCTest.framework; sourceTree = BUILT_PRODUCTS_DIR; };
11171125
B95FC97422AF051B005DEA0A /* xcode-build.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "xcode-build.sh"; sourceTree = "<group>"; };
11181126
B96C10F525BA1EFD00985A32 /* NSURLComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSURLComponents.swift; sourceTree = "<group>"; };
@@ -1777,6 +1785,7 @@
17771785
F023071023F0976B0023DBEC /* Foundation */ = {
17781786
isa = PBXGroup;
17791787
children = (
1788+
B95901912597102000CACAE3 /* CMakeLists.txt */,
17801789
155D3BBB22401D1100B0D38E /* FixtureValues.swift */,
17811790
616068F2225DE5C2004FCC54 /* FTPServer.swift */,
17821791
1520469A1D8AEABE00D02E36 /* HTTPServer.swift */,
@@ -1819,6 +1828,7 @@
18191828
EA66F63E1BF1619600136161 /* TestIndexSet.swift */,
18201829
63DCE9D31EAA432400E9CB02 /* TestISO8601DateFormatter.swift */,
18211830
3EA9D66F1EF0532D00B362D6 /* TestJSONEncoder.swift */,
1831+
B959016D25970BE300CACAE3 /* TestJSONNumber.swift */,
18221832
5EB6A15C1C188FC40037DCB8 /* TestJSONSerialization.swift */,
18231833
BD8042151E09857800487EB8 /* TestLengthFormatter.swift */,
18241834
A058C2011E529CF100B07AA1 /* TestMassFormatter.swift */,
@@ -2042,6 +2052,7 @@
20422052
F023072323F0A6E50023DBEC /* Foundation */ = {
20432053
isa = PBXGroup;
20442054
children = (
2055+
B929246E258E772B00E24DA5 /* CMakeLists.txt */,
20452056
F023072523F0B4890023DBEC /* Headers */,
20462057
F023072423F0B4140023DBEC /* Resources */,
20472058
EADE0B4D1BD09E0800C49C64 /* AffineTransform.swift */,
@@ -2081,6 +2092,7 @@
20812092
5B8BA1611D0B773A00938C27 /* IndexSet.swift */,
20822093
63DCE9D11EAA430100E9CB02 /* ISO8601DateFormatter.swift */,
20832094
3EDCE5091EF04D8100C2EC04 /* JSONEncoder.swift */,
2095+
B9292464258E75DD00E24DA5 /* JSONNumber.swift */,
20842096
EADE0B641BD15DFF00C49C64 /* JSONSerialization.swift */,
20852097
49D55FA025E84FE5007BD3B3 /* JSONSerialization+Parser.swift */,
20862098
EADE0B661BD15DFF00C49C64 /* LengthFormatter.swift */,
@@ -2100,6 +2112,7 @@
21002112
5BDC3FCD1BCF17D300ED97BB /* NSCFDictionary.swift */,
21012113
5BDC3FCF1BCF17E600ED97BB /* NSCFSet.swift */,
21022114
5BDC3FCB1BCF177E00ED97BB /* NSCFString.swift */,
2115+
15CA750924F8336A007DF6C1 /* NSCFTypeShims.swift */,
21032116
5BDC3F311BCC5DCB00ED97BB /* NSCharacterSet.swift */,
21042117
5BDC3F321BCC5DCB00ED97BB /* NSCoder.swift */,
21052118
EADE0B551BD15DFF00C49C64 /* NSComparisonPredicate.swift */,
@@ -2122,7 +2135,6 @@
21222135
D3BCEB9F1C2F6DDB00295652 /* NSKeyedCoderOldStyleArray.swift */,
21232136
D39A14001C2D6E0A00295652 /* NSKeyedUnarchiver.swift */,
21242137
5BDC3F3B1BCC5DCB00ED97BB /* NSLocale.swift */,
2125-
15CA750924F8336A007DF6C1 /* NSCFTypeShims.swift */,
21262138
5BDC3F3C1BCC5DCB00ED97BB /* NSLock.swift */,
21272139
D3BCEB9D1C2EDED800295652 /* NSLog.swift */,
21282140
5BECBA391D1CAE9A00B39B1F /* NSMeasurement.swift */,
@@ -2713,6 +2725,7 @@
27132725
isa = PBXResourcesBuildPhase;
27142726
buildActionMask = 2147483647;
27152727
files = (
2728+
B929246F258E772B00E24DA5 /* CMakeLists.txt in Resources */,
27162729
F023072623F0B4890023DBEC /* Headers in Resources */,
27172730
B983E32C23F0C69600D9C402 /* Docs in Resources */,
27182731
B983E32E23F0C6E200D9C402 /* CONTRIBUTING.md in Resources */,
@@ -2743,6 +2756,7 @@
27432756
D3A597F71C3415CC00295652 /* NSKeyedUnarchiver-ArrayTest.plist in Resources */,
27442757
CE19A88C1C23AA2300B4CB6A /* NSStringTestData.txt in Resources */,
27452758
E1A03F361C4828650023AF4D /* PropertyList-1.0.dtd in Resources */,
2759+
B95901922597102000CACAE3 /* CMakeLists.txt in Resources */,
27462760
E1A3726F1C31EBFB0023AF4D /* NSXMLDocumentTestData.xml in Resources */,
27472761
E1A03F381C482C730023AF4D /* NSXMLDTDTestData.xml in Resources */,
27482762
D3A598041C349E6A00295652 /* NSKeyedUnarchiver-OrderedSetTest.plist in Resources */,
@@ -2888,6 +2902,7 @@
28882902
5BF7AEC01BCD51F9008F214A /* NSUUID.swift in Sources */,
28892903
5BF7AEB01BCD51F9008F214A /* NSLocale.swift in Sources */,
28902904
EADE0BA31BD15E0000C49C64 /* NSKeyedArchiver.swift in Sources */,
2905+
B9292465258E75DD00E24DA5 /* JSONNumber.swift in Sources */,
28912906
5BF7AEAD1BCD51F9008F214A /* NSError.swift in Sources */,
28922907
EADE0BB61BD15E0000C49C64 /* NSSortDescriptor.swift in Sources */,
28932908
5BF7AEA41BCD51F9008F214A /* Bundle.swift in Sources */,
@@ -3104,6 +3119,7 @@
31043119
90E645DF1E4C89A400D0D47C /* TestNSCache.swift in Sources */,
31053120
5B13B34A1C582D4C00651CE2 /* TestURL.swift in Sources */,
31063121
EA54A6FB1DB16D53009E0809 /* TestObjCRuntime.swift in Sources */,
3122+
B959016E25970BE300CACAE3 /* TestJSONNumber.swift in Sources */,
31073123
BB3D7558208A1E500085CFDC /* Imports.swift in Sources */,
31083124
5B13B34D1C582D4C00651CE2 /* TestNSUUID.swift in Sources */,
31093125
15F10CDC218909BF00D88114 /* TestNSCalendar.swift in Sources */,

Sources/Foundation/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ add_library(Foundation
3636
IndexSet.swift
3737
ISO8601DateFormatter.swift
3838
JSONEncoder.swift
39+
JSONNumber.swift
3940
JSONSerialization.swift
4041
JSONSerialization+Parser.swift
4142
LengthFormatter.swift

Sources/Foundation/JSONEncoder.swift

+61-64
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ extension JSONEncoderImpl: _SpecialTreatmentEncoder {
459459
case let url as URL:
460460
return .string(url.absoluteString)
461461
case let decimal as Decimal:
462-
return .number(decimal.description)
462+
return .outputNumber(decimal.description)
463463
case let object as [String: Encodable]: // this emits a warning, but it works perfectly
464464
return try self.wrapObject(object, for: nil)
465465
case let date as Date:
@@ -507,7 +507,7 @@ extension _SpecialTreatmentEncoder {
507507
if string.hasSuffix(".0") {
508508
string.removeLast(2)
509509
}
510-
return .number(string)
510+
return .outputNumber(string)
511511
}
512512

513513
fileprivate func wrapEncodable<E: Encodable>(_ encodable: E, for additionalKey: CodingKey?) throws -> JSONValue? {
@@ -519,7 +519,7 @@ extension _SpecialTreatmentEncoder {
519519
case let url as URL:
520520
return .string(url.absoluteString)
521521
case let decimal as Decimal:
522-
return .number(decimal.description)
522+
return .outputNumber(decimal.description)
523523
case let object as [String: Encodable]:
524524
return try self.wrapObject(object, for: additionalKey)
525525
default:
@@ -537,10 +537,10 @@ extension _SpecialTreatmentEncoder {
537537
return encoder.value ?? .null
538538

539539
case .secondsSince1970:
540-
return .number(date.timeIntervalSince1970.description)
540+
return .outputNumber(date.timeIntervalSince1970.description)
541541

542542
case .millisecondsSince1970:
543-
return .number((date.timeIntervalSince1970 * 1000).description)
543+
return .outputNumber((date.timeIntervalSince1970 * 1000).description)
544544

545545
case .iso8601:
546546
if #available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
@@ -751,7 +751,7 @@ extension JSONKeyedEncodingContainer {
751751
}
752752

753753
@inline(__always) private mutating func encodeFixedWidthInteger<N: FixedWidthInteger>(_ value: N, key: CodingKey) throws {
754-
self.object.set(.number(value.description), for: key.stringValue)
754+
self.object.set(.outputNumber(value.description), for: key.stringValue)
755755
}
756756
}
757757

@@ -872,7 +872,7 @@ private struct JSONUnkeyedEncodingContainer: UnkeyedEncodingContainer, _SpecialT
872872

873873
extension JSONUnkeyedEncodingContainer {
874874
@inline(__always) private mutating func encodeFixedWidthInteger<N: FixedWidthInteger>(_ value: N) throws {
875-
self.array.append(.number(value.description))
875+
self.array.append(.outputNumber(value.description))
876876
}
877877

878878
@inline(__always) private mutating func encodeFloatingPoint<F: FloatingPoint & CustomStringConvertible>(_ float: F) throws {
@@ -971,7 +971,7 @@ private struct JSONSingleValueEncodingContainer: SingleValueEncodingContainer, _
971971
extension JSONSingleValueEncodingContainer {
972972
@inline(__always) private mutating func encodeFixedWidthInteger<N: FixedWidthInteger>(_ value: N) throws {
973973
self.preconditionCanEncodeNewValue()
974-
self.impl.singleValue = .number(value.description)
974+
self.impl.singleValue = .outputNumber(value.description)
975975
}
976976

977977
@inline(__always) private mutating func encodeFloatingPoint<F: FloatingPoint & CustomStringConvertible>(_ float: F) throws {
@@ -1011,7 +1011,9 @@ extension JSONValue {
10111011
bytes.append(contentsOf: [UInt8]._false)
10121012
case .string(let string):
10131013
self.encodeString(string, to: &bytes)
1014-
case .number(let string):
1014+
case .inputNumber(let jsonNumber):
1015+
bytes.append(contentsOf: jsonNumber.description.utf8)
1016+
case .outputNumber(let string):
10151017
bytes.append(contentsOf: string.utf8)
10161018
case .array(let array):
10171019
var iterator = array.makeIterator()
@@ -1070,7 +1072,9 @@ extension JSONValue {
10701072
bytes.append(contentsOf: [UInt8]._false)
10711073
case .string(let string):
10721074
self.encodeString(string, to: &bytes)
1073-
case .number(let string):
1075+
case .inputNumber(let jsonNumber):
1076+
bytes.append(contentsOf: jsonNumber.description.utf8)
1077+
case .outputNumber(let string):
10741078
bytes.append(contentsOf: string.utf8)
10751079
case .array(let array):
10761080
var iterator = array.makeIterator()
@@ -1529,14 +1533,14 @@ extension JSONDecoderImpl: Decoder {
15291533
}
15301534

15311535
private func unwrapDecimal() throws -> Decimal {
1532-
guard case .number(let numberString) = self.json else {
1536+
guard case .inputNumber(let jsonNumber) = self.json else {
15331537
throw DecodingError.typeMismatch(Decimal.self, DecodingError.Context(codingPath: self.codingPath, debugDescription: ""))
15341538
}
15351539

1536-
guard let decimal = Decimal(string: numberString) else {
1540+
guard let decimal = jsonNumber.exactlyDecimal else {
15371541
throw DecodingError.dataCorrupted(.init(
15381542
codingPath: self.codingPath,
1539-
debugDescription: "Parsed JSON number <\(numberString)> does not fit in \(Decimal.self)."))
1543+
debugDescription: "Parsed JSON number <\(jsonNumber)> does not fit in \(Decimal.self)."))
15401544
}
15411545

15421546
return decimal
@@ -1572,18 +1576,20 @@ extension JSONDecoderImpl: Decoder {
15721576
for additionalKey: CodingKey? = nil,
15731577
as type: T.Type) throws -> T
15741578
{
1575-
if case .number(let number) = value {
1576-
guard let floatingPoint = T(number) else {
1577-
var path = self.codingPath
1578-
if let additionalKey = additionalKey {
1579-
path.append(additionalKey)
1580-
}
1581-
throw DecodingError.dataCorrupted(.init(
1582-
codingPath: path,
1583-
debugDescription: "Parsed JSON number <\(number)> does not fit in \(T.self)."))
1579+
if case .inputNumber(let jsonNumber) = value {
1580+
if type == Double.self, let number = jsonNumber.exactlyDouble {
1581+
return number as! T
15841582
}
1585-
1586-
return floatingPoint
1583+
if type == Float.self, let number = jsonNumber.exactlyFloat {
1584+
return number as! T
1585+
}
1586+
var path = self.codingPath
1587+
if let additionalKey = additionalKey {
1588+
path.append(additionalKey)
1589+
}
1590+
throw DecodingError.dataCorrupted(.init(
1591+
codingPath: path,
1592+
debugDescription: "Parsed JSON number <\(jsonNumber)> does not fit in \(T.self)."))
15871593
}
15881594

15891595
if case .string(let string) = value,
@@ -1607,57 +1613,48 @@ extension JSONDecoderImpl: Decoder {
16071613
for additionalKey: CodingKey? = nil,
16081614
as type: T.Type) throws -> T
16091615
{
1610-
guard case .number(let number) = value else {
1616+
guard case .inputNumber(let jsonNumber) = value else {
16111617
throw self.createTypeMismatchError(type: T.self, for: additionalKey, value: value)
16121618
}
16131619

1614-
// this is the fast pass. Number directly convertible to Integer
1615-
if let integer = T(number) {
1616-
return integer
1620+
if type == UInt8.self, let number = jsonNumber.exactlyUInt8 {
1621+
return number as! T
16171622
}
1618-
1619-
// this is the really slow path... If the fast path has failed. For example for "34.0" as
1620-
// an integer, we try to go through NSNumber
1621-
if let nsNumber = NSNumber.fromJSONNumber(number) {
1622-
if type == UInt8.self, NSNumber(value: nsNumber.uint8Value) == nsNumber {
1623-
return nsNumber.uint8Value as! T
1624-
}
1625-
if type == Int8.self, NSNumber(value: nsNumber.int8Value) == nsNumber {
1626-
return nsNumber.uint8Value as! T
1627-
}
1628-
if type == UInt16.self, NSNumber(value: nsNumber.uint16Value) == nsNumber {
1629-
return nsNumber.uint16Value as! T
1630-
}
1631-
if type == Int16.self, NSNumber(value: nsNumber.int16Value) == nsNumber {
1632-
return nsNumber.uint16Value as! T
1633-
}
1634-
if type == UInt32.self, NSNumber(value: nsNumber.uint32Value) == nsNumber {
1635-
return nsNumber.uint32Value as! T
1636-
}
1637-
if type == Int32.self, NSNumber(value: nsNumber.int32Value) == nsNumber {
1638-
return nsNumber.uint32Value as! T
1639-
}
1640-
if type == UInt64.self, NSNumber(value: nsNumber.uint64Value) == nsNumber {
1641-
return nsNumber.uint64Value as! T
1642-
}
1643-
if type == Int64.self, NSNumber(value: nsNumber.int64Value) == nsNumber {
1644-
return nsNumber.uint64Value as! T
1645-
}
1646-
if type == UInt.self, NSNumber(value: nsNumber.uintValue) == nsNumber {
1647-
return nsNumber.uintValue as! T
1648-
}
1649-
if type == Int.self, NSNumber(value: nsNumber.uintValue) == nsNumber {
1650-
return nsNumber.intValue as! T
1651-
}
1623+
if type == Int8.self, let number = jsonNumber.exactlyInt8 {
1624+
return number as! T
16521625
}
1653-
1626+
if type == UInt16.self, let number = jsonNumber.exactlyUInt16 {
1627+
return number as! T
1628+
}
1629+
if type == Int16.self, let number = jsonNumber.exactlyInt16 {
1630+
return number as! T
1631+
}
1632+
if type == UInt32.self, let number = jsonNumber.exactlyUInt32 {
1633+
return number as! T
1634+
}
1635+
if type == Int32.self, let number = jsonNumber.exactlyInt32 {
1636+
return number as! T
1637+
}
1638+
if type == UInt64.self, let number = jsonNumber.exactlyUInt64 {
1639+
return number as! T
1640+
}
1641+
if type == Int64.self, let number = jsonNumber.exactlyInt64 {
1642+
return number as! T
1643+
}
1644+
if type == UInt.self, let number = jsonNumber.exactlyUInt {
1645+
return number as! T
1646+
}
1647+
if type == Int.self, let number = jsonNumber.exactlyInt {
1648+
return number as! T
1649+
}
1650+
16541651
var path = self.codingPath
16551652
if let additionalKey = additionalKey {
16561653
path.append(additionalKey)
16571654
}
16581655
throw DecodingError.dataCorrupted(.init(
16591656
codingPath: path,
1660-
debugDescription: "Parsed JSON number <\(number)> does not fit in \(T.self)."))
1657+
debugDescription: "Parsed JSON number <\(jsonNumber)> does not fit in \(T.self)."))
16611658
}
16621659

16631660
private func createTypeMismatchError(type: Any.Type, for additionalKey: CodingKey? = nil, value: JSONValue) -> DecodingError {

0 commit comments

Comments
 (0)