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
|
// RUN: %target-run-simple-swift(-parse-as-library -Xfrontend -disable-availability-checking %import-libdispatch) | %FileCheck %s
// REQUIRES: executable_test
// REQUIRES: concurrency
// REQUIRES: libdispatch
// rdar://76038845
// REQUIRES: concurrency_runtime
// UNSUPPORTED: back_deployment_runtime
// UNSUPPORTED: single_threaded_concurrency
import Dispatch
/// @returns true iff the expected answer is actually the case, i.e., correct.
/// If the current queue does not match expectations, this function may return
/// false or just crash the program with non-zero exit code, depending on SDK.
func checkIfMainQueue(expectedAnswer expected: Bool) -> Bool {
if #available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *) {
dispatchPrecondition(condition: expected ? .onQueue(DispatchQueue.main)
: .notOnQueue(DispatchQueue.main))
}
return true
}
actor A {
func onCorrectQueue(_ count : Int) -> Int {
if checkIfMainQueue(expectedAnswer: false) {
print("on actor instance's queue")
return count + 1
}
print("ERROR: not on actor instance's queue")
return -10
}
}
@MainActor func checkAnotherFn(_ count : Int) -> Int {
if checkIfMainQueue(expectedAnswer: true) {
print("on main queue again!")
return count + 1
} else {
print("ERROR: left the main queue?")
return -10
}
}
@MainActor func enterMainActor(_ initialCount : Int) async -> Int {
if checkIfMainQueue(expectedAnswer: true) {
print("hello from main actor!")
} else {
print("ERROR: not on correct queue!")
}
// try calling a function on another actor.
let count = await A().onCorrectQueue(initialCount)
guard checkIfMainQueue(expectedAnswer: true) else {
print("ERROR: did not switch back to main actor!")
return -10
}
return checkAnotherFn(count) + 1
}
@Sendable func someFunc() async -> Int {
// NOTE: the "return" counter is just to make sure we're properly returning values.
// the expected number should be equal to the number of "plus-one" expressions.
// since there are no loops or duplicate function calls
return await enterMainActor(0) + 1
}
@MainActor func mainActorFn() -> Int {
checkIfMainQueue(expectedAnswer: true)
return 10
}
@MainActor
struct S {
static var bacteria: Int = mainActorFn()
}
@MainActor
class C {
static var bacteria: Int = mainActorFn()
lazy var amoeba: Int = mainActorFn()
nonisolated init() {}
}
// CHECK: starting
// CHECK-NOT: ERROR
// CHECK: Hello from the main function
// CHECK-NOT: ERROR
// CHECK: hello from main actor!
// CHECK-NOT: ERROR
// CHECK: on actor instance's queue
// CHECK-NOT: ERROR
// CHECK: on main queue again!
// CHECK-NOT: ERROR
// CHECK: finished with return counter = 4
// CHECK: detached task not on main queue
// CHECK: on main queue again
// CHECK: detached task hopped back
@main struct RunIt {
static func main() async {
print("starting")
if checkIfMainQueue(expectedAnswer: true) {
print("Hello from the main function")
} else {
print("ERROR: not on the main queue")
}
let result = await someFunc()
print("finished with return counter = \(result)")
// Check actor hopping with MainActor.run.
let task = Task.detached {
if checkIfMainQueue(expectedAnswer: false) {
print("detached task not on main queue")
} else {
print("ERROR: detached task is on the main queue?")
}
_ = await MainActor.run {
checkAnotherFn(1)
}
if checkIfMainQueue(expectedAnswer: false) {
print("detached task hopped back")
} else {
print("ERROR: detached task is on the main queue?")
}
}
_ = await task.value
// Check that initializers for stored properties are on the right actor
let t1 = Task.detached { () -> Int in
let c = C()
return await c.amoeba
}
let t2 = Task.detached { () -> Int in
return await S.bacteria + C.bacteria
}
_ = await t1.value + t2.value
}
}
|