Skip to content

Commit 2b01fe1

Browse files
DougGregorxwu
andauthored
[SE-0470] Infer nonisolated on conformances (#2893)
* [SE-0470] Infer `nonisolated` on conformances Introduce two inference rules that infer `nonisolated` when `InferIsolatedConformances` is enabled. These inference rules ensure that most conformances that should be nonisolated remain nonisolated, particular when we're in the main-actor-by-default mode. The end result is that much less code needs to change when enabling isolated conformance inference (including via main-actor-by-default mode). The two rules are: * If the protocol inherits from `SendableMetatype` (including indirectly, e.g., from `Sendable`), then the isolated conformance could never be used, so it is inferred to be `nonisolated`. * If all of the declarations used to satisfy protocol requirements are `nonisolated`, the conformance will be assumed to be `nonisolated`. * More justification for why this feature is needed, and a possible future removing it * Fix typo * Clarify that a nonisolated conformance might evolve to an isolated one * Update headers and revision history --------- Co-authored-by: Xiaodi Wu <[email protected]>
1 parent cf2a0fa commit 2b01fe1

File tree

1 file changed

+33
-7
lines changed

1 file changed

+33
-7
lines changed

proposals/0470-isolated-conformances.md

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
* Proposal: [SE-0470](0470-isolated-conformances.md)
44
* Authors: [Doug Gregor](https://github.com/DougGregor)
55
* Review Manager: [Xiaodi Wu](https://github.com/xwu)
6-
* Status: **Implemented (Swift 6.2)**
6+
* Status: **Active review (July 8...15, 2025)**
77
* Vision: [Improving the approachability of data-race safety](https://github.com/swiftlang/swift-evolution/blob/main/visions/approachable-concurrency.md)
88
* Implementation: On `main` with the experimental features `IsolatedConformances` and `StrictSendableMetatypes`.
99
* Upcoming Feature Flag: `InferIsolatedConformances`
10-
* Review: ([pitch](https://forums.swift.org/t/pre-pitch-isolated-conformances/77726)) ([review](https://forums.swift.org/t/se-0470-global-actor-isolated-conformances/78704)) ([acceptance](https://forums.swift.org/t/accepted-se-0470-global-actor-isolated-conformances/79189))
10+
* Review: ([pitch](https://forums.swift.org/t/pre-pitch-isolated-conformances/77726)) ([review](https://forums.swift.org/t/se-0470-global-actor-isolated-conformances/78704)) ([acceptance](https://forums.swift.org/t/accepted-se-0470-global-actor-isolated-conformances/79189)) ([amendment pitch](https://forums.swift.org/t/pitch-amend-se-0466-se-0470-to-improve-isolation-inference/79854))
1111

1212
## Introduction
1313

@@ -549,18 +549,21 @@ class MyModelType: /*inferred @MainActor*/ P {
549549
}
550550
```
551551

552-
If this inference is not desired, for example because the code will use `nonisolated` members to satisfy the requirements of the protocol, it can use `nonisolated` on the conformance:
552+
If this inference is not desired, one can use `nonisolated` on the conformances:
553553

554554
```swift
555555
@MainActor
556-
class MyModelType: nonisolated P {
557-
nonisolated func f() { } // implements P.f, is non-isolated
556+
class MyModelType: nonisolated Q {
557+
nonisolated static func g() { } // implements Q.g, is non-isolated
558558
}
559559
```
560560

561-
This mirrors the rules for global actor inference elsewhere in the language, providing a more consistent answer.
561+
There are two additional inference rules that imply `nonisolated` on a conformance of a global-actor-isolated type:
562562

563-
This proposed change is source-breaking, so it should be staged in via an upcoming feature (`InferIsolatedConformances`) that can be folded into a future language mode. Fortunately, it is mechanically migratable: existing code migrating to `InferIsolatedConformances` could introduce `nonisolated` for each conformance of a global-actor-isolated type.
563+
* If the protocol inherits from `SendableMetatype` (including indirectly, e.g., from `Sendable`), then the isolated conformance could never be used, so it is inferred to be `nonisolated`.
564+
* If all of the declarations used to satisfy protocol requirements are `nonisolated`, the conformance will be assumed to be `nonisolated`. The conformance of `MyModelType` to `Q` would be inferred to be `nonisolated` because the static method `g` used to satisfy `Q.g` is `nonisolated.`
565+
566+
This proposed change is source-breaking in the cases where a conformance is currently `nonisolated`, the rules above would not infer `nonisolated`, and the conformance crosses isolation domains. There, conformance isolation inference is staged in via an upcoming feature (`InferIsolatedConformances`) that can be folded into a future language mode. Fortunately, it is mechanically migratable: existing code migrating to `InferIsolatedConformances` could introduce `nonisolated` for each conformance of a global-actor-isolated type.
564567

565568
### Infer `@MainActor` conformances
566569

@@ -662,7 +665,30 @@ This is a generalization of the proposed rules that makes more explicit when con
662665

663666
The main down side of this alternative is the additional complexity it introduces into generic requirements. It should be possible to introduce this approach later if it proves to be necessary, by treating it as a generalization of the existing rules in this proposal.
664667

668+
### Require `nonisolated` rather than inferring it
669+
670+
Under the upcoming feature `InferIsolatedConformances`, this proposal infers `nonisolated` for conformances when all of the declarations that satisfy requirements of a protocol are themselves `nonisolated`. For example:
671+
672+
```swift
673+
nonisolated protocol Q {
674+
static func create() -> Self
675+
}
676+
677+
@MainActor struct MyType: /*infers nonisolated*/ Q {
678+
nonisolated static func create() -> MyType { ... }
679+
}
680+
```
681+
682+
This inference is important for providing source compatibility with and without `InferIsolatedConformances`, and is especially useful useful when combined with default main-actor isolation ([SE-0466](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0466-control-default-actor-isolation.md)), where many more types will become main-actor isolated. Experience with using these features together also identified some macros (such as [`@Observable`](https://developer.apple.com/documentation/observation/observable())) that produced `nonisolated` members for a protocol conformances, but had not yet been updated to mark the conformance as `nonisolated`. Macro-generated code is much harder for users to update when a source-compatibility issue arises, which makes `nonisolated` conformance inference particularly important for source compatibility.
683+
684+
However, this inference rule has downsides. It means one needs to examine a protocol and how a type conforms to that protocol to determine whether the conformance might be `nonisolated`, which can be a lot of work for the developer reading the code as well as the compiler. It can also change over time: for example, a default implementation of a protocol requirement will likely be `nonisolated`, but a user-written one within a main-actor-isolated type would be `@MainActor` and, therefore, make the conformance `@MainActor`.
685+
686+
One alternative would be to introduce this inference rule for source compatibility, but treat it as a temporary measure to be disabled again in some future language mode. Introducing the inference rule in this proposal does not foreclose on that possibility: if we find that the `nonisolated` conformance inference rule here is harmful to readability, a separate proposal can deprecate it in a future language mode, providing a suitable migration timeframe.
687+
665688
## Revision history
666689

690+
* Changes in amendment review:
691+
* If the protocol inherits from `SendableMetatype` (including indirectly, e.g., from `Sendable`), then the isolated conformance could never be used, so it is inferred to be `nonisolated`.
692+
* If all of the declarations used to satisfy protocol requirements are `nonisolated`, the conformance will be assumed to be `nonisolated`.
667693
* Changes in review:
668694
* Within a generic function, use sendability of metatypes of generic parameters as the basis for checking, rather than treating specific conformances as potentially isolated. This model is easier to reason about and fits better with `SendableMetatype`, and was used in earlier drafts of this proposal.

0 commit comments

Comments
 (0)