Skip to content

Make AnyType Sendable#788

Merged
KVSRoyal merged 5 commits into
player-1-dot-zerofrom
jj-intuit-clone
Feb 5, 2026
Merged

Make AnyType Sendable#788
KVSRoyal merged 5 commits into
player-1-dot-zerofrom
jj-intuit-clone

Conversation

@KVSRoyal
Copy link
Copy Markdown
Member

@KVSRoyal KVSRoyal commented Jan 29, 2026

Note

Contribution originally by @JJ-Intuit
This is a clone of #782 that is a direct branch of player, rather than a fork. Forks don't run on CI/CD properly.

What

This PR makes the AnyType enum conform to the Sendable protocol by removing all Any-based APIs and using only recursive AnyType values. This enables safe usage across Swift concurrency boundaries but introduces breaking changes for code that relied on Any interoperability.

See "Release Notes" for full description. (Moved there to avoid redundancy.)

Why

With Swift 6's strict concurrency checking, AnyType needed to be Sendable to be used safely in concurrent contexts.

Change Type (required)

Indicate the type of change your pull request is:

  • patch
  • minor
  • major
  • N/A; going into Player 1.0

Does your PR have any documentation updates?

  • Updated docs
  • No Update needed
  • Unable to update docs

Release Notes

Breaking Change: .anyArray and .anyDictionary use AnyType

The AnyType enum now conforms to Sendable protocol and is concurrency-safe. This required removing all APIs that depended on the Any type:

// Before
case anyDictionary(data: [String: Any])
case anyArray(data: [Any])

// After  
case anyDictionary(data: [String: AnyType])
case anyArray(data: [AnyType])

Migration

Use AnyType cases directly instead of converting from/to Any:

// Old (removed)
let anyType = AnyType.anyDictionary(data: ["key": "value"])
let anyArray = AnyType.anyArray(data: ["key", 2])

// New (Sendable-safe)  
let anyType = AnyType.anyDictionary(data: ["key": .string(data: "value")])
let anyArray = AnyType.anyArray(data: [.string(data: "key"), .number(data: 2)])

Breaking Change: AnyType will only decode .unknownData with AnyTypeDecodingContext

Users are required to provide AnyTypeDecodingContext when attempting to decode anyArray or anyDictionary. The decoder will throw if we need the context but one is not provided. As a side effect of this, .unknownData will only be returned when a context is provided. For example:

// Before, decoding data = "null"
let anyType = try? JSONDecoder() // no context
    .decode(AnyType.self, from: data) // This will return .unknownData

// After, decoding data = "null"
let anyType = try? JSONDecoder() // no context
    .decode(AnyType.self, from: data) // This will throw an error

let anyType = try? AnyTypeDecodingContext(rawData: data) // with context
            .inject(to: JSONDecoder())
            .decode(AnyType.self, from: data) // This will return .unknownData

Breaking Change: AnyTypeDecodingContext.objectFor is no longer public.

All decoding of AnyType is now handled internally. So AnyTypeDecodingContext.objectFor(path: [CodingKey]) throws -> Any is no longer exposed to users.

New Features

Added as<T>(_:) convenience method and AnyType (anyDictionary) subscripting for type-safe value extraction:

// Before
if case let .anyDictionary(myDict) = anyType,
    let title = myDict["title"] as? String {
    // Do a thing
}

// After
let title: String? = anyType["title"]?.as(String.self)

@KVSRoyal KVSRoyal changed the base branch from main to player-1-dot-zero January 29, 2026 04:16
@KVSRoyal KVSRoyal closed this Jan 29, 2026
@KVSRoyal KVSRoyal reopened this Jan 29, 2026
@KVSRoyal KVSRoyal changed the title Clone of #782; Make AnyType Sendable with Reflection support Make AnyType Sendable Feb 4, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 4, 2026

Codecov Report

❌ Patch coverage is 88.50932% with 37 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.89%. Comparing base (ec0701d) to head (2076241).
⚠️ Report is 2 commits behind head on player-1-dot-zero.

Files with missing lines Patch % Lines
ios/core/Sources/Types/Generic/AnyType.swift 80.90% 21 Missing ⚠️
ios/core/Tests/Types/Generic/AnyTypeTests.swift 93.00% 14 Missing ⚠️
plugins/pubsub/ios/Tests/PubSubPluginTests.swift 77.77% 2 Missing ⚠️
Additional details and impacted files
@@                  Coverage Diff                  @@
##           player-1-dot-zero     #788      +/-   ##
=====================================================
- Coverage              85.90%   85.89%   -0.01%     
=====================================================
  Files                    507      507              
  Lines                  22891    23104     +213     
  Branches                2656     2656              
=====================================================
+ Hits                   19664    19845     +181     
- Misses                  2898     2930      +32     
  Partials                 329      329              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread ios/core/Sources/Types/Generic/AnyType.swift
@KVSRoyal KVSRoyal marked this pull request as ready for review February 5, 2026 20:40
@KVSRoyal KVSRoyal requested a review from a team as a code owner February 5, 2026 20:40
@KVSRoyal KVSRoyal merged commit 61ad5e4 into player-1-dot-zero Feb 5, 2026
15 checks passed
@KVSRoyal KVSRoyal deleted the jj-intuit-clone branch February 5, 2026 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants