Skip to content

Commit 150f350

Browse files
authored
Fix the issue where AtomEffectBuilder fails to demangle witness for the return type of the builder with multiple blocks in iOS 16 (#193)
1 parent a22c7df commit 150f350

File tree

1 file changed

+50
-69
lines changed

1 file changed

+50
-69
lines changed

Sources/Atoms/Effect/AtomEffectBuilder.swift

Lines changed: 50 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,19 @@
1919
@MainActor
2020
@resultBuilder
2121
public enum AtomEffectBuilder {
22+
public static func buildBlock() -> some AtomEffect {
23+
EmptyEffect()
24+
}
25+
2226
public static func buildBlock<Effect: AtomEffect>(_ effect: Effect) -> Effect {
2327
effect
2428
}
2529

26-
public static func buildBlock<each Effect: AtomEffect>(_ effect: repeat each Effect) -> some AtomEffect {
27-
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) {
28-
return BlockEffect(repeat each effect)
29-
}
30-
else {
31-
return BlockBCEffect(repeat each effect)
32-
}
30+
// NB: The combination of variadic type and opaque return type in iOS 16 fails to demangle
31+
// the witness for the return type, which causes a runtime crash.
32+
// Once iOS 16 support is dropped, this function will be changed to return an opaque type.
33+
public static func buildBlock<each Effect: AtomEffect>(_ effect: repeat each Effect) -> BlockEffect {
34+
BlockEffect(repeat each effect)
3335
}
3436

3537
public static func buildIf<Effect: AtomEffect>(_ effect: Effect?) -> some AtomEffect {
@@ -54,6 +56,46 @@ public enum AtomEffectBuilder {
5456
}
5557

5658
public extension AtomEffectBuilder {
59+
// Use type pack once it is available in iOS 17 or newer.
60+
// struct BlockEffect<each Effect: AtomEffect>: AtomEffect
61+
struct BlockEffect: AtomEffect {
62+
private let _initializing: @MainActor (Context) -> Void
63+
private let _initialized: @MainActor (Context) -> Void
64+
private let _updated: @MainActor (Context) -> Void
65+
private let _released: @MainActor (Context) -> Void
66+
67+
internal init<each Effect: AtomEffect>(_ effect: repeat each Effect) {
68+
_initializing = { context in
69+
repeat (each effect).initializing(context: context)
70+
}
71+
_initialized = { context in
72+
repeat (each effect).initialized(context: context)
73+
}
74+
_updated = { context in
75+
repeat (each effect).updated(context: context)
76+
}
77+
_released = { context in
78+
repeat (each effect).released(context: context)
79+
}
80+
}
81+
82+
public func initializing(context: Context) {
83+
_initializing(context)
84+
}
85+
86+
public func initialized(context: Context) {
87+
_initialized(context)
88+
}
89+
90+
public func updated(context: Context) {
91+
_updated(context)
92+
}
93+
94+
public func released(context: Context) {
95+
_released(context)
96+
}
97+
}
98+
5799
struct ConditionalEffect<TrueEffect: AtomEffect, FalseEffect: AtomEffect>: AtomEffect {
58100
internal enum Storage {
59101
case trueEffect(TrueEffect)
@@ -108,68 +150,7 @@ public extension AtomEffectBuilder {
108150
}
109151

110152
private extension AtomEffectBuilder {
111-
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
112-
struct BlockEffect<each Effect: AtomEffect>: AtomEffect {
113-
private let effect: (repeat each Effect)
114-
115-
init(_ effect: repeat each Effect) {
116-
self.effect = (repeat each effect)
117-
}
118-
119-
func initializing(context: Context) {
120-
repeat (each effect).initializing(context: context)
121-
}
122-
123-
func initialized(context: Context) {
124-
repeat (each effect).initialized(context: context)
125-
}
126-
127-
func updated(context: Context) {
128-
repeat (each effect).updated(context: context)
129-
}
130-
131-
func released(context: Context) {
132-
repeat (each effect).released(context: context)
133-
}
134-
}
135-
136-
struct BlockBCEffect: AtomEffect {
137-
private let _initializing: @MainActor (Context) -> Void
138-
private let _initialized: @MainActor (Context) -> Void
139-
private let _updated: @MainActor (Context) -> Void
140-
private let _released: @MainActor (Context) -> Void
141-
142-
init<each Effect: AtomEffect>(_ effect: repeat each Effect) {
143-
_initializing = { context in
144-
repeat (each effect).initializing(context: context)
145-
}
146-
_initialized = { context in
147-
repeat (each effect).initialized(context: context)
148-
}
149-
_updated = { context in
150-
repeat (each effect).updated(context: context)
151-
}
152-
_released = { context in
153-
repeat (each effect).released(context: context)
154-
}
155-
}
156-
157-
func initializing(context: Context) {
158-
_initializing(context)
159-
}
160-
161-
func initialized(context: Context) {
162-
_initialized(context)
163-
}
164-
165-
func updated(context: Context) {
166-
_updated(context)
167-
}
168-
169-
func released(context: Context) {
170-
_released(context)
171-
}
172-
}
153+
struct EmptyEffect: AtomEffect {}
173154

174155
struct IfEffect<Effect: AtomEffect>: AtomEffect {
175156
private let effect: Effect?

0 commit comments

Comments
 (0)