-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathactor_assume_executor.swift
161 lines (128 loc) · 4.85 KB
/
actor_assume_executor.swift
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -target %target-swift-5.1-abi-triple -parse-as-library %s -o %t/a.out
// RUN: %target-codesign %t/a.out
// RUN: %env-SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=legacy %target-run %t/a.out
// REQUIRES: executable_test
// REQUIRES: concurrency
// REQUIRES: concurrency_runtime
// TODO: The actual reason is that we do these %env- tricks, which e.g. Windows is confused about
// REQUIRES: libdispatch
// UNSUPPORTED: back_deploy_concurrency
// UNSUPPORTED: use_os_stdlib
// UNSUPPORTED: freestanding
import StdlibUnittest
func checkAssumeMainActor(echo: MainActorEcho) /* synchronous! */ {
// Echo.get("any") // error: main actor isolated, cannot perform async call here
MainActor.assumeIsolated {
let input = "example"
let got = echo.get(input)
precondition(got == "example", "Expected echo to match \(input)")
}
}
@MainActor
func mainActorCallCheck(echo: MainActorEcho) {
checkAssumeMainActor(echo: echo)
}
actor MainFriend {
nonisolated var unownedExecutor: UnownedSerialExecutor {
MainActor.sharedUnownedExecutor
}
func callCheck(echo: MainActorEcho) {
checkAssumeMainActor(echo: echo)
}
}
func checkAssumeSomeone(someone: SomeoneOnDefaultExecutor) /* synchronous */ {
// someone.something // can't access, would need a hop but we can't
someone.assumeIsolated { someone in
let something = someone.something
let expected = "isolated something"
precondition(something == expected, "expected '\(expected)', got: \(something)")
}
}
actor SomeoneOnDefaultExecutor {
func callCheckMainActor(echo: MainActorEcho) {
checkAssumeMainActor(echo: echo)
}
func callCheckSomeone() {
checkAssumeSomeone(someone: self)
}
var something: String {
"isolated something"
}
}
actor SomeonesFriend {
let someone: SomeoneOnDefaultExecutor
nonisolated var unownedExecutor: UnownedSerialExecutor {
self.someone.unownedExecutor
}
init(someone: SomeoneOnDefaultExecutor) {
self.someone = someone
}
func callCheckSomeone() {
checkAssumeSomeone(someone: someone)
}
}
actor CompleteStranger {
let someone: SomeoneOnDefaultExecutor
init(someone: SomeoneOnDefaultExecutor) {
self.someone = someone
}
func callCheckSomeone() {
checkAssumeSomeone(someone: someone)
}
}
@MainActor
final class MainActorEcho {
func get(_ key: String) -> String {
key
}
}
@main struct Main {
static func main() async {
let tests = TestSuite("AssumeActorExecutor")
let echo = MainActorEcho()
if #available(SwiftStdlib 5.1, *) {
// === MainActor --------------------------------------------------------
tests.test("MainActor.assumeIsolated: assume the main executor, from 'main() async'") {
await checkAssumeMainActor(echo: echo)
}
tests.test("MainActor.assumeIsolated: assume the main executor, from MainActor method") {
await mainActorCallCheck(echo: echo)
}
tests.test("MainActor.assumeIsolated: assume the main executor, from actor on MainActor executor") {
await MainFriend().callCheck(echo: echo)
}
#if !os(WASI)
tests.test("MainActor.assumeIsolated: wrongly assume the main executor, from actor on other executor") {
expectCrashLater(withMessage: "Incorrect actor executor assumption; Expected 'MainActor' executor.")
await SomeoneOnDefaultExecutor().callCheckMainActor(echo: echo)
}
#endif
// === some Actor -------------------------------------------------------
let someone = SomeoneOnDefaultExecutor()
#if !os(WASI)
tests.test("assumeOnActorExecutor: wrongly assume someone's executor, from 'main() async'") {
expectCrashLater(withMessage: "Incorrect actor executor assumption; Expected same executor as a.SomeoneOnDefaultExecutor.")
checkAssumeSomeone(someone: someone)
}
tests.test("assumeOnActorExecutor: wrongly assume someone's executor, from MainActor method") {
expectCrashLater(withMessage: "Incorrect actor executor assumption; Expected same executor as a.SomeoneOnDefaultExecutor.")
checkAssumeSomeone(someone: someone)
}
#endif
tests.test("assumeOnActorExecutor: assume someone's executor, from SomeoneOnDefaultExecutor") {
await someone.callCheckSomeone()
}
tests.test("assumeOnActorExecutor: assume someone's executor, from actor on the SomeoneOnDefaultExecutor.unownedExecutor") {
await SomeonesFriend(someone: someone).callCheckSomeone()
}
#if !os(WASI)
tests.test("assumeOnActorExecutor: wrongly assume the main executor, from actor on other executor") {
expectCrashLater(withMessage: "Incorrect actor executor assumption; Expected same executor as a.SomeoneOnDefaultExecutor.")
await CompleteStranger(someone: someone).callCheckSomeone()
}
#endif
}
await runAllTestsAsync()
}
}