Files
swift-mirror/test/Concurrency/Runtime/custom_main_executor.swift
Alastair Houghton 6cc4a4d823 [SILGen][Concurrency] Improve DefaultExecutorFactory lookup.
Rather than just looking at top level in the module, start by searching
the type marked as `@main`.  This means that a library that provides a
protocol or superclass that the `@main` type can conform to can specify
an executor in a reasonable manner.
2025-08-26 09:38:13 +01:00

135 lines
4.2 KiB
Swift

// RUN: %target-run-simple-swift(-DTOPLEVEL_FACTORY -Xfrontend -disable-availability-checking -g %import-libdispatch -parse-as-library) | %FileCheck %s
// RUN: %target-run-simple-swift(-DPROTOCOL_FACTORY -Xfrontend -disable-availability-checking -g %import-libdispatch -parse-as-library) | %FileCheck %s
// RUN: %target-run-simple-swift(-DPROTOCOL_FACTORY_OVERRIDDEN -Xfrontend -disable-availability-checking -g %import-libdispatch -parse-as-library) | %FileCheck %s
// RUN: %target-run-simple-swift(-DPROTOCOL_FACTORY_DEFAULT -Xfrontend -disable-availability-checking -g %import-libdispatch -parse-as-library) | %FileCheck %s
// RUN: %target-run-simple-swift(-DPROTOCOL_FACTORY_DEFAULT2 -Xfrontend -disable-availability-checking -g %import-libdispatch -parse-as-library) | %FileCheck %s
// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking -g %import-libdispatch -parse-as-library) | %FileCheck %s
// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking -g %import-libdispatch -parse-as-library -swift-version 5 -strict-concurrency=complete -enable-upcoming-feature NonisolatedNonsendingByDefault) | %FileCheck %s
// REQUIRES: swift_feature_NonisolatedNonsendingByDefault
// REQUIRES: concurrency
// REQUIRES: executable_test
// rdar://106849189 move-only types should be supported in freestanding mode
// UNSUPPORTED: freestanding
// UNSUPPORTED: back_deployment_runtime
// REQUIRES: concurrency_runtime
// REQUIRES: synchronization
import StdlibUnittest
import Synchronization
#if TOPLEVEL_FACTORY
typealias DefaultExecutorFactory = SimpleExecutorFactory
#endif
struct SimpleExecutorFactory: ExecutorFactory {
public static var mainExecutor: any MainExecutor {
print("Creating main executor")
return SimpleMainExecutor()
}
public static var defaultExecutor: any TaskExecutor {
print("Creating task executor")
return SimpleTaskExecutor()
}
}
struct FatalExecutorFactory: ExecutorFactory {
public static var mainExecutor: any MainExecutor {
fatalError("mainExecutor called on FatalExecutorFactory")
}
public static var defaultExecutor: any TaskExecutor {
fatalError("taskExecutor called on FatalExecutorFactory")
}
}
@available(SwiftStdlib 6.2, *)
final class SimpleMainExecutor: MainExecutor, @unchecked Sendable {
public var isRunning: Bool = false
var shouldStop: Bool = false
let queue = Mutex<[UnownedJob]>([])
func enqueue(_ job: consuming ExecutorJob) {
print("Enqueued job")
let unownedJob = UnownedJob(job)
queue.withLock {
$0.append(unownedJob)
}
}
func run() throws {
print("Running")
isRunning = true
while !shouldStop {
let jobs = queue.withLock {
let jobs = $0
$0.removeAll()
return jobs
}
for job in jobs {
print("Running job")
job.runSynchronously(on: self.asUnownedSerialExecutor())
}
}
isRunning = false
}
func stop() {
shouldStop = true
}
}
@available(SwiftStdlib 6.2, *)
final class SimpleTaskExecutor: TaskExecutor, @unchecked Sendable {
func enqueue(_ job: consuming ExecutorJob) {
MainActor.executor.enqueue(job)
}
}
@concurrent func myAsyncFunction() async {
print("Hello World")
}
protocol AppProtocol {
#if PROTOCOL_FACTORY
associatedtype DefaultExecutorFactory
#endif
#if PROTOCOL_FACTORY_DEFAULT
associatedtype DefaultExecutorFactory = SimpleExecutorFactory
#endif
#if PROTOCOL_FACTORY_DEFAULT2 || PROTOCOL_FACTORY_OVERRIDDEN
associatedtype DefaultExecutorFactory = FatalExecutorFactory
#endif
}
#if PROTOCOL_FACTORY || PROTOCOL_FACTORY_DEFAULT2
extension AppProtocol {
typealias DefaultExecutorFactory = SimpleExecutorFactory
}
#endif
@available(SwiftStdlib 6.2, *)
@main struct Main: AppProtocol {
#if !TOPLEVEL_FACTORY && !PROTOCOL_FACTORY && !PROTOCOL_FACTORY_DEFAULT && !PROTOCOL_FACTORY_DEFAULT2
typealias DefaultExecutorFactory = SimpleExecutorFactory
#endif
static func main() async {
print("Hello")
await myAsyncFunction()
print("Goodbye")
}
}
// CHECK: Creating main executor
// CHECK-NEXT: Creating task executor
// CHECK-NEXT: Hello
// CHECK-NEXT: Enqueued job
// CHECK-NEXT: Running
// CHECK-NEXT: Running job
// CHECK-NEXT: Hello World
// CHECK-NEXT: Goodbye