OpenAPITools / OpenAPITools/openapi-generator

[REQ][swift6] Option to mark generated declarations nonisolated for projects using default MainActor isolation

Open
#24,903 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Enhancement: Feature
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

Is your feature request related to a problem? Please describe.

Swift 6.2 lets a module opt into main-actor isolation by default (SE-0466, -default-isolation MainActor; in Xcode 26 the SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor build setting, which the new-project template enables). Under that setting, every top-level declaration without an explicit isolation is inferred @MainActor, including the public struct / public enum models the swift6 generator emits, their Codable conformances, and the extension blocks it writes for them. The generated models then cannot be used from any nonisolated context, which is where decoding normally happens (a URLSession completion, an actor-based API client, a background Task). The diagnostics take the form (Xcode 26, Swift 6.2):

conformance of 'Foo' to protocol 'Decodable' crosses into main actor-isolated code and can cause data races
main actor-isolated initializer 'init(from:)' cannot be used to satisfy nonisolated requirement from protocol 'Decodable'

Describe the solution you'd like

A swift6 generator option, for example nonisolatedModels (boolean), that when enabled emits:

  • public nonisolated struct Foo: Codable, … / public nonisolated enum Foo: String, … for every top-level model
  • nonisolated extension Foo: … for every conformance extension the generator writes (e.g. the CaseIterableDefaultsLast / UnknownCaseCheckable extensions produced under enumUnknownDefaultCase, and the oneOf enum wrappers)
  • the same on the Infrastructure/*.swift protocols and their default-implementation extensions, since a nonisolated type cannot satisfy a main-actor-isolated protocol requirement, nor take a main-actor default implementation as its witness

nonisolated extension requires Swift 6.2, so the option should probably be documented as requiring a Swift 6.2 toolchain, or emit per-member nonisolated when it is off.

Always emitting nonisolated (without the config option) would also be correct for these types, since it changes nothing for consumers on the default isolation.

Describe alternatives you've considered

  • additionalModelObjectAttributes: this hook inserts text on the model struct/enum line, but it does not reach the oneOf wrapper enums, inline property enums, or the conformance extension blocks, and it cannot touch the Infrastructure protocols. So a project cannot get a compiling result from it alone.
  • A textual post-pass over the generated files (what we do today): a regex rewriting ^public (struct|enum) and ^extension , plus a hand-written copy of the two Infrastructure protocols with nonisolated added. It works, but it is fragile against template changes.
  • Wrapping every use of a model in MainActor.run or making the API client @MainActor: pushes decoding onto the main thread, which incurs unnecessary runtime costs.

Additional context

This is the next step after #20057: that issue made the models Sendable so they can cross an actor boundary; default MainActor isolation additionally pins them to one unless they are declared nonisolated. The generated code is plain value types with no shared mutable state, so there is no reason for it to carry actor isolation. Marking the declarations nonisolated is the correct annotation regardless of the consumer's default-isolation setting, and it is a no-op for modules that keep the Swift 6.0/6.1 default (nonisolated).

Reproduction

Generate any spec with -g swift6 --global-property models, add the output to an app target with SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor and SWIFT_VERSION = 6, and decode a model from a nonisolated function:

nonisolated func decode(_ data: Data) throws -> Pet {
    try JSONDecoder().decode(Pet.self, from: data)   // error: main actor-isolated initializer 'init(from:)' …
}

Generator version: 7.25.0.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the swift6 generator entry point using -g swift6 --global-property models, then inspect the templates that emit model declarations, conformance extensions, and Infrastructure/*.swift protocols. Reproduce the issue with SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor and a nonisolated decode function; done means the option produces nonisolated models, extensions, protocols, and default implementations that compile under Swift 6.2.

Written by the indexing model from the issue text.

Assessment

Tech stack
openapi, swift
Domain
tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.