Skip to content

[BUG]: Swift 6 Strict Sendable conformance #2858

@kieran-osgood-shopify

Description

@kieran-osgood-shopify

Issue Type

TLDR; Quicktype is generating invalid Swift under the Swift 6 language compiler

Generated Swift helper classes (JSONCodingKey, JSONAny, JSONNull) don't compile under Swift 6 strict concurrency, even when --sendable is passed.

Context (Environment, Version, Language)

Input Format: JSON Schema (--src-lang schema)
Output Language: Swift

CLI, npm, or app.quicktype.io: CLI
Version: 23.2.6

Description

When generating Swift code with --sendable and --struct-or-class struct, the generated model structs correctly gain Sendable conformance. However, the helper classes at the bottom of the output (JSONNull, JSONCodingKey, JSONAny) are not updated for Swift 6 strict concurrency:

  1. JSONCodingKey is a non-final class — Swift 6 errors with non-final class 'JSONCodingKey' cannot conform to 'Sendable'
  2. JSONAny stores Any which is not Sendable — needs @unchecked Sendable and nonisolated(unsafe) (related: [FEATURE]: Swift - Sendable JSONAny #2598)
  3. JSONNull uses deprecated hashValue (minor, but warning noise)

This makes the output unusable with swift-tools-version: 6.0 packages out of the box.

Input Data

Any JSON Schema that produces additionalProperties / untyped fields triggers JSONAny usage. Minimal example:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Example",
  "type": "object",
  "properties": {
    "data": {
      "type": "object",
      "additionalProperties": true
    }
  }
}

Expected Behaviour / Output

When --sendable is passed, all generated types — including JSONCodingKey, JSONNull, and JSONAny — should compile cleanly under Swift 6 strict concurrency (swift-tools-version: 6.0).

Specifically:

  • JSONCodingKey should be final class JSONCodingKey: CodingKey, Sendable
  • JSONAny should be marked @unchecked Sendable (since it wraps Any)
  • JSONNull should use hash(into:) instead of deprecated hashValue

Current Behaviour / Output

error: non-final class 'JSONCodingKey' cannot conform to 'Sendable'; use '@unchecked Sendable'
warning: 'Hashable.hashValue' is deprecated as a protocol requirement; conform type 'JSONNull' to 'Hashable' by implementing 'hash(into:)' instead

The generated struct models are correctly Sendable, but the helper classes break the build.

Steps to Reproduce

  1. npm install -g quicktype
  2. Save the minimal JSON Schema above as example.json
  3. Run:
    quicktype \
      --lang swift \
      --src-lang schema \
      --src example.json \
      --access-level public \
      --struct-or-class struct \
      --coding-keys \
      --sendable \
      -o Models.swift
  4. Create a Swift package with swift-tools-version: 6.0 and try to build
 mkdir MyPackage && cd MyPackage
 swift package init --type library --name MyPackage
 sed -i '' 's/swift-tools-version: .*/swift-tools-version: 6.0/' Package.swift
 cp ../Models.swift Sources/MyPackage/Models.swift
 swift build

Possible Solution

I'm currently working around this by making the following changes with sed after generation:

  1. Emit final class JSONCodingKey: CodingKey, Sendable instead of class JSONCodingKey: CodingKey
  2. Emit public class JSONAny: Codable, @unchecked Sendable with nonisolated(unsafe) on the value property
  3. Replace public var hashValue: Int with public func hash(into hasher: inout Hasher) {} on JSONNull

For point 2 this is would be safer as an enum for future extensibility

public enum JSONValue: Codable, Sendable {
      case null
      case bool(Bool)
      case int(Int64)
      case double(Double)
      case string(String)
      case array([JSONValue])
      case object([String: JSONValue])
  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions