diff --git a/Sources/SourceKitD/SourceKitD.swift b/Sources/SourceKitD/SourceKitD.swift index f2ef17f9..0bd434a7 100644 --- a/Sources/SourceKitD/SourceKitD.swift +++ b/Sources/SourceKitD/SourceKitD.swift @@ -23,8 +23,8 @@ extension sourcekitd_api_values: @unchecked Sendable {} fileprivate extension ThreadSafeBox { /// If the wrapped value is `nil`, run `compute` and store the computed value. If it is not `nil`, return the stored /// value. - func computeIfNil(compute: () -> WrappedValue) -> WrappedValue where T == WrappedValue? { - return withLock { value in + func computeIfNil(compute: () -> WrappedValue) -> WrappedValue where T == WrappedValue? { + return withLock { (value: inout WrappedValue?) -> WrappedValue in if let value { return value } diff --git a/Sources/SourceKitLSP/DocumentManager.swift b/Sources/SourceKitLSP/DocumentManager.swift index f664dc22..e92d8aa5 100644 --- a/Sources/SourceKitLSP/DocumentManager.swift +++ b/Sources/SourceKitLSP/DocumentManager.swift @@ -61,7 +61,7 @@ package struct DocumentSnapshot: Identifiable, Sendable { } } -package final class Document: @unchecked Sendable { +package final class Document { package let uri: DocumentURI package let language: Language var latestVersion: Int diff --git a/Sources/SwiftExtensions/ThreadSafeBox.swift b/Sources/SwiftExtensions/ThreadSafeBox.swift index bc0ec9be..c5b29ca7 100644 --- a/Sources/SwiftExtensions/ThreadSafeBox.swift +++ b/Sources/SwiftExtensions/ThreadSafeBox.swift @@ -15,12 +15,26 @@ import Foundation /// A thread safe container that contains a value of type `T`. /// /// - Note: Unchecked sendable conformance because value is guarded by a lock. -package class ThreadSafeBox: @unchecked Sendable { +package final class ThreadSafeBox: Sendable { /// Lock guarding `_value`. private let lock = NSLock() - private var _value: T + private nonisolated(unsafe) var _value: T + package init(initialValue: T) { + _value = initialValue + } + + /// Restrict the result of the body to `Sendable` so callers can safely use + /// the returned value outside the lock without requiring `T: Sendable`. + package func withLock(_ body: (inout T) throws -> Result) rethrows -> Result { + return try lock.withLock { + return try body(&_value) + } + } +} + +extension ThreadSafeBox where T: Sendable { package var value: T { get { return lock.withLock { @@ -39,16 +53,6 @@ package class ThreadSafeBox: @unchecked Sendable { } } - package init(initialValue: T) { - _value = initialValue - } - - package func withLock(_ body: (inout T) throws -> Result) rethrows -> Result { - return try lock.withLock { - return try body(&_value) - } - } - /// If the value in the box is an optional, return it and reset it to `nil` /// in an atomic operation. package func takeValue() -> T where U? == T {