Skip to content

Commit 3dd83c1

Browse files
stephencelisp4checo
authored andcommitted
Fix bad buildFinalResult warning on Swift 5.7 (#1467)
(cherry picked from commit e6fe82cfe1ecbebaaae924a67a4a7562b6449f22)
1 parent e996500 commit 3dd83c1

File tree

4 files changed

+324
-196
lines changed

4 files changed

+324
-196
lines changed

Sources/ComposableArchitecture/Reducer/Reducers/ForEachReducer.swift

Lines changed: 93 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,97 @@
11
extension ReducerProtocol {
2-
/// Embeds a child reducer in a parent domain that works on elements of a collection in parent
3-
/// state.
4-
///
5-
/// For example, if a parent feature holds onto an array of child states, then it can
6-
/// perform its core logic _and_ the child's logic by using the `forEach` operator:
7-
///
8-
/// ```swift
9-
/// struct Parent: ReducerProtocol {
10-
/// struct State {
11-
/// var rows: IdentifiedArrayOf<Row.State>
12-
/// // ...
13-
/// }
14-
/// enum Action {
15-
/// case row(id: Row.State.ID, action: Row.Action)
16-
/// // ...
17-
/// }
18-
///
19-
/// var body: some ReducerProtocol<State, Action> {
20-
/// Reduce { state, action in
21-
/// // Core logic for parent feature
22-
/// }
23-
/// .forEach(\.rows, action: /Action.row) {
24-
/// Row()
25-
/// }
26-
/// }
27-
/// }
28-
/// ```
29-
///
30-
/// > Tip: We are using `IdentifiedArray` from our
31-
/// [Identified Collections][swift-identified-collections] library because it provides a safe and
32-
/// ergonomic API for accessing elements from a stable ID rather than positional indices.
33-
///
34-
/// The `forEach` forces a specific order of operations for the child and parent features. It runs
35-
/// the child first, and then the parent. If the order was reversed, then it would be possible for
36-
/// the parent feature to remove the child state from the array, in which case the child feature
37-
/// would not be able to react to that action. That can cause subtle bugs.
38-
///
39-
/// It is still possible for a parent feature higher up in the application to remove the child
40-
/// state from the array before the child has a chance to react to the action. In such cases a
41-
/// runtime warning is shown in Xcode to let you know that there's a potential problem.
42-
///
43-
/// [swift-identified-collections]: http://github.com/pointfreeco/swift-identified-collections
44-
///
45-
/// - Parameters:
46-
/// - toElementsState: A writable key path from parent state to an `IdentifiedArray` of child
47-
/// state.
48-
/// - toElementAction: A case path from parent action to child identifier and child actions.
49-
/// - element: A reducer that will be invoked with child actions against elements of child
50-
/// state.
51-
/// - Returns: A reducer that combines the child reducer with the parent reducer.
52-
@inlinable
53-
public func forEach<ID: Hashable, Element: ReducerProtocol>(
54-
_ toElementsState: WritableKeyPath<State, IdentifiedArray<ID, Element.State>>,
55-
action toElementAction: CasePath<Action, (ID, Element.Action)>,
56-
@ReducerBuilderOf<Element> _ element: () -> Element,
57-
file: StaticString = #file,
58-
fileID: StaticString = #fileID,
59-
line: UInt = #line
60-
) -> _ForEachReducer<Self, ID, Element> {
61-
_ForEachReducer(
62-
parent: self,
63-
toElementsState: toElementsState,
64-
toElementAction: toElementAction,
65-
element: element(),
66-
file: file,
67-
fileID: fileID,
68-
line: line
69-
)
70-
}
2+
#if swift(>=5.7)
3+
/// Embeds a child reducer in a parent domain that works on elements of a collection in parent
4+
/// state.
5+
///
6+
/// For example, if a parent feature holds onto an array of child states, then it can perform
7+
/// its core logic _and_ the child's logic by using the `forEach` operator:
8+
///
9+
/// ```swift
10+
/// struct Parent: ReducerProtocol {
11+
/// struct State {
12+
/// var rows: IdentifiedArrayOf<Row.State>
13+
/// // ...
14+
/// }
15+
/// enum Action {
16+
/// case row(id: Row.State.ID, action: Row.Action)
17+
/// // ...
18+
/// }
19+
///
20+
/// var body: some ReducerProtocol<State, Action> {
21+
/// Reduce { state, action in
22+
/// // Core logic for parent feature
23+
/// }
24+
/// .forEach(\.rows, action: /Action.row) {
25+
/// Row()
26+
/// }
27+
/// }
28+
/// }
29+
/// ```
30+
///
31+
/// > Tip: We are using `IdentifiedArray` from our
32+
/// [Identified Collections][swift-identified-collections] library because it provides a safe
33+
/// and ergonomic API for accessing elements from a stable ID rather than positional indices.
34+
///
35+
/// The `forEach` forces a specific order of operations for the child and parent features. It
36+
/// runs the child first, and then the parent. If the order was reversed, then it would be
37+
/// possible for the parent feature to remove the child state from the array, in which case the
38+
/// child feature would not be able to react to that action. That can cause subtle bugs.
39+
///
40+
/// It is still possible for a parent feature higher up in the application to remove the child
41+
/// state from the array before the child has a chance to react to the action. In such cases a
42+
/// runtime warning is shown in Xcode to let you know that there's a potential problem.
43+
///
44+
/// [swift-identified-collections]: http://github.com/pointfreeco/swift-identified-collections
45+
///
46+
/// - Parameters:
47+
/// - toElementsState: A writable key path from parent state to an `IdentifiedArray` of child
48+
/// state.
49+
/// - toElementAction: A case path from parent action to child identifier and child actions.
50+
/// - element: A reducer that will be invoked with child actions against elements of child
51+
/// state.
52+
/// - Returns: A reducer that combines the child reducer with the parent reducer.
53+
@inlinable
54+
public func forEach<ID: Hashable, ElementState, ElementAction>(
55+
_ toElementsState: WritableKeyPath<State, IdentifiedArray<ID, ElementState>>,
56+
action toElementAction: CasePath<Action, (ID, ElementAction)>,
57+
@ReducerBuilder<ElementState, ElementAction> _ element: () -> some ReducerProtocol<
58+
ElementState, ElementAction
59+
>,
60+
file: StaticString = #file,
61+
fileID: StaticString = #fileID,
62+
line: UInt = #line
63+
) -> some ReducerProtocol<State, Action> {
64+
_ForEachReducer(
65+
parent: self,
66+
toElementsState: toElementsState,
67+
toElementAction: toElementAction,
68+
element: element(),
69+
file: file,
70+
fileID: fileID,
71+
line: line
72+
)
73+
}
74+
#else
75+
@inlinable
76+
public func forEach<ID: Hashable, Element: ReducerProtocol>(
77+
_ toElementsState: WritableKeyPath<State, IdentifiedArray<ID, Element.State>>,
78+
action toElementAction: CasePath<Action, (ID, Element.Action)>,
79+
@ReducerBuilderOf<Element> _ element: () -> Element,
80+
file: StaticString = #file,
81+
fileID: StaticString = #fileID,
82+
line: UInt = #line
83+
) -> _ForEachReducer<Self, ID, Element> {
84+
_ForEachReducer(
85+
parent: self,
86+
toElementsState: toElementsState,
87+
toElementAction: toElementAction,
88+
element: element(),
89+
file: file,
90+
fileID: fileID,
91+
line: line
92+
)
93+
}
94+
#endif
7195
}
7296

7397
public struct _ForEachReducer<

Sources/ComposableArchitecture/Reducer/Reducers/IfCaseLetReducer.swift

Lines changed: 87 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,91 @@
11
extension ReducerProtocol {
2-
/// Embeds a child reducer in a parent domain that works on a case of parent enum state.
3-
///
4-
/// For example, if a parent feature's state is expressed as an enum of multiple children states,
5-
/// then `ifCaseLet` can run a child reducer on a particular case of the enum:
6-
///
7-
/// ```swift
8-
/// struct Parent: ReducerProtocol {
9-
/// enum State {
10-
/// case loggedIn(Authenticated.State)
11-
/// case loggedOut(Unauthenticated.State)
12-
/// }
13-
/// enum Action {
14-
/// case loggedIn(Authenticated.Action)
15-
/// case loggedOut(Unauthenticated.Action)
16-
/// // ...
17-
/// }
18-
///
19-
/// var body: some ReducerProtocol<State, Action> {
20-
/// Reduce { state, action in
21-
/// // Core logic for parent feature
22-
/// }
23-
/// .ifCaseLet(/State.loggedIn, action: /Action.loggedIn) {
24-
/// Authenticated()
25-
/// }
26-
/// .ifCaseLet(/State.loggedOut, action: /Action.loggedOut) {
27-
/// Unauthenticated()
28-
/// }
29-
/// }
30-
/// }
31-
/// ```
32-
///
33-
/// The `ifCaseLet` forces a specific order of operations for the child and parent features. It
34-
/// runs the child first, and then the parent. If the order was reversed, then it would be
35-
/// possible for the parent feature to change the case of the enum, in which case the child
36-
/// feature would not be able to react to that action. That can cause subtle bugs.
37-
///
38-
/// It is still possible for a parent feature higher up in the application to change the case of
39-
/// the enum before the child has a chance to react to the action. In such cases a runtime warning
40-
/// is shown in Xcode to let you know that there's a potential problem.
41-
///
42-
/// - Parameters:
43-
/// - toCaseState: A case path from parent state to a case containing child state.
44-
/// - toCaseAction: A case path from parent action to a case containing child actions.
45-
/// - case: A reducer that will be invoked with child actions against child state when it is
46-
/// present
47-
/// - Returns: A reducer that combines the child reducer with the parent reducer.
48-
@inlinable
49-
public func ifCaseLet<Case: ReducerProtocol>(
50-
_ toCaseState: CasePath<State, Case.State>,
51-
action toCaseAction: CasePath<Action, Case.Action>,
52-
@ReducerBuilderOf<Case> then case: () -> Case,
53-
file: StaticString = #file,
54-
fileID: StaticString = #fileID,
55-
line: UInt = #line
56-
) -> _IfCaseLetReducer<Self, Case> {
57-
.init(
58-
parent: self,
59-
child: `case`(),
60-
toChildState: toCaseState,
61-
toChildAction: toCaseAction,
62-
file: file,
63-
fileID: fileID,
64-
line: line
65-
)
66-
}
2+
#if swift(>=5.7)
3+
/// Embeds a child reducer in a parent domain that works on a case of parent enum state.
4+
///
5+
/// For example, if a parent feature's state is expressed as an enum of multiple children
6+
/// states, then `ifCaseLet` can run a child reducer on a particular case of the enum:
7+
///
8+
/// ```swift
9+
/// struct Parent: ReducerProtocol {
10+
/// enum State {
11+
/// case loggedIn(Authenticated.State)
12+
/// case loggedOut(Unauthenticated.State)
13+
/// }
14+
/// enum Action {
15+
/// case loggedIn(Authenticated.Action)
16+
/// case loggedOut(Unauthenticated.Action)
17+
/// // ...
18+
/// }
19+
///
20+
/// var body: some ReducerProtocol<State, Action> {
21+
/// Reduce { state, action in
22+
/// // Core logic for parent feature
23+
/// }
24+
/// .ifCaseLet(/State.loggedIn, action: /Action.loggedIn) {
25+
/// Authenticated()
26+
/// }
27+
/// .ifCaseLet(/State.loggedOut, action: /Action.loggedOut) {
28+
/// Unauthenticated()
29+
/// }
30+
/// }
31+
/// }
32+
/// ```
33+
///
34+
/// The `ifCaseLet` forces a specific order of operations for the child and parent features. It
35+
/// runs the child first, and then the parent. If the order was reversed, then it would be
36+
/// possible for the parent feature to change the case of the enum, in which case the child
37+
/// feature would not be able to react to that action. That can cause subtle bugs.
38+
///
39+
/// It is still possible for a parent feature higher up in the application to change the case of
40+
/// the enum before the child has a chance to react to the action. In such cases a runtime
41+
/// warning is shown in Xcode to let you know that there's a potential problem.
42+
///
43+
/// - Parameters:
44+
/// - toCaseState: A case path from parent state to a case containing child state.
45+
/// - toCaseAction: A case path from parent action to a case containing child actions.
46+
/// - case: A reducer that will be invoked with child actions against child state when it is
47+
/// present
48+
/// - Returns: A reducer that combines the child reducer with the parent reducer.
49+
@inlinable
50+
public func ifCaseLet<CaseState, CaseAction>(
51+
_ toCaseState: CasePath<State, CaseState>,
52+
action toCaseAction: CasePath<Action, CaseAction>,
53+
@ReducerBuilder<CaseState, CaseAction> then case: () -> some ReducerProtocol<CaseState, CaseAction>,
54+
file: StaticString = #file,
55+
fileID: StaticString = #fileID,
56+
line: UInt = #line
57+
) -> some ReducerProtocol<State, Action> {
58+
_IfCaseLetReducer(
59+
parent: self,
60+
child: `case`(),
61+
toChildState: toCaseState,
62+
toChildAction: toCaseAction,
63+
file: file,
64+
fileID: fileID,
65+
line: line
66+
)
67+
}
68+
#else
69+
@inlinable
70+
public func ifCaseLet<Case: ReducerProtocol>(
71+
_ toCaseState: CasePath<State, Case.State>,
72+
action toCaseAction: CasePath<Action, Case.Action>,
73+
@ReducerBuilderOf<Case> then case: () -> Case,
74+
file: StaticString = #file,
75+
fileID: StaticString = #fileID,
76+
line: UInt = #line
77+
) -> _IfCaseLetReducer<Self, Case> {
78+
.init(
79+
parent: self,
80+
child: `case`(),
81+
toChildState: toCaseState,
82+
toChildAction: toCaseAction,
83+
file: file,
84+
fileID: fileID,
85+
line: line
86+
)
87+
}
88+
#endif
6789
}
6890

6991
public struct _IfCaseLetReducer<Parent: ReducerProtocol, Child: ReducerProtocol>: ReducerProtocol {

0 commit comments

Comments
 (0)