|
| 1 | +import Library |
| 2 | + |
| 3 | +// MARK: Under-Specified Protocol |
| 4 | + |
| 5 | +#if swift(<6.0) |
| 6 | +/// A conforming type that has now adopted global isolation. |
| 7 | +@MainActor |
| 8 | +class WindowStyler: Styler { |
| 9 | + // Swift 5 Warning: main actor-isolated instance method 'applyStyle()' cannot be used to satisfy nonisolated protocol requirement |
| 10 | + // Swift 6 Error: main actor-isolated instance method 'applyStyle()' cannot be used to satisfy nonisolated protocol requirement |
| 11 | + func applyStyle() { |
| 12 | + } |
| 13 | +} |
| 14 | +#endif |
| 15 | + |
| 16 | +// MARK: Globally-Isolated Protocol |
| 17 | + |
| 18 | +/// A type conforming to the global actor annotated `GloballyIsolatedStyler` protocol, |
| 19 | +/// will infer the protocol's global actor isolation. |
| 20 | +class GloballyIsolatedWindowStyler: GloballyIsolatedStyler { |
| 21 | + func applyStyle() { |
| 22 | + } |
| 23 | +} |
| 24 | + |
| 25 | +/// A type conforming to `PerRequirementIsolatedStyler` which has MainActor isolated protocol requirements, |
| 26 | +/// will infer the protocol's requirements isolation for methods witnessing those protocol requirements *only* |
| 27 | +/// for the satisfying methods. |
| 28 | +class PerRequirementIsolatedWindowStyler: PerRequirementIsolatedStyler { |
| 29 | + func applyStyle() { |
| 30 | + // only this is MainActor-isolated |
| 31 | + } |
| 32 | + |
| 33 | + func checkStyle() { |
| 34 | + // this method is non-isolated; it is not witnessing any isolated protocol requirement |
| 35 | + } |
| 36 | +} |
| 37 | + |
| 38 | +// MARK: Asynchronous Requirements |
| 39 | + |
| 40 | +/// A conforming type that can have arbitrary isolation and |
| 41 | +/// still matches the async requirement. |
| 42 | +class AsyncWindowStyler: AsyncStyler { |
| 43 | + func applyStyle() { |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +// MARK: Using preconcurrency |
| 48 | + |
| 49 | +/// A conforming type that will infer the protocol's global isolation *but* |
| 50 | +/// with downgraded diagnostics in Swift 6 mode and Swift 5 + complete checking |
| 51 | +class StagedGloballyIsolatedWindowStyler: StagedGloballyIsolatedStyler { |
| 52 | + func applyStyle() { |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +// MARK: Using Dynamic Isolation |
| 57 | + |
| 58 | +/// A conforming type that uses a nonisolated function to match |
| 59 | +/// with dynamic isolation in the method body. |
| 60 | +@MainActor |
| 61 | +class DynamicallyIsolatedStyler: Styler { |
| 62 | + nonisolated func applyStyle() { |
| 63 | +#if compiler(<6.0) |
| 64 | + // temporarily disabled due to https://github.com/apple/swift/issues/74009 |
| 65 | + MainActor.assumeIsolated { |
| 66 | + // MainActor state is available here |
| 67 | + } |
| 68 | +#endif |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +#if compiler(>=6.0) |
| 73 | +/// A conforming type that uses a preconcurency conformance, which |
| 74 | +/// is a safer and more ergonomic version of DynamicallyIsolatedStyler. |
| 75 | +@MainActor |
| 76 | +class PreconcurrencyConformanceStyler: @preconcurrency Styler { |
| 77 | + func applyStyle() { |
| 78 | + } |
| 79 | +} |
| 80 | +#endif |
| 81 | + |
| 82 | +// MARK: Non-Isolated |
| 83 | + |
| 84 | +/// A conforming type that uses nonisolated and non-Sendable types but |
| 85 | +/// still performs useful work. |
| 86 | +@MainActor |
| 87 | +class NonisolatedWindowStyler: StylerConfiguration { |
| 88 | + nonisolated var primaryColorComponents: ColorComponents { |
| 89 | + ColorComponents(red: 0.2, green: 0.3, blue: 0.4) |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +// MARK: Conformance by Proxy |
| 94 | + |
| 95 | +/// An intermediary type that conforms to the protocol so it can be |
| 96 | +/// used by an actor |
| 97 | +struct CustomWindowStyle: Styler { |
| 98 | + func applyStyle() { |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +/// An actor that interacts with the Style protocol indirectly. |
| 103 | +actor ActorWindowStyler { |
| 104 | + private let internalStyle = CustomWindowStyle() |
| 105 | + |
| 106 | + func applyStyle() { |
| 107 | + // forward the call through to the conforming type |
| 108 | + internalStyle.applyStyle() |
| 109 | + } |
| 110 | +} |
| 111 | + |
| 112 | +func exerciseConformanceMismatchExamples() async { |
| 113 | + print("Protocol Conformance Isolation Mismatch Examples") |
| 114 | + |
| 115 | + // Could also all be done with async calls, but this |
| 116 | + // makes the isolation, and the ability to invoke them |
| 117 | + // from a synchronous context explicit. |
| 118 | + await MainActor.run { |
| 119 | +#if swift(<6.0) |
| 120 | + print(" - using a mismatched conformance") |
| 121 | + WindowStyler().applyStyle() |
| 122 | +#endif |
| 123 | + |
| 124 | + print(" - using a MainActor-isolated type") |
| 125 | + GloballyIsolatedWindowStyler().applyStyle() |
| 126 | + |
| 127 | + print(" - using a per-requirement MainActor-isolated type") |
| 128 | + PerRequirementIsolatedWindowStyler().applyStyle() |
| 129 | + |
| 130 | + print(" - using an async conformance") |
| 131 | + AsyncWindowStyler().applyStyle() |
| 132 | + |
| 133 | + print(" - using staged isolation") |
| 134 | + StagedGloballyIsolatedWindowStyler().applyStyle() |
| 135 | + |
| 136 | + print(" - using dynamic isolation") |
| 137 | + DynamicallyIsolatedStyler().applyStyle() |
| 138 | + |
| 139 | +#if swift(>=6.0) |
| 140 | + print(" - using a preconcurrency conformance") |
| 141 | + PreconcurrencyConformanceStyler().applyStyle() |
| 142 | +#endif |
| 143 | + |
| 144 | + let value = NonisolatedWindowStyler().primaryColorComponents |
| 145 | + print(" - accessing a non-isolated conformance: ", value) |
| 146 | + } |
| 147 | + |
| 148 | + print(" - using an actor with a proxy conformance") |
| 149 | + await ActorWindowStyler().applyStyle() |
| 150 | +} |
0 commit comments