Skip to content

Commit 38a9411

Browse files
stephencelisp4checo
authored andcommitted
Use opaque reducers in 5.7 to fix builder inference (#1591)
* Use opaque reducers in 5.7 to fix builder inference * wip * wip * Revert "wip" This reverts commit f51e5690f62d10df5af37e85d2509a311fb5916e. * wip * Fix availability; simplify optionality (cherry picked from commit 9413d9fbcd057f353891c9f3b791cac7c41f59ee) # Conflicts: # Tests/ComposableArchitectureTests/CompatibilityTests.swift # Tests/ComposableArchitectureTests/ComposableArchitectureTests.swift
1 parent 26f49f5 commit 38a9411

File tree

11 files changed

+747
-662
lines changed

11 files changed

+747
-662
lines changed

Sources/ComposableArchitecture/Reducer/ReducerBuilder.swift

Lines changed: 181 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -7,175 +7,101 @@
77
/// See ``CombineReducers`` for an entry point into a reducer builder context.
88
@resultBuilder
99
public enum ReducerBuilder<State, Action> {
10-
@inlinable
11-
public static func buildArray<R: ReducerProtocol>(_ reducers: [R]) -> _SequenceMany<R>
12-
where R.State == State, R.Action == Action {
13-
_SequenceMany(reducers: reducers)
14-
}
15-
16-
@inlinable
17-
public static func buildBlock() -> EmptyReducer<State, Action> {
18-
EmptyReducer()
19-
}
20-
21-
@inlinable
22-
public static func buildBlock<R: ReducerProtocol>(_ reducer: R) -> R
23-
where R.State == State, R.Action == Action {
24-
reducer
25-
}
26-
27-
@inlinable
28-
public static func buildEither<R0: ReducerProtocol, R1: ReducerProtocol>(
29-
first reducer: R0
30-
) -> _Conditional<R0, R1>
31-
where R0.State == State, R0.Action == Action {
32-
.first(reducer)
33-
}
34-
35-
@inlinable
36-
public static func buildEither<R0: ReducerProtocol, R1: ReducerProtocol>(
37-
second reducer: R1
38-
) -> _Conditional<R0, R1>
39-
where R1.State == State, R1.Action == Action {
40-
.second(reducer)
41-
}
42-
43-
@inlinable
44-
public static func buildExpression<R: ReducerProtocol>(_ expression: R) -> R
45-
where R.State == State, R.Action == Action {
46-
expression
47-
}
48-
49-
@inlinable
50-
public static func buildFinalResult<R: ReducerProtocol>(_ reducer: R) -> R
51-
where R.State == State, R.Action == Action {
52-
reducer
53-
}
54-
55-
#if swift(<5.7)
56-
@_disfavoredOverload
10+
#if swift(>=5.7)
5711
@inlinable
58-
public static func buildFinalResult<R: ReducerProtocol>(_ reducer: R) -> Reduce<State, Action>
59-
where R.State == State, R.Action == Action {
60-
Reduce(reducer)
12+
public static func buildArray(
13+
_ reducers: [some ReducerProtocol<State, Action>]
14+
) -> some ReducerProtocol<State, Action> {
15+
_SequenceMany(reducers: reducers)
6116
}
62-
#endif
63-
64-
@inlinable
65-
public static func buildLimitedAvailability<R: ReducerProtocol>(
66-
_ wrapped: R
67-
) -> _Optional<R>
68-
where R.State == State, R.Action == Action {
69-
_Optional(wrapped: wrapped)
70-
}
71-
72-
@inlinable
73-
public static func buildOptional<R: ReducerProtocol>(_ wrapped: R?) -> _Optional<R>
74-
where R.State == State, R.Action == Action {
75-
_Optional(wrapped: wrapped)
76-
}
77-
78-
@inlinable
79-
public static func buildPartialBlock<R: ReducerProtocol>(first: R) -> R
80-
where R.State == State, R.Action == Action {
81-
first
82-
}
83-
84-
@inlinable
85-
public static func buildPartialBlock<R0: ReducerProtocol, R1: ReducerProtocol>(
86-
accumulated: R0, next: R1
87-
) -> _Sequence<R0, R1>
88-
where R0.State == State, R0.Action == Action {
89-
_Sequence(accumulated, next)
90-
}
91-
92-
public enum _Conditional<First: ReducerProtocol, Second: ReducerProtocol>: ReducerProtocol
93-
where
94-
First.State == Second.State,
95-
First.Action == Second.Action
96-
{
97-
case first(First)
98-
case second(Second)
9917

10018
@inlinable
101-
public func reduce(into state: inout First.State, action: First.Action) -> EffectTask<
102-
First.Action
103-
> {
104-
switch self {
105-
case let .first(first):
106-
return first.reduce(into: &state, action: action)
107-
108-
case let .second(second):
109-
return second.reduce(into: &state, action: action)
110-
}
19+
public static func buildBlock() -> some ReducerProtocol<State, Action> {
20+
EmptyReducer()
11121
}
112-
}
11322

114-
public struct _Optional<Wrapped: ReducerProtocol>: ReducerProtocol {
115-
@usableFromInline
116-
let wrapped: Wrapped?
23+
@inlinable
24+
public static func buildBlock(
25+
_ reducer: some ReducerProtocol<State, Action>
26+
) -> some ReducerProtocol<State, Action> {
27+
reducer
28+
}
11729

118-
@usableFromInline
119-
init(wrapped: Wrapped?) {
120-
self.wrapped = wrapped
30+
@inlinable
31+
public static func buildEither<R0: ReducerProtocol, R1: ReducerProtocol>(
32+
first reducer: R0
33+
) -> _Conditional<R0, R1>
34+
where R0.State == State, R0.Action == Action, R1.State == State, R1.Action == Action {
35+
.first(reducer)
12136
}
12237

12338
@inlinable
124-
public func reduce(
125-
into state: inout Wrapped.State, action: Wrapped.Action
126-
) -> EffectTask<Wrapped.Action> {
127-
switch wrapped {
128-
case let .some(wrapped):
129-
return wrapped.reduce(into: &state, action: action)
130-
case .none:
131-
return .none
132-
}
39+
public static func buildEither<R0: ReducerProtocol, R1: ReducerProtocol>(
40+
second reducer: R1
41+
) -> _Conditional<R0, R1>
42+
where R0.State == State, R0.Action == Action, R1.State == State, R1.Action == Action {
43+
.second(reducer)
13344
}
134-
}
13545

136-
public struct _Sequence<R0: ReducerProtocol, R1: ReducerProtocol>: ReducerProtocol
137-
where R0.State == R1.State, R0.Action == R1.Action {
138-
@usableFromInline
139-
let r0: R0
46+
@inlinable
47+
public static func buildExpression(
48+
_ expression: some ReducerProtocol<State, Action>
49+
) -> some ReducerProtocol<State, Action> {
50+
expression
51+
}
14052

141-
@usableFromInline
142-
let r1: R1
53+
@inlinable
54+
public static func buildFinalResult(
55+
_ reducer: some ReducerProtocol<State, Action>
56+
) -> some ReducerProtocol<State, Action> {
57+
reducer
58+
}
14359

144-
@usableFromInline
145-
init(_ r0: R0, _ r1: R1) {
146-
self.r0 = r0
147-
self.r1 = r1
60+
@inlinable
61+
public static func buildLimitedAvailability(
62+
_ wrapped: some ReducerProtocol<State, Action>
63+
) -> Reduce<State, Action> {
64+
Reduce(wrapped)
14865
}
14966

15067
@inlinable
151-
public func reduce(into state: inout R0.State, action: R0.Action) -> EffectTask<R0.Action> {
152-
self.r0.reduce(into: &state, action: action)
153-
.merge(with: self.r1.reduce(into: &state, action: action))
68+
public static func buildOptional(
69+
_ wrapped: (some ReducerProtocol<State, Action>)?
70+
) -> some ReducerProtocol<State, Action> {
71+
wrapped
15472
}
155-
}
15673

157-
public struct _SequenceMany<Element: ReducerProtocol>: ReducerProtocol {
158-
@usableFromInline
159-
let reducers: [Element]
74+
@inlinable
75+
public static func buildPartialBlock(
76+
first: some ReducerProtocol<State, Action>
77+
) -> some ReducerProtocol<State, Action> {
78+
first
79+
}
16080

161-
@usableFromInline
162-
init(reducers: [Element]) {
163-
self.reducers = reducers
81+
@inlinable
82+
public static func buildPartialBlock(
83+
accumulated: some ReducerProtocol<State, Action>, next: some ReducerProtocol<State, Action>
84+
) -> some ReducerProtocol<State, Action> {
85+
_Sequence(accumulated, next)
86+
}
87+
#else
88+
@inlinable
89+
public static func buildArray<R: ReducerProtocol>(_ reducers: [R]) -> _SequenceMany<R>
90+
where R.State == State, R.Action == Action {
91+
_SequenceMany(reducers: reducers)
16492
}
16593

16694
@inlinable
167-
public func reduce(
168-
into state: inout Element.State, action: Element.Action
169-
) -> EffectTask<Element.Action> {
170-
self.reducers.reduce(.none) { $0.merge(with: $1.reduce(into: &state, action: action)) }
95+
public static func buildBlock() -> EmptyReducer<State, Action> {
96+
EmptyReducer()
17197
}
172-
}
173-
}
17498

175-
public typealias ReducerBuilderOf<R: ReducerProtocol> = ReducerBuilder<R.State, R.Action>
99+
@inlinable
100+
public static func buildBlock<R: ReducerProtocol>(_ reducer: R) -> R
101+
where R.State == State, R.Action == Action {
102+
reducer
103+
}
176104

177-
#if swift(<5.7)
178-
extension ReducerBuilder {
179105
@inlinable
180106
public static func buildBlock<
181107
R0: ReducerProtocol,
@@ -403,5 +329,116 @@ public typealias ReducerBuilderOf<R: ReducerProtocol> = ReducerBuilder<R.State,
403329
r9
404330
)
405331
}
332+
333+
@inlinable
334+
public static func buildEither<R0: ReducerProtocol, R1: ReducerProtocol>(
335+
first reducer: R0
336+
) -> _Conditional<R0, R1>
337+
where R0.State == State, R0.Action == Action {
338+
.first(reducer)
339+
}
340+
341+
@inlinable
342+
public static func buildEither<R0: ReducerProtocol, R1: ReducerProtocol>(
343+
second reducer: R1
344+
) -> _Conditional<R0, R1>
345+
where R1.State == State, R1.Action == Action {
346+
.second(reducer)
347+
}
348+
349+
@inlinable
350+
public static func buildExpression<R: ReducerProtocol>(_ expression: R) -> R
351+
where R.State == State, R.Action == Action {
352+
expression
353+
}
354+
355+
@inlinable
356+
public static func buildFinalResult<R: ReducerProtocol>(_ reducer: R) -> R
357+
where R.State == State, R.Action == Action {
358+
reducer
359+
}
360+
361+
@_disfavoredOverload
362+
@inlinable
363+
public static func buildFinalResult<R: ReducerProtocol>(_ reducer: R) -> Reduce<State, Action>
364+
where R.State == State, R.Action == Action {
365+
Reduce(reducer)
366+
}
367+
368+
@inlinable
369+
public static func buildLimitedAvailability<R: ReducerProtocol>(
370+
_ wrapped: R
371+
) -> Reduce<R.State, R.Action>
372+
where R.State == State, R.Action == Action {
373+
Reduce(wrapped)
374+
}
375+
376+
@inlinable
377+
public static func buildOptional<R: ReducerProtocol>(_ wrapped: R?) -> R?
378+
where R.State == State, R.Action == Action {
379+
wrapped
380+
}
381+
#endif
382+
383+
public enum _Conditional<First: ReducerProtocol, Second: ReducerProtocol>: ReducerProtocol
384+
where
385+
First.State == Second.State,
386+
First.Action == Second.Action
387+
{
388+
case first(First)
389+
case second(Second)
390+
391+
@inlinable
392+
public func reduce(into state: inout First.State, action: First.Action) -> EffectTask<
393+
First.Action
394+
> {
395+
switch self {
396+
case let .first(first):
397+
return first.reduce(into: &state, action: action)
398+
399+
case let .second(second):
400+
return second.reduce(into: &state, action: action)
401+
}
402+
}
406403
}
407-
#endif
404+
405+
public struct _Sequence<R0: ReducerProtocol, R1: ReducerProtocol>: ReducerProtocol
406+
where R0.State == R1.State, R0.Action == R1.Action {
407+
@usableFromInline
408+
let r0: R0
409+
410+
@usableFromInline
411+
let r1: R1
412+
413+
@usableFromInline
414+
init(_ r0: R0, _ r1: R1) {
415+
self.r0 = r0
416+
self.r1 = r1
417+
}
418+
419+
@inlinable
420+
public func reduce(into state: inout R0.State, action: R0.Action) -> EffectTask<R0.Action> {
421+
self.r0.reduce(into: &state, action: action)
422+
.merge(with: self.r1.reduce(into: &state, action: action))
423+
}
424+
}
425+
426+
public struct _SequenceMany<Element: ReducerProtocol>: ReducerProtocol {
427+
@usableFromInline
428+
let reducers: [Element]
429+
430+
@usableFromInline
431+
init(reducers: [Element]) {
432+
self.reducers = reducers
433+
}
434+
435+
@inlinable
436+
public func reduce(
437+
into state: inout Element.State, action: Element.Action
438+
) -> EffectTask<Element.Action> {
439+
self.reducers.reduce(.none) { $0.merge(with: $1.reduce(into: &state, action: action)) }
440+
}
441+
}
442+
}
443+
444+
public typealias ReducerBuilderOf<R: ReducerProtocol> = ReducerBuilder<R.State, R.Action>

Sources/ComposableArchitecture/Reducer/Reducers/CombineReducers.swift

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,3 @@ public struct CombineReducers<Reducers: ReducerProtocol>: ReducerProtocol {
4141
self.reducers.reduce(into: &state, action: action)
4242
}
4343
}
44-
45-
#if swift(>=5.7)
46-
extension ReducerProtocol {
47-
// NB: This overload is provided to work around https://github.com/apple/swift/issues/60445
48-
/// Combines multiple reducers into a single reducer.
49-
public func CombineReducers<State, Action>(
50-
@ReducerBuilder<State, Action> _ build: () -> some ReducerProtocol<State, Action>
51-
) -> some ReducerProtocol<State, Action> {
52-
ComposableArchitecture.CombineReducers(build)
53-
}
54-
}
55-
#endif

0 commit comments

Comments
 (0)