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 -Xfrontend -disable-availability-checking -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()
}
}
|