1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
|
# Sendable metatypes
Types that are shared in concurrent code generally need to conform to `Sendable`. The same is true in generic code when sharing parameters of a generic parameter `T`. For example, the given code will produce an error under strict concurrency checking
```swift
func doSomethingElsewhere<T>(_ value: T) {
Task { @concurrent in
print(value) // warning: capture of non-Sendable type 'T'
}
}
```
because `value` can have a non-Sendable type that is not safe to share. To address this potential data race, the type `T` can be marked as `Sendable`:
```swift
func doSomethingElsewhere<T: Sendable>(_ value: T) {
Task { @concurrent in
print(value)
}
}
```
The same issue can occur when passing the type `T` itself, rather than a value of type `T`. The compiler will indicate such problems by noting that the metatype of `T`, spelled `T.Type`, is not `Sendable`:
```swift
protocol P {
static func doSomething()
}
func doSomethingStatic<T: P>(_: T.Type) {
Task { @concurrent in
T.doSomething() // warning: capture of non-Sendable type 'T.Type' in an isolated closure
}
}
```
In these cases, the type parameter should be required to conform to the `SendableMetatype` protocol, e.g.,
```swift
func doSomethingStatic<T: P & SendableMetatype>(_: T.Type) {
Task { @concurrent in
T.doSomething()
}
}
```
The `SendableMetatype` requirement allows the function to share the type `T` in concurrent code. To maintain data race safety, it prevents callers from using isolated conformances in the call. For example, the following code will be rejected due to a data race:
```swift
@MainActor
class C: @MainActor P {
static func doSomething() { }
}
@MainActor
func test(c: C) {
doSomethingStatic(C.self) // error: main actor-isolated conformance of 'C' to 'P' cannot satisfy conformance requirement for a 'Sendable' type parameter
}
```
The conformance of `C` to `P` can only be used on the main actor, so it cannot be provided to `doSomethingStatic`, which calls the conformance from a different concurrent task.
|