Skip to content

Commit bf88588

Browse files
authored
Merge branch 'main' into fix-uikit-identifiable-dismiss
2 parents 442c7de + 3879d2c commit bf88588

File tree

5 files changed

+94
-37
lines changed

5 files changed

+94
-37
lines changed

Sources/ComposableArchitecture/Internal/KeyPath+Sendable.swift

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,69 @@
2222
public typealias _SendableCaseKeyPath<Root, Value> = CaseKeyPath<Root, Value>
2323
#endif
2424

25-
@_transparent
26-
func sendableKeyPath(
27-
_ keyPath: AnyKeyPath
28-
) -> _SendableAnyKeyPath {
29-
#if compiler(>=6)
30-
unsafeBitCast(keyPath, to: _SendableAnyKeyPath.self)
31-
#else
32-
keyPath
33-
#endif
25+
// NB: Dynamic member lookup does not currently support sendable key paths and even breaks
26+
// autocomplete.
27+
//
28+
// * https://github.com/swiftlang/swift/issues/77035
29+
// * https://github.com/swiftlang/swift/issues/77105
30+
extension _AppendKeyPath {
31+
@_transparent
32+
func unsafeSendable() -> _SendableAnyKeyPath
33+
where Self == AnyKeyPath {
34+
#if compiler(>=6)
35+
unsafeBitCast(self, to: _SendableAnyKeyPath.self)
36+
#else
37+
self
38+
#endif
39+
}
40+
41+
@_transparent
42+
func unsafeSendable<Root>() -> _SendablePartialKeyPath<Root>
43+
where Self == PartialKeyPath<Root> {
44+
#if compiler(>=6)
45+
unsafeBitCast(self, to: _SendablePartialKeyPath<Root>.self)
46+
#else
47+
self
48+
#endif
49+
}
50+
51+
@_transparent
52+
func unsafeSendable<Root, Value>() -> _SendableKeyPath<Root, Value>
53+
where Self == KeyPath<Root, Value> {
54+
#if compiler(>=6)
55+
unsafeBitCast(self, to: _SendableKeyPath<Root, Value>.self)
56+
#else
57+
self
58+
#endif
59+
}
60+
61+
@_transparent
62+
func unsafeSendable<Root, Value>() -> _SendableWritableKeyPath<Root, Value>
63+
where Self == WritableKeyPath<Root, Value> {
64+
#if compiler(>=6)
65+
unsafeBitCast(self, to: _SendableWritableKeyPath<Root, Value>.self)
66+
#else
67+
self
68+
#endif
69+
}
70+
71+
@_transparent
72+
func unsafeSendable<Root, Value>() -> _SendableReferenceWritableKeyPath<Root, Value>
73+
where Self == ReferenceWritableKeyPath<Root, Value> {
74+
#if compiler(>=6)
75+
unsafeBitCast(self, to: _SendableReferenceWritableKeyPath<Root, Value>.self)
76+
#else
77+
self
78+
#endif
79+
}
80+
81+
@_transparent
82+
func unsafeSendable<Root, Value>() -> _SendableCaseKeyPath<Root, Value>
83+
where Self == CaseKeyPath<Root, Value> {
84+
#if compiler(>=6)
85+
unsafeBitCast(self, to: _SendableCaseKeyPath<Root, Value>.self)
86+
#else
87+
self
88+
#endif
89+
}
3490
}

Sources/ComposableArchitecture/Observation/Binding+Observation.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,12 @@ extension BindableAction where State: ObservableState {
159159

160160
extension Store where State: ObservableState, Action: BindableAction, Action.State == State {
161161
public subscript<Value: Equatable & Sendable>(
162-
dynamicMember keyPath: _SendableWritableKeyPath<State, Value>
162+
dynamicMember keyPath: WritableKeyPath<State, Value>
163163
) -> Value {
164164
get { self.state[keyPath: keyPath] }
165165
set {
166166
BindingLocal.$isActive.withValue(true) {
167-
self.send(.set(keyPath, newValue, isInvalidated: _isInvalidated))
167+
self.send(.set(keyPath.unsafeSendable(), newValue, isInvalidated: _isInvalidated))
168168
}
169169
}
170170
}
@@ -195,12 +195,12 @@ where
195195
Action.ViewAction.State == State
196196
{
197197
public subscript<Value: Equatable & Sendable>(
198-
dynamicMember keyPath: _SendableWritableKeyPath<State, Value>
198+
dynamicMember keyPath: WritableKeyPath<State, Value>
199199
) -> Value {
200200
get { self.state[keyPath: keyPath] }
201201
set {
202202
BindingLocal.$isActive.withValue(true) {
203-
self.send(.view(.set(keyPath, newValue, isInvalidated: _isInvalidated)))
203+
self.send(.view(.set(keyPath.unsafeSendable(), newValue, isInvalidated: _isInvalidated)))
204204
}
205205
}
206206
}

Sources/ComposableArchitecture/Reducer/Reducers/PresentationReducer.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,11 @@ extension PresentationAction: CasePathable {
293293
}
294294

295295
public subscript<AppendedAction>(
296-
dynamicMember keyPath: _SendableCaseKeyPath<Action, AppendedAction>
296+
dynamicMember keyPath: CaseKeyPath<Action, AppendedAction>
297297
) -> AnyCasePath<PresentationAction, AppendedAction>
298298
where Action: CasePathable {
299-
AnyCasePath<PresentationAction, AppendedAction>(
299+
let keyPath = keyPath.unsafeSendable()
300+
return AnyCasePath<PresentationAction, AppendedAction>(
300301
embed: { .presented(keyPath($0)) },
301302
extract: {
302303
guard case let .presented(action) = $0 else { return nil }
@@ -307,10 +308,11 @@ extension PresentationAction: CasePathable {
307308

308309
@_disfavoredOverload
309310
public subscript<AppendedAction>(
310-
dynamicMember keyPath: _SendableCaseKeyPath<Action, AppendedAction>
311+
dynamicMember keyPath: CaseKeyPath<Action, AppendedAction>
311312
) -> AnyCasePath<PresentationAction, PresentationAction<AppendedAction>>
312313
where Action: CasePathable {
313-
AnyCasePath<PresentationAction, PresentationAction<AppendedAction>>(
314+
let keyPath = keyPath.unsafeSendable()
315+
return AnyCasePath<PresentationAction, PresentationAction<AppendedAction>>(
314316
embed: {
315317
switch $0 {
316318
case .dismiss:

Sources/ComposableArchitecture/SharedState/Shared.swift

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,9 @@ public struct Shared<Value: Sendable>: Sendable {
6464
reference: base.reference,
6565
// NB: Can get rid of bitcast when this is fixed:
6666
// https://github.com/swiftlang/swift/issues/75531
67-
keyPath: sendableKeyPath(
68-
(base.keyPath as AnyKeyPath)
69-
.appending(path: \Value?.[default: DefaultSubscript(initialValue)])!
70-
)
67+
keyPath: (base.keyPath as AnyKeyPath)
68+
.appending(path: \Value?.[default: DefaultSubscript(initialValue)])!
69+
.unsafeSendable()
7170
)
7271
}
7372

@@ -179,9 +178,9 @@ public struct Shared<Value: Sendable>: Sendable {
179178
reference: self.reference,
180179
// NB: Can get rid of bitcast when this is fixed:
181180
// https://github.com/swiftlang/swift/issues/75531
182-
keyPath: sendableKeyPath(
183-
(self.keyPath as AnyKeyPath).appending(path: keyPath)!
184-
)
181+
keyPath: (self.keyPath as AnyKeyPath)
182+
.appending(path: keyPath)!
183+
.unsafeSendable()
185184
)
186185
}
187186

@@ -459,11 +458,7 @@ extension Shared {
459458
) -> SharedReader<Member> {
460459
SharedReader<Member>(
461460
reference: self.reference,
462-
// NB: Can get rid of bitcast when this is fixed:
463-
// https://github.com/swiftlang/swift/issues/75531
464-
keyPath: sendableKeyPath(
465-
(self.keyPath as AnyKeyPath).appending(path: keyPath)!
466-
)
461+
keyPath: (self.keyPath as AnyKeyPath).appending(path: keyPath)!.unsafeSendable()
467462
)
468463
}
469464

Sources/ComposableArchitecture/SwiftUI/Binding.swift

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -174,18 +174,20 @@ public struct BindingAction<Root>: CasePathable, Equatable, Sendable {
174174
@dynamicMemberLookup
175175
public struct AllCasePaths {
176176
public subscript<Value: Equatable & Sendable>(
177-
dynamicMember keyPath: _SendableWritableKeyPath<Root, Value>
177+
dynamicMember keyPath: WritableKeyPath<Root, Value>
178178
) -> AnyCasePath<BindingAction, Value> where Root: ObservableState {
179-
AnyCasePath(
179+
let keyPath = keyPath.unsafeSendable()
180+
return AnyCasePath(
180181
embed: { .set(keyPath, $0) },
181182
extract: { $0.keyPath == keyPath ? $0.value as? Value : nil }
182183
)
183184
}
184185

185186
public subscript<Value: Equatable & Sendable>(
186-
dynamicMember keyPath: _SendableWritableKeyPath<Root, BindingState<Value>>
187+
dynamicMember keyPath: WritableKeyPath<Root, BindingState<Value>>
187188
) -> AnyCasePath<BindingAction, Value> {
188-
AnyCasePath(
189+
let keyPath = keyPath.unsafeSendable()
190+
return AnyCasePath(
189191
embed: { .set(keyPath, $0) },
190192
extract: { $0.keyPath == keyPath ? $0.value as? Value : nil }
191193
)
@@ -299,9 +301,10 @@ extension BindableAction {
299301

300302
extension ViewStore where ViewAction: BindableAction, ViewAction.State == ViewState {
301303
public subscript<Value: Equatable & Sendable>(
302-
dynamicMember keyPath: _SendableWritableKeyPath<ViewState, BindingState<Value>>
304+
dynamicMember keyPath: WritableKeyPath<ViewState, BindingState<Value>>
303305
) -> Binding<Value> {
304-
self.binding(
306+
let keyPath = keyPath.unsafeSendable()
307+
return self.binding(
305308
get: { $0[keyPath: keyPath].wrappedValue },
306309
send: { value in
307310
#if DEBUG
@@ -454,9 +457,10 @@ public struct BindingViewStore<State> {
454457
}
455458

456459
public subscript<Value: Equatable & Sendable>(
457-
dynamicMember keyPath: _SendableWritableKeyPath<State, BindingState<Value>>
460+
dynamicMember keyPath: WritableKeyPath<State, BindingState<Value>>
458461
) -> BindingViewState<Value> {
459-
BindingViewState(
462+
let keyPath = keyPath.unsafeSendable()
463+
return BindingViewState(
460464
binding: ViewStore(self.store, observe: { $0[keyPath: keyPath].wrappedValue })
461465
.binding(
462466
send: { value in

0 commit comments

Comments
 (0)