Skip to content

Commit afb6685

Browse files
committed
[NCGenerics] test for Mutator pattern
covers rdar://117867086
1 parent ea9c637 commit afb6685

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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

Comments
 (0)