diff --git a/Examples/CaseStudies/UIKit/WiFiFeature/Network.swift b/Examples/CaseStudies/UIKit/WiFiFeature/Network.swift index ea4e0332f..d54998a03 100644 --- a/Examples/CaseStudies/UIKit/WiFiFeature/Network.swift +++ b/Examples/CaseStudies/UIKit/WiFiFeature/Network.swift @@ -1,6 +1,6 @@ import Foundation -struct Network: Identifiable, Hashable { +nonisolated struct Network: Identifiable, Hashable { let id = UUID() var name = "" var isSecured = true diff --git a/Examples/CaseStudies/UIKit/WiFiFeature/WiFiSettingsFeature.swift b/Examples/CaseStudies/UIKit/WiFiFeature/WiFiSettingsFeature.swift index d489bed34..e96a787ef 100644 --- a/Examples/CaseStudies/UIKit/WiFiFeature/WiFiSettingsFeature.swift +++ b/Examples/CaseStudies/UIKit/WiFiFeature/WiFiSettingsFeature.swift @@ -231,14 +231,14 @@ class WiFiSettingsViewController: UICollectionViewController, UIKitCaseStudy { model.networkTapped(network) } - enum Section: Hashable, Sendable { + nonisolated enum Section: Hashable, Sendable { case top case foundNetworks } @CasePathable @dynamicMemberLookup - enum Item: Hashable, Sendable { + nonisolated enum Item: Hashable, Sendable { case isOn case selectedNetwork(Network.ID) case foundNetwork(Network) diff --git a/Examples/Examples.xcodeproj/project.pbxproj b/Examples/Examples.xcodeproj/project.pbxproj index ac05f0d99..e9e6b8f53 100644 --- a/Examples/Examples.xcodeproj/project.pbxproj +++ b/Examples/Examples.xcodeproj/project.pbxproj @@ -629,6 +629,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 6.0; @@ -685,6 +686,7 @@ MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 6.0; diff --git a/Package.resolved b/Package.resolved index 2110df684..fc238a181 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "e7771155ba293db6f581e7fc2edba94abda4b6f9a3c4caa93c0e06ffd534a221", + "originHash" : "02849cc0317642c717337a838311b41569cf40f56f950f31fbce38ef06d67ba0", "pins" : [ { "identity" : "swift-case-paths", @@ -60,8 +60,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-perception", "state" : { - "revision" : "30721accd0370d7c9cb5bd0f7cdf5a1a767b383d", - "version" : "2.0.8" + "revision" : "4f47ebafed5f0b0172cf5c661454fa8e28fb2ac4", + "version" : "2.0.9" } }, { diff --git a/Package.swift b/Package.swift index cb98f1ded..8d76f0ea0 100644 --- a/Package.swift +++ b/Package.swift @@ -31,7 +31,7 @@ let package = Package( dependencies: [ .package(url: "https://github.com/apple/swift-collections", from: "1.0.0"), .package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.0.0"), - .package(url: "https://github.com/pointfreeco/swift-case-paths", from: "1.5.6"), + .package(url: "https://github.com/pointfreeco/swift-case-paths", branch: "relax-sendable"), .package(url: "https://github.com/pointfreeco/swift-concurrency-extras", from: "1.2.0"), .package(url: "https://github.com/pointfreeco/swift-custom-dump", from: "1.3.2"), .package(url: "https://github.com/pointfreeco/swift-perception", "1.3.4"..<"3.0.0"), diff --git a/Sources/SwiftNavigation/Internal/KeyPath+Sendable.swift b/Sources/SwiftNavigation/Internal/KeyPath+Sendable.swift deleted file mode 100644 index 78e278eae..000000000 --- a/Sources/SwiftNavigation/Internal/KeyPath+Sendable.swift +++ /dev/null @@ -1,35 +0,0 @@ -#if compiler(>=6) - public typealias _SendableKeyPath = any KeyPath & Sendable - public typealias _SendableWritableKeyPath = any WritableKeyPath - & Sendable -#else - public typealias _SendableKeyPath = KeyPath - public typealias _SendableWritableKeyPath = WritableKeyPath -#endif - -// NB: Dynamic member lookup does not currently support sendable key paths and even breaks -// autocomplete. -// -// * https://github.com/swiftlang/swift/issues/77035 -// * https://github.com/swiftlang/swift/issues/77105 -extension _AppendKeyPath { - @_transparent - func unsafeSendable() -> _SendableKeyPath - where Self == KeyPath { - #if compiler(>=6) - unsafeBitCast(self, to: _SendableKeyPath.self) - #else - self - #endif - } - - @_transparent - func unsafeSendable() -> _SendableWritableKeyPath - where Self == WritableKeyPath { - #if compiler(>=6) - unsafeBitCast(self, to: _SendableWritableKeyPath.self) - #else - self - #endif - } -} diff --git a/Sources/SwiftNavigation/UIBinding.swift b/Sources/SwiftNavigation/UIBinding.swift index 804da578c..15dd7ad26 100644 --- a/Sources/SwiftNavigation/UIBinding.swift +++ b/Sources/SwiftNavigation/UIBinding.swift @@ -80,7 +80,7 @@ import IssueReporting /// When `PlayerViewController` initializes `PlayButton`, it passes a binding of its `isPlaying` /// state along. Applying the `$` prefix to a property wrapped value returns its ``projectedValue``, /// which returns a binding to the value. Whenever the user taps the `PlayButton`, the -/// `PlayerViewController` updates its `isPlaying` state. +/// `PlayerViewController` updates its `isPlaying` state. /// /// > Note: To create bindings to properties of a type that conforms to the `Observable` or /// > `Perceptible` protocols, use the [`@UIBindable`]() property wrapper. @@ -134,7 +134,7 @@ import IssueReporting /// ``` @dynamicMemberLookup @propertyWrapper -public struct UIBinding: Sendable { +public struct UIBinding { fileprivate let location: any _UIBinding /// The binding's transaction. @@ -400,7 +400,7 @@ public struct UIBinding: Sendable { ) -> UIBinding { func open(_ location: some _UIBinding) -> UIBinding { UIBinding( - location: _UIBindingAppendKeyPath(base: location, keyPath: keyPath.unsafeSendable()), + location: _UIBindingAppendKeyPath(base: location, keyPath: keyPath), transaction: transaction ) } @@ -418,7 +418,7 @@ public struct UIBinding: Sendable { where Value: CasePathable { func open(_ location: some _UIBinding) -> UIBinding { UIBinding( - location: _UIBindingEnumToOptionalCase(base: location, keyPath: keyPath.unsafeSendable()), + location: _UIBindingEnumToOptionalCase(base: location, keyPath: keyPath), transaction: transaction ) } @@ -435,7 +435,7 @@ public struct UIBinding: Sendable { where Value == Wrapped? { func open(_ location: some _UIBinding) -> UIBinding { UIBinding( - location: _UIBindingOptionalToMember(base: location, keyPath: keyPath.unsafeSendable()), + location: _UIBindingOptionalToMember(base: location, keyPath: keyPath), transaction: transaction ) } @@ -452,7 +452,7 @@ public struct UIBinding: Sendable { where Value == V? { func open(_ location: some _UIBinding) -> UIBinding { UIBinding( - location: _UIBindingOptionalEnumToCase(base: location, keyPath: keyPath.unsafeSendable()), + location: _UIBindingOptionalEnumToCase(base: location, keyPath: keyPath), transaction: transaction ) } @@ -506,24 +506,26 @@ extension UIBinding: Identifiable where Value: Identifiable { } } +extension UIBinding: @unchecked Sendable where Value: Sendable {} + /// A unique identifier for a binding. -public struct UIBindingIdentifier: Hashable, Sendable { - private let location: AnyHashableSendable +public struct UIBindingIdentifier: Hashable { + private let location: AnyHashable /// Creates an instance that uniquely identifies the given binding. /// /// - Parameter binding: An instance of a binding. public init(_ binding: UIBinding) { - self.location = AnyHashableSendable(binding.location) + self.location = AnyHashable(binding.location) } } -protocol _UIBinding: AnyObject, Hashable, Sendable { +protocol _UIBinding: AnyObject, Hashable { associatedtype Value var wrappedValue: Value { get set } } -private final class _UIBindingStrongRoot: _UIBinding, @unchecked Sendable { +private final class _UIBindingStrongRoot: _UIBinding { init(root: Root) { self.wrappedValue = root } @@ -644,10 +646,10 @@ private final class _UIBindingConstant: _UIBinding, @unchecked Sendable { } } -private final class _UIBindingAppendKeyPath: _UIBinding, Sendable { +private final class _UIBindingAppendKeyPath: _UIBinding { let base: Base - let keyPath: _SendableWritableKeyPath - init(base: Base, keyPath: _SendableWritableKeyPath) { + let keyPath: WritableKeyPath + init(base: Base, keyPath: WritableKeyPath) { self.base = base self.keyPath = keyPath } @@ -664,10 +666,7 @@ private final class _UIBindingAppendKeyPath: _UIBinding } } -private final class _UIBindingFromOptional, Value>: _UIBinding, - @unchecked - Sendable -{ +private final class _UIBindingFromOptional, Value>: _UIBinding { var value: Value let base: Base init(initialValue: Value, base: Base) { @@ -739,10 +738,10 @@ where Base.Value: Hashable { private final class _UIBindingEnumToOptionalCase: _UIBinding where Base.Value: CasePathable { let base: Base - let keyPath: _SendableKeyPath> + let keyPath: KeyPath> let casePath: AnyCasePath init( - base: Base, keyPath: _SendableKeyPath> + base: Base, keyPath: KeyPath> ) { self.base = base self.keyPath = keyPath @@ -822,8 +821,8 @@ private final class _UIBindingOptionalToMember< Base: _UIBinding, Wrapped, Value >: _UIBinding { let base: Base - let keyPath: _SendableWritableKeyPath - init(base: Base, keyPath: _SendableWritableKeyPath) { + let keyPath: WritableKeyPath + init(base: Base, keyPath: WritableKeyPath) { self.base = base self.keyPath = keyPath } @@ -852,9 +851,9 @@ private final class _UIBindingOptionalEnumToCase< Base: _UIBinding, Enum: CasePathable, Case >: _UIBinding { let base: Base - let keyPath: _SendableKeyPath> + let keyPath: KeyPath> let casePath: AnyCasePath - init(base: Base, keyPath: _SendableKeyPath>) { + init(base: Base, keyPath: KeyPath>) { self.base = base self.keyPath = keyPath self.casePath = Enum.allCasePaths[keyPath: keyPath] diff --git a/SwiftNavigation.xcworkspace/xcshareddata/swiftpm/Package.resolved b/SwiftNavigation.xcworkspace/xcshareddata/swiftpm/Package.resolved index 374b7140e..5d575a346 100644 --- a/SwiftNavigation.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/SwiftNavigation.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,4 +1,5 @@ { + "originHash" : "a46897f6b16afe8ea77ff523ab6a3826ddc0df058ca6d80318673fd74958d3cd", "pins" : [ { "identity" : "combine-schedulers", @@ -14,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-case-paths", "state" : { - "revision" : "9810c8d6c2914de251e072312f01d3bf80071852", - "version" : "1.7.1" + "branch" : "relax-sendable", + "revision" : "53c0e4184ffa474eaa5172c34d59b02cbf218523" } }, { @@ -127,5 +128,5 @@ } } ], - "version" : 2 + "version" : 3 }