diff --git a/Sources/SKSupport/AsyncUtils.swift b/Sources/SKSupport/AsyncUtils.swift index 216463fb1..0cfb2a94c 100644 --- a/Sources/SKSupport/AsyncUtils.swift +++ b/Sources/SKSupport/AsyncUtils.swift @@ -98,7 +98,7 @@ public extension Task where Failure == Never { /// /// If the task executing `withCancellableCheckedThrowingContinuation` gets /// cancelled, `cancel` is invoked with the handle that `operation` provided. -public func withCancellableCheckedThrowingContinuation( +public func withCancellableCheckedThrowingContinuation( _ operation: (_ continuation: CheckedContinuation) -> Handle, cancel: @Sendable (Handle) -> Void ) async throws -> Result { diff --git a/Sources/SKSupport/ThreadSafeBox.swift b/Sources/SKSupport/ThreadSafeBox.swift index 5f56b8c66..a4f825eaf 100644 --- a/Sources/SKSupport/ThreadSafeBox.swift +++ b/Sources/SKSupport/ThreadSafeBox.swift @@ -24,7 +24,7 @@ extension NSLock { /// A thread safe container that contains a value of type `T`. /// /// - Note: Unchecked sendable conformance because value is guarded by a lock. -public class ThreadSafeBox: @unchecked Sendable { +public class ThreadSafeBox: @unchecked Sendable { /// Lock guarding `_value`. private let lock = NSLock() @@ -41,6 +41,11 @@ public class ThreadSafeBox: @unchecked Sendable { _value = newValue } } + _modify { + lock.lock() + defer { lock.unlock() } + yield &_value + } } public init(initialValue: T) { diff --git a/Sources/SKTestSupport/TestSourceKitLSPClient.swift b/Sources/SKTestSupport/TestSourceKitLSPClient.swift index 83915ad10..299d5ff37 100644 --- a/Sources/SKTestSupport/TestSourceKitLSPClient.swift +++ b/Sources/SKTestSupport/TestSourceKitLSPClient.swift @@ -34,7 +34,7 @@ extension SourceKitLSPServer.Options { /// that the server sends to the client. public final class TestSourceKitLSPClient: MessageHandler { /// A function that takes a request and returns the request's response. - public typealias RequestHandler = (Request) -> Request.Response + public typealias RequestHandler = @Sendable (Request) -> Request.Response /// The ID that should be assigned to the next request sent to the `server`. /// `nonisolated(unsafe)` is fine because `nextRequestID` is atomic. @@ -72,7 +72,7 @@ public final class TestSourceKitLSPClient: MessageHandler { /// /// `isOneShort` if the request handler should only serve a single request and should be removed from /// `requestHandlers` after it has been called. - private nonisolated(unsafe) var requestHandlers: ThreadSafeBox<[(requestHandler: Any, isOneShot: Bool)]> = + private nonisolated(unsafe) var requestHandlers: ThreadSafeBox<[(requestHandler: Sendable, isOneShot: Bool)]> = ThreadSafeBox(initialValue: []) /// A closure that is called when the `TestSourceKitLSPClient` is destructed. diff --git a/Sources/SourceKitD/SourceKitD.swift b/Sources/SourceKitD/SourceKitD.swift index 8aa470541..a58b1b3a2 100644 --- a/Sources/SourceKitD/SourceKitD.swift +++ b/Sources/SourceKitD/SourceKitD.swift @@ -15,6 +15,12 @@ import Dispatch import Foundation import SKSupport +#if compiler(>=6) +extension sourcekitd_api_request_handle_t: @retroactive @unchecked Sendable {} +#else +extension sourcekitd_api_request_handle_t: @unchecked Sendable {} +#endif + /// Access to sourcekitd API, taking care of initialization, shutdown, and notification handler /// multiplexing. ///