|
10 | 10 | //
|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
13 |
| -/// A type `T` whose metatype `T.Type` is `Sendable`. |
| 13 | +/// A type whose metatype can be shared across arbitrary concurrent contexts |
| 14 | +/// without introducing a risk of data races. When a generic type `T` conforms |
| 15 | +/// to `SendableMetatype`, its metatype `T.Type` conforms to `Sendable`. All |
| 16 | +/// concrete types implicitly conform to the `SendableMetatype` protocol, so its |
| 17 | +/// primary purpose is in generic code to prohibit the use of isolated |
| 18 | +/// conformances along with the generic type. |
| 19 | +/// |
| 20 | +/// A generic type `T` will need a `SendableMetatype` conformance when its |
| 21 | +/// metatype is shared across concurrency boundaries. For example, |
| 22 | +/// |
| 23 | +/// protocol P { |
| 24 | +/// static func f() |
| 25 | +/// } |
| 26 | +/// |
| 27 | +/// func useFromAnotherTask<T: P>(_: T.Type) { |
| 28 | +/// Task { @concurrent in |
| 29 | +/// T.f() // error: capturing non-Sendable type `T.Type` in a concurrently-executing task |
| 30 | +/// } |
| 31 | +/// } |
| 32 | +/// |
| 33 | +/// The potential data race above would occur when `useFromAnotherTask` is |
| 34 | +/// provided with an isolated conformance to `P`. For example: |
| 35 | +/// |
| 36 | +/// @MainActor |
| 37 | +/// class MyModel: @MainActor P { |
| 38 | +/// /*implicitly @MainActor/* |
| 39 | +/// static func f() { |
| 40 | +/// /* on the main actor */ |
| 41 | +/// } |
| 42 | +/// } |
| 43 | +/// |
| 44 | +/// useFromAnotherTask(MyModel.self) |
| 45 | +/// |
| 46 | +/// Here, the error within the body of `useFromAnotherTask` is preventing the |
| 47 | +/// isolated conformance from leaving the current task and actor. The signature |
| 48 | +/// of `useFromAnotherTask` can be adjusted to introduce a requirement on |
| 49 | +/// `SendableMetatype`: |
| 50 | +/// |
| 51 | +/// func useFromAnotherTask<T: P & SendableMetatype>(_: T.Type) { |
| 52 | +/// Task { @concurrent in |
| 53 | +/// T.f() // error: okay, T.Type is Sendable |
| 54 | +/// } |
| 55 | +/// } |
| 56 | +/// |
| 57 | +/// useFromAnotherTask(MyModel.self) // error: cannot use main-actor-isolated conformance `MyModel: P` for a `SendableMetatype`-conforming type parameter `T` |
| 58 | +/// |
| 59 | +/// The `Sendable` protocol inherits from `SendableMetatype`, so any generic |
| 60 | +/// type `T` with a requirement `T: Sendable` will have the implied requirement |
| 61 | +/// `T: SendableMetatype`. |
14 | 62 | @_marker public protocol SendableMetatype: ~Copyable, ~Escapable { }
|
15 | 63 |
|
16 | 64 | /// A thread-safe type whose values can be shared across arbitrary concurrent
|
|
135 | 183 | /// ### Sendable Metatypes
|
136 | 184 | ///
|
137 | 185 | /// Metatypes such as `Int.Type` implicitly conform to the `Sendable` protocol.
|
| 186 | +/// For a generic type `T`, its metatype `T.Type` does not necessarily conform |
| 187 | +/// to `Sendable`. Please see the `SendableMetatype` protocol for more |
| 188 | +/// information. |
138 | 189 | @_marker public protocol Sendable: SendableMetatype, ~Copyable, ~Escapable { }
|
139 | 190 |
|
140 | 191 | ///
|
|
0 commit comments