Files
swift-mirror/test/Concurrency/Runtime/mainactor.swift
Alastair Houghton 47fa71787f Revert "Merge pull request #80224 from glessard/revert-79789-custom-executors"
This reverts commit 06f6358067, reversing
changes made to 033f6679e8.
2025-03-28 10:15:07 +00:00

146 lines
3.9 KiB
Swift

// RUN: %target-run-simple-swift(-parse-as-library -g -target %target-swift-5.1-abi-triple %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
}
}