@@ -146,7 +146,7 @@ public enum FileMode: Sendable {
146
146
/// substitute a virtual file system or redirect file system operations.
147
147
///
148
148
/// - Note: All of these APIs are synchronous and can block.
149
- public protocol FileSystem : AnyObject {
149
+ public protocol FileSystem : AnyObject , Sendable {
150
150
/// Check whether the given path exists and is accessible.
151
151
func exists( _ path: AbsolutePath , followSymlink: Bool ) -> Bool
152
152
@@ -548,8 +548,6 @@ private class LocalFileSystem: FileSystem {
548
548
}
549
549
}
550
550
551
- // FIXME: This class does not yet support concurrent mutation safely.
552
- //
553
551
/// Concrete FileSystem implementation which simulates an empty disk.
554
552
public class InMemoryFileSystem : FileSystem {
555
553
@@ -1008,6 +1006,9 @@ public class InMemoryFileSystem: FileSystem {
1008
1006
}
1009
1007
}
1010
1008
1009
+ // Internal state of `InMemoryFileSystem` is protected with a lock in all of its `public` methods.
1010
+ extension InMemoryFileSystem : @unchecked Sendable { }
1011
+
1011
1012
/// A rerooted view on an existing FileSystem.
1012
1013
///
1013
1014
/// This is a simple wrapper which creates a new FileSystem view into a subtree
@@ -1159,9 +1160,16 @@ public class RerootedFileSystemView: FileSystem {
1159
1160
}
1160
1161
}
1161
1162
1163
+ // `RerootedFileSystemView` doesn't hold any internal state and can be considered `Sendable` since
1164
+ // `underlyingFileSystem` is required to be `Sendable`.
1165
+ extension RerootedFileSystemView : @unchecked Sendable { }
1166
+
1162
1167
/// Public access to the local FS proxy.
1163
1168
public var localFileSystem : FileSystem = LocalFileSystem ( )
1164
1169
1170
+ // `LocalFileSystem` doesn't hold any internal state and all of its underlying operations are blocking.
1171
+ extension LocalFileSystem : @unchecked Sendable { }
1172
+
1165
1173
extension FileSystem {
1166
1174
/// Print the filesystem tree of the given path.
1167
1175
///
0 commit comments