You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: proposals/NNNN-nonisolated-for-global-actor-cutoff.md
+66-56Lines changed: 66 additions & 56 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,7 +9,7 @@
9
9
10
10
## Introduction
11
11
12
-
This proposal allows annotating a set of declarations with `nonisolated` to prevent global actor inference.
12
+
This proposal allows annotating a set of declarations with `nonisolated` to prevent global actor inference. Additionally, it extends the existing rules for when `nonisolated` can be written on a stored property, improving usability.
13
13
14
14
## Motivation
15
15
@@ -78,7 +78,7 @@ protocol RemoveGlobalActor {}
78
78
protocolRefinedProtocol: GloballyIsolated, RemoveGlobalActor {} // 'RefinedProtocol' is non-isolated
79
79
```
80
80
81
-
In the above code, the programmer creates a new protocol that is isolated to an actor that nominally is isolated to the global actor. This means that the protocol declaration `RefinedProtocol` refining the `RemoveGlobalActor` protocol will result in a conflicting global actor isolation, one from `GloballyIsolated` that’s isolated to `@MainActor`, and another one from `RemoveGlobalActor` that’s isolated to the `@FakeGlobalActor`. This results in the overall declaration having no global actor isolation, while still refining the protocols it conformed to.
81
+
In the above code, the programmer creates a new protocol that is isolated to an actor that nominally is isolated to the global actor. This means that the protocol declaration `RefinedProtocol` refining the `RemoveGlobalActor` protocol will result in a conflicting global actor isolation, one from `GloballyIsolated` that’s isolated to `@MainActor`, and another one from `RemoveGlobalActor` that’s isolated to the `@FakeGlobalActor`. This results in the overall declaration having no global actor isolation, while still refining the protocols it conformed to.
And in the above code, the protocol `P` refines the `GloballyIsolated` protocol. Because `nonisolated` is applied to it, the global actor isolation coming from the `GloballyIsolated` protocol will not be inferred for protocol `P`.
99
99
100
+
In addition to the above, we propose extending existing rules for when `nonisolated` can be applied to stored properties to improve usability. More precisely, we propose `nonisolated` inference from within the module for mutable storage of `Sendable` value types, and annotating such storage with `nonisolated` to allow synchronous access from outside the module. Additionally, we propose explicit spelling of `nonisolated` for stored properties of non-`Sendable` types.
101
+
100
102
## Detailed design
101
103
102
104
Today, there are a number of places where `nonisolated` can be written, as proposed in [SE-0313: Improved control over actor isolation](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0313-actor-isolation-control.md#non-isolated-declarations):
103
105
104
106
* Functions
105
107
* Stored properties of classes that are `let` and `Sendable`
106
108
107
-
Additionally, under [SE-0434: Usability of global-actor-isolated types](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0434-global-actor-isolated-types-usability.md), `nonisolated` is allowed to be written on mutable `Sendable` storage of globally-isolated value types.
109
+
Additionally, under [SE-0434: Usability of global-actor-isolated types](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0434-global-actor-isolated-types-usability.md), `nonisolated` is allowed to be written on mutable `Sendable` storage of globally-isolated value types.
110
+
111
+
In this proposal, we expand the above rules by allowing annotating more declarations with `nonisolated`. The first batch of these rules is specifically targeting the global actor inference "cut-off", while the second focuses on usability improvements allowing `nonisolated` to be written on more kinds of storage.
108
112
109
-
In this proposal, we expand the above rules by allowing annotating the declarations listed below with `nonisolated`.
113
+
### Allowing `nonisolated` to prevent global actor inference
110
114
111
-
###1. Protocols
115
+
####Protocols
112
116
113
117
This proposal allows `nonisolated` attribute to be applied on protocol declarations:
114
118
@@ -125,7 +129,7 @@ struct A: Refined {
125
129
126
130
In the above code, the protocol `Refined` is refining the `GloballyIsolated` protocol, but is declared non-isolated. This means that the `Refined` still has the same requirements as `GloballyIsolated`, but they are not isolated. Therefore, a struct `A` conforming to it is also non-isolated, which allows the programmer for more flexibility when implementing the requirements of a protocol.
127
131
128
-
###2. Extensions
132
+
####Extensions
129
133
130
134
This proposal allows for `nonisolated` attribute to be applied on extension declarations:
131
135
@@ -145,56 +149,7 @@ struct C: GloballyIsolated {
145
149
146
150
In the code above, the `nonisolated` attribute is applied to an extension declaration for a `GloballyIsolated` protocol. When applied to an extension, `nonisolated` applies to all of its members. In this case, `implicitlyNonisolated` method and the computed property `x` are both nonisolated, and therefore are able to be accessed from a nonisolated context in the body of `explicitlyNonisolated` method of a globally-isolated struct `C`.
147
151
148
-
### 3. Stored properties of non-`Sendable` types
149
-
150
-
Currently, any stored property of a non-`Sendable` type is implicitly treated as non-isolated. This proposal allows for spelling of this behavior:
Because `MyClass` is does not conform to `Sendable`, the compiler guarantees mutually exclusive access to references of `MyClass` instance. `nonisolated` on methods and properties of non-`Sendable` types can be safely called from any isolation domain because the base instance can only be accessed by one isolation domain at a time.
159
-
160
-
### 4. Mutable `Sendable` storage of `Sendable` value types
161
-
162
-
For global-actor-isolated value types, [SE-0434: Usability of global-actor-isolated types](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0434-global-actor-isolated-types-usability.md) allows accessing `var` stored properties with `Sendable` type from within the module as `nonisolated`. This proposal extends this rule to **all**`Sendable` value types:
163
-
164
-
```swift
165
-
structS {
166
-
var x: Int=0// okay ('nonisolated' is inferred within the module)
167
-
}
168
-
169
-
actorMyActor {
170
-
functest(s: S) {
171
-
print(s.x) // synchronous access to 'x' after sending `S` to `MyActor` is okay.
172
-
}
173
-
}
174
-
```
175
-
176
-
In the above code, the value type `S` is implicitly `Sendable` within the module and its storage `x` is of `Sendable` type `Int`. When `Sendable` value types are passed between isolation domains, each isolation domain has an independent copy of the value. Accessing properties stored on a value type from across isolation domains is safe as long as the stored property type is also `Sendable`. Even if the stored property is a `var`, assigning to the property will not risk a data race, because the assignment cannot have effects on copies in other isolation domains. Therefore, synchronous access of `x` from within the module is okay.
177
-
178
-
Additionally, [SE-0434](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0434-global-actor-isolated-types-usability.md) allows explicitly annotating globally-isolated value types' properties such as `x` in the previous example with `nonisolated` for synchronous access from outside the module. This proposal extends this rule to **all**`Sendable` value types:
179
-
180
-
```swift
181
-
// In Module A
182
-
publicstructS: Sendable {
183
-
nonisolatedpublicvar x: Int=0// okay
184
-
publicinit() {}
185
-
}
186
-
187
-
// In Module B
188
-
importA
189
-
190
-
actorMyActor {
191
-
functest(s: S) {
192
-
print(s.x) // synchronous access to 'x' after sending `S` to `MyActor` is okay.
193
-
}
194
-
}
195
-
```
196
-
197
-
### 5. Classes, structs, and enums
152
+
#### Classes, structs, and enums
198
153
199
154
Finally, we propose allowing writing `nonisolated` on class, struct and enum declarations:
200
155
@@ -245,6 +200,61 @@ The above behavior is semantically consistent with the existing rules around glo
245
200
}
246
201
```
247
202
203
+
### Annotating more types of storage with `nonisolated`
204
+
205
+
This section extends the existing rules for when `nonisolated` can be written on a storage of a user-defined type.
206
+
207
+
#### Stored properties of non-`Sendable` types
208
+
209
+
Currently, any stored property of a non-`Sendable` type is implicitly treated as non-isolated. This proposal allows for spelling of this behavior:
Because `MyClass` does not conform to `Sendable`, it cannot be accessed from multiple isolation domains at once. Therefore, the compiler guarantees mutually exclusive access to references of `MyClass` instance. The `nonisolated` on methods and properties of non-`Sendable` types can be safely called from any isolation domain because the base instance can only be accessed by one isolation domain at a time. Importantly, `nonisolated` does not impact the number of isolation domains that can reference the `self` value. As long as there is a reference to `self` value in one isolation domain, the `nonisolated` method/property can be safely called from that domain.
218
+
219
+
#### Mutable `Sendable` storage of `Sendable` value types
220
+
221
+
For global-actor-isolated value types, [SE-0434: Usability of global-actor-isolated types](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0434-global-actor-isolated-types-usability.md) allows accessing `var` stored properties with `Sendable` type from within the module as `nonisolated`. This proposal extends this rule to **all**`Sendable` value types:
222
+
223
+
```swift
224
+
structS {
225
+
var x: Int=0// okay ('nonisolated' is inferred within the module)
226
+
}
227
+
228
+
actorMyActor {
229
+
functest(s: S) {
230
+
print(s.x) // synchronous access to 'x' after sending `S` to `MyActor` is okay.
231
+
}
232
+
}
233
+
```
234
+
235
+
In the above code, the value type `S` is implicitly `Sendable` within the module and its storage `x` is of `Sendable` type `Int`. When `Sendable` value types are passed between isolation domains, each isolation domain has an independent copy of the value. Accessing properties stored on a value type from across isolation domains is safe as long as the stored property type is also `Sendable`. Even if the stored property is a `var`, assigning to the property will not risk a data race, because the assignment cannot have effects on copies in other isolation domains. Therefore, synchronous access of `x` from within the module is okay.
236
+
237
+
Additionally, [SE-0434](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0434-global-actor-isolated-types-usability.md) allows explicitly annotating globally-isolated value types' properties such as `x` in the previous example with `nonisolated` for synchronous access from outside the module. This proposal extends this rule to **all**`Sendable` value types:
238
+
239
+
```swift
240
+
// In Module A
241
+
publicstructS: Sendable {
242
+
nonisolatedpublicvar x: Int=0// okay
243
+
publicinit() {}
244
+
}
245
+
```
246
+
247
+
```swift
248
+
// In Module B
249
+
importA
250
+
251
+
actorMyActor {
252
+
functest(s: S) {
253
+
print(s.x) // synchronous access to 'x' after sending `S` to `MyActor` is okay.
254
+
}
255
+
}
256
+
```
257
+
248
258
### Restrictions
249
259
250
260
Additionally, we propose the following set of rules for when the `nonisolated` attribute **cannot** be applied:
0 commit comments