-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Fix JSONDecoder
superDecoder darwin/linux discrepancy
#3167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great fix! Thank you so much! @millenomi how can we get this into 5.7 and a 5.6 patch release?
@swift-ci please test |
a95dff8
to
7a5612d
Compare
@swift-ci please test |
@adam-fowler this would be nice to get into 5.6.3: https://forums.swift.org/t/development-open-for-swift-5-6-3-for-linux-and-windows/58859 Can we get CI green so its mergable? |
Ok had a closer look at this. It isn't the workaround that is causing the issue. It is the initialisation of a SourceKit-LSP type The null decoder current wraps a @fabianfett, @ahoppen what are your thoughts. |
Looking at the issue you describe, I think that a |
IMO func testSuperDecoder() {
struct OuterType : Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
_ = try InnerType(from: container.superDecoder(forKey: .superDecoder))
}
private enum CodingKeys: String, CodingKey {
case superDecoder = "super"
}
}
struct InnerType : Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self) <----------
_ = try container.decode(Bool.self, forKey: .whatever)
}
private enum CodingKeys : String, CodingKey {
case whatever
}
}
let decoder = JSONDecoder()
do {
let _ = try decoder.decode(OuterType.self, from: Data("{}".utf8))
} catch {
print("Caught error: \(error)")
}
} If you run this test on Darwin you'll get
This means the error is actually thrown on the line marked with The @usableFromInline func container<Key>(keyedBy _: Key.Type) throws ->
KeyedDecodingContainer<Key> where Key: CodingKey
{
guard case .object(let dictionary) = self.json else {
throw DecodingError.typeMismatch([String: JSONValue].self, DecodingError.Context(
codingPath: self.codingPath,
debugDescription: "Expected to decode \([String: JSONValue].self) but found \(self.json.debugDataTypeDescription) instead."
))
}
let container = KeyedContainer<Key>(
impl: self,
codingPath: codingPath,
dictionary: dictionary
)
return KeyedDecodingContainer(container)
} In our test case, |
To be clear, I don’t have a strong preference either way. I just think that if we have a new divergence between the Darwin and Linux implementation, we should decide which implementation we consider correct. |
@adam-fowler @ahoppen @iCharlesHu what is the next step here? If its actionable, would be nice to get into 5.7 |
I think we need some opinion from corelibs-foundation maintainers to make a decision whether we want to throw |
When trying to created a keyed container or unkeyed containter from a null value throw a `DecodingError.valueNotFound` error instead of a `typeMismatch` error. This is more inline with Darwin.
I misread the comment from @iCharlesHu previously. I have now added code to throw |
@tomerd the CI for this change has been running for 10 days. Can you find out why. |
cc @shahmishal @swift-ci please test |
I think this is ready to merge now |
@parkera please review / merge |
thanks @adam-fowler, do you want to also bring into 5.7 branch for the next patch release? |
* Don't throw DecodingError if superDecoder doesn't exist * Add decoderForKeyNoThrow * Improve JSONDecoder error handling When trying to created a keyed container or unkeyed containter from a null value throw a `DecodingError.valueNotFound` error instead of a `typeMismatch` error. This is more inline with Darwin.
* Don't throw DecodingError if superDecoder doesn't exist * Add decoderForKeyNoThrow * Improve JSONDecoder error handling When trying to created a keyed container or unkeyed containter from a null value throw a `DecodingError.valueNotFound` error instead of a `typeMismatch` error. This is more inline with Darwin.
On Darwin when you call
superDecoder
on theJSONDecoder
keyed container and there is no associated value for the key passed in, it returns a new decoder that returns empty containers. On Linux it would throw aDecodingError.keyNotFound
error.This PR resolves this discrepancy by catching the
DecodingError.keyNotFound
error and returning a decoder that references aJSONValue.null
.The PR also adds a new test
test_notFoundSuperDecoder
to verify this fix.This resolves #3169
cc: @fabianfett