Skip to content

Mark @ResourceWrapper-generated extensions and Definition types nonisolated - #22

Draft
NicoMulet wants to merge 1 commit into
mainfrom
nicolas.mulet/nonisolated-macro-conformances
Draft

Mark @ResourceWrapper-generated extensions and Definition types nonisolated#22
NicoMulet wants to merge 1 commit into
mainfrom
nicolas.mulet/nonisolated-macro-conformances

Conversation

@NicoMulet

@NicoMulet NicoMulet commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #19

TL;DR

Mark @ResourceWrapper's generated extensions and Definition/BodyDefinition types nonisolated so the macro output no longer depends on the consuming module's default actor-isolation setting.

Context

Xcode 26's "Approachable Concurrency" makes @MainActor the default isolation for any declaration that doesn't opt out explicitly. @ResourceWrapper generates several extension Person: ... conformances and a nested Definition struct without marking them nonisolated, so under that default they inherit @MainActor isolation. Since ResourceDefinition/ResourceDefinitionProviding are ordinary nonisolated protocols, this produces:

error: conformance of 'Person' to protocol 'ResourceDefinitionProviding' crosses into main actor-isolated code and can cause data races

Reported in #19, where the reporter found that adding nonisolated to their own model works around it. Resource models are plain data-transfer types encoded/decoded across concurrency domains, so they shouldn't be actor-isolated regardless of what isolation default the consuming module picked — the fix belongs in the macro.

Summary of Changes

  • @ResourceWrapper now emits nonisolated on all 5 generated extensions (ResourceDefinitionProviding, ResourceIdentifiable, ResourceLinkageProviding, Codable, and the body-factory extension).
  • The generated Definition and BodyDefinition struct declarations are also marked nonisolated, since nested type declarations are independent isolation-inference roots and don't inherit isolation from their enclosing (now-nonisolated) extension.
  • Attributes/Relationships are intentionally left unmarked: they hold mutable var stored properties, and nonisolated on a mutable stored property is a hard error in the Swift 6 language mode. They don't need it anyway — the compiler error was specifically about Definition's conformance, not these nested value types.
  • Updated the ResourceWrapperMacroTests expansion snapshots to match.

How to Test

Verified against the reporter's exact repro (Person with id/firstName/lastName/twitter) using swift build -Xswiftc -swift-version -Xswiftc 6 -Xswiftc -default-isolation -Xswiftc MainActor on a client target depending on this branch:

  • Before this change: fails with the reported "crosses into main actor-isolated code" error.
  • After this change: builds cleanly.

Also ran the full existing test suite (swift test), all green with no new warnings.

Demo

@ResourceWrapper(type: "people")
struct Person: Equatable {
    var id: String

    @ResourceAttribute var firstName: String
    @ResourceAttribute var lastName: String
    @ResourceAttribute var twitter: String?
}
// Compiles under `-default-isolation MainActor` (Xcode 26's Approachable
// Concurrency default) without needing to mark `Person` itself `nonisolated`.

…olated

Under Swift 6.2's default MainActor isolation ("Approachable Concurrency",
the default for new Xcode 26 projects), macro-generated extensions and
nested types inherit @mainactor isolation unless marked otherwise. This
made the generated `Definition`/`BodyDefinition` conformance to
`ResourceDefinition` main-actor isolated, which is incompatible with the
non-isolated `ResourceDefinitionProviding` protocol and fails to compile
with "conformance ... crosses into main actor-isolated code".

Mark the macro's generated extensions and the Definition/BodyDefinition
struct declarations `nonisolated` so the generated code no longer depends
on the consuming module's default-isolation setting. Attributes/
Relationships structs are left untouched since their mutable stored
properties can't be marked nonisolated.

Fixes #19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant