Skip to content
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

[SR-9599] CodingKeys are improperly generated for nested Decodable/Encodable objects #52046

Open
swift-ci opened this issue Jan 3, 2019 · 1 comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. Codable Area → standard library: `Codable` and co. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Jan 3, 2019

Previous ID SR-9599
Radar None
Original Reporter jonstaff (JIRA User)
Type Bug
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, Codable
Assignee None
Priority Medium

md5: 905f4d7055e6d21048c58a6d805c48d7

Issue Description:

Referencing the compiler-generated CodingKeys enum within the init of a nested Decodable or Encodable fails. For example:

struct Outer: Decodable {
  var a: Int

  struct Inner: Decodable {
    var b: Int

    init(from decoder: Decoder) throws {
      // CodingKeys should be Inner.CodingKeys, but is Outer.CodingKeys
      let container = try decoder.container(keyedBy: CodingKeys.self)
      b = try container.decode(Int.self, forKey: .b) // compiler error
    }
  }
}

However, this works perfectly fine for objects conforming to Codable:

struct Outer: Codable {
  var a: Int

  struct Inner: Codable {
    var b: Int

    init(from decoder: Decoder) throws {
      // CodingKeys is Inner.CodingKeys
      let container = try decoder.container(keyedBy: CodingKeys.self)
      b = try container.decode(Int.self, forKey: .b)
    }
  }
}

When an explicitly-defined CodingKeys enum is provided, everything works as expected:

struct Outer: Decodable {
  var a: Int

  struct Inner: Decodable {
    var b: Int

    private enum CodingKeys: CodingKey {
      case b
    }

    init(from decoder: Decoder) throws {
      // CodingKeys is Inner.CodingKeys
      let container = try decoder.container(keyedBy: CodingKeys.self)
      b = try container.decode(Int.self, forKey: .b) // works fine
    }
  }
} 

Possibly related to https://bugs.swift.org/browse/SR-5215

@belkadan
Copy link
Contributor

belkadan commented Jan 7, 2019

Hm. The way CodingKeys synthesis works is that it does a lookup first and only synthesizes a custom one if the look fails. In this case, that comes out to "lookup in Inner -> lookup in Outer -> synthesize in Outer" and we never get back to "synthesize in Inner". I think that means we should be doing a qualified lookup into the Self type, even though that's technically a breaking change.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. Codable Area → standard library: `Codable` and co. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

2 participants