|
| 1 | +// RUN: %target-swift-emit-sil %s -DBAD_COPY -verify -sil-verify-all -enable-experimental-feature NoncopyableGenerics |
| 2 | +// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all -enable-experimental-feature NoncopyableGenerics) | %FileCheck %s |
| 3 | +// RUN: %target-run-simple-swift(-O -Xfrontend -sil-verify-all -enable-experimental-feature NoncopyableGenerics) | %FileCheck %s |
| 4 | + |
| 5 | +// REQUIRES: executable_test |
| 6 | +// REQUIRES: asserts |
| 7 | +// REQUIRES: noncopyable_generics |
| 8 | + |
| 9 | +class Backend { |
| 10 | + private var data: [String: String] = [:] |
| 11 | + func read(key: String) -> String? { data[key] } |
| 12 | + func write(key: String, value: String?, author: String) { |
| 13 | + data[key] = "\(author) wrote: \(value ?? "nil")" |
| 14 | + } |
| 15 | +} |
| 16 | + |
| 17 | +protocol StringSubscript: ~Copyable { |
| 18 | + subscript(key: String) -> String? { get set } |
| 19 | +} |
| 20 | + |
| 21 | +protocol Accessor { |
| 22 | + associatedtype Mutator: StringSubscript & ~Copyable |
| 23 | + func mutator(as author: String) -> Mutator |
| 24 | +} |
| 25 | + |
| 26 | +struct SomeAccessor: Accessor { |
| 27 | + private let backend = Backend() |
| 28 | + |
| 29 | + struct Mutator: StringSubscript, ~Copyable { |
| 30 | + let author: String |
| 31 | + var backend: Backend |
| 32 | + |
| 33 | + subscript(key: String) -> String? { |
| 34 | + get { backend.read(key: key) } |
| 35 | + set { backend.write(key: key, value: newValue, author: author) } |
| 36 | + } |
| 37 | + } |
| 38 | + |
| 39 | + func mutator(as author: String) -> Mutator { .init(author: author, backend: backend) } |
| 40 | +} |
| 41 | + |
| 42 | + |
| 43 | +// The major goal of this `Accessor` is that you cannot escape the `Mutator` in the context of the writer closure. |
| 44 | +extension Accessor { |
| 45 | + func write(as author: String, body: (inout Mutator) -> ()) { |
| 46 | + var writable = self.mutator(as: author) |
| 47 | + body(&writable) |
| 48 | + } |
| 49 | + |
| 50 | + func read(key: String) -> String? { |
| 51 | + let immutable = self.mutator(as: "READ_ONLY") |
| 52 | + return immutable[key] |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +func asGeneric<T: Accessor>(_ access: T) { |
| 57 | + #if BAD_COPY |
| 58 | + access.write(as: "Nobody") { // expected-error {{'$0' used after consume}} |
| 59 | + let _ = $0 // expected-note {{consumed}} |
| 60 | + $0["Blah"] = "illegal" // expected-note {{used}} |
| 61 | + } |
| 62 | + #endif |
| 63 | + |
| 64 | + access.write(as: "Someone") { $0["Foo"] = "Bar" } |
| 65 | + print(access.read(key: "Foo") ?? "nil") |
| 66 | + // CHECK: Someone wrote: Bar |
| 67 | +} |
| 68 | + |
| 69 | +defer { check() } |
| 70 | +func check() { |
| 71 | + let access = SomeAccessor() |
| 72 | + asGeneric(access) |
| 73 | +} |
0 commit comments