Skip to content

Commit c7bf59e

Browse files
committed
Require ThreadSafeBox.T to be Sendable
Otherwise, I think `ThreadSafeBox` might still have data races. This also requires us to make `TestSourceKitLSPClient.RequestHandler` sendable. rdar://128572489
1 parent 98718d4 commit c7bf59e

File tree

4 files changed

+15
-4
lines changed

4 files changed

+15
-4
lines changed

Sources/SKSupport/AsyncUtils.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public extension Task where Failure == Never {
9898
///
9999
/// If the task executing `withCancellableCheckedThrowingContinuation` gets
100100
/// cancelled, `cancel` is invoked with the handle that `operation` provided.
101-
public func withCancellableCheckedThrowingContinuation<Handle, Result>(
101+
public func withCancellableCheckedThrowingContinuation<Handle: Sendable, Result>(
102102
_ operation: (_ continuation: CheckedContinuation<Result, any Error>) -> Handle,
103103
cancel: @Sendable (Handle) -> Void
104104
) async throws -> Result {

Sources/SKSupport/ThreadSafeBox.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ extension NSLock {
2424
/// A thread safe container that contains a value of type `T`.
2525
///
2626
/// - Note: Unchecked sendable conformance because value is guarded by a lock.
27-
public class ThreadSafeBox<T>: @unchecked Sendable {
27+
public class ThreadSafeBox<T: Sendable>: @unchecked Sendable {
2828
/// Lock guarding `_value`.
2929
private let lock = NSLock()
3030

@@ -41,6 +41,11 @@ public class ThreadSafeBox<T>: @unchecked Sendable {
4141
_value = newValue
4242
}
4343
}
44+
_modify {
45+
lock.lock()
46+
defer { lock.unlock() }
47+
yield &_value
48+
}
4449
}
4550

4651
public init(initialValue: T) {

Sources/SKTestSupport/TestSourceKitLSPClient.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ extension SourceKitLSPServer.Options {
3434
/// that the server sends to the client.
3535
public final class TestSourceKitLSPClient: MessageHandler {
3636
/// A function that takes a request and returns the request's response.
37-
public typealias RequestHandler<Request: RequestType> = (Request) -> Request.Response
37+
public typealias RequestHandler<Request: RequestType> = @Sendable (Request) -> Request.Response
3838

3939
/// The ID that should be assigned to the next request sent to the `server`.
4040
/// `nonisolated(unsafe)` is fine because `nextRequestID` is atomic.
@@ -72,7 +72,7 @@ public final class TestSourceKitLSPClient: MessageHandler {
7272
///
7373
/// `isOneShort` if the request handler should only serve a single request and should be removed from
7474
/// `requestHandlers` after it has been called.
75-
private nonisolated(unsafe) var requestHandlers: ThreadSafeBox<[(requestHandler: Any, isOneShot: Bool)]> =
75+
private nonisolated(unsafe) var requestHandlers: ThreadSafeBox<[(requestHandler: Sendable, isOneShot: Bool)]> =
7676
ThreadSafeBox(initialValue: [])
7777

7878
/// A closure that is called when the `TestSourceKitLSPClient` is destructed.

Sources/SourceKitD/SourceKitD.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ import Dispatch
1515
import Foundation
1616
import SKSupport
1717

18+
#if compiler(>=6)
19+
extension sourcekitd_api_request_handle_t: @retroactive @unchecked Sendable {}
20+
#else
21+
extension sourcekitd_api_request_handle_t: @unchecked Sendable {}
22+
#endif
23+
1824
/// Access to sourcekitd API, taking care of initialization, shutdown, and notification handler
1925
/// multiplexing.
2026
///

0 commit comments

Comments
 (0)