Skip to content

Commit 982b424

Browse files
pblazejclaude
andcommitted
Fix #IsolatedConformances warning in subscribeOnMainActor
Swift 6.2 emits `#IsolatedConformances` (SE-0470) when `for try await` runs on `@MainActor`, since the iterator's `AsyncIteratorProtocol` conformance may be MainActor-isolated. Run iteration on `@concurrent` and hop to MainActor per element. Drop the unused stateful overload and its `MainActorStateBox` helper — all call sites use the no-state form. Pre-6.2 keeps the original `@MainActor` body via `#if compiler`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 1bd6e0c commit 982b424

1 file changed

Lines changed: 24 additions & 37 deletions

File tree

Sources/LiveKit/Support/Async/AsyncSequence+Subscribe.swift

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -86,60 +86,47 @@ extension AsyncSequence where Element: Sendable, Self: Sendable {
8686
/// - Parameters:
8787
/// - observer: The observer object (captured weakly).
8888
/// - priority: The priority of the task.
89-
/// - state: The initial mutable state.
9089
/// - onElement: Called for each element on the MainActor.
91-
/// - onFailure: Called when the sequence terminates with an error on the MainActor. Skipped on cancellation.
90+
/// - onFailure: Called when the sequence terminates with an error on the MainActor. Cancellation errors are ignored.
9291
/// - Returns: The task cancellable.
9392
@MainActor
94-
func subscribeOnMainActor<O: AnyObject & Sendable, State: Sendable>(
93+
func subscribeOnMainActor<O: AnyObject & Sendable>(
9594
_ observer: O,
9695
priority: TaskPriority? = nil,
97-
state: State,
98-
onElement: @escaping @MainActor (O, Element, inout State) async -> Void,
99-
onFailure: (@MainActor (O, Error, inout State) async -> Void)? = nil
96+
onElement: @escaping @MainActor (O, Element) async -> Void,
97+
onFailure: (@MainActor (O, Error) async -> Void)? = nil
10098
) -> AnyTaskCancellable {
101-
Task(priority: priority) { @MainActor [weak observer] in
102-
var state = state
99+
// Swift 6.2 emits `#IsolatedConformances` when `for try await` runs on `@MainActor` (SE-0470);
100+
// iterate on `@concurrent` and hop per element. Older toolchains keep the `@MainActor` body.
101+
#if compiler(>=6.2)
102+
return Task(priority: priority) { @concurrent [weak observer] in
103103
do {
104104
for try await element in self {
105105
guard let observer else { break }
106-
await onElement(observer, element, &state)
106+
await onElement(observer, element)
107107
}
108108
} catch {
109109
if error is CancellationError || Task.isCancelled { return }
110110
if let observer, let onFailure {
111-
await onFailure(observer, error, &state)
111+
await onFailure(observer, error)
112112
}
113113
}
114114
}.cancellable()
115-
}
116-
117-
/// Subscribe to an AsyncSequence with a lifecycle tied to an observer on the MainActor.
118-
///
119-
/// The loop automatically terminates if the observer is deallocated.
120-
///
121-
/// - Parameters:
122-
/// - observer: The observer object (captured weakly).
123-
/// - priority: The priority of the task.
124-
/// - onElement: Called for each element on the MainActor.
125-
/// - onFailure: Called when the sequence terminates with an error on the MainActor. Cancellation errors are ignored.
126-
/// - Returns: The task cancellable.
127-
@MainActor
128-
func subscribeOnMainActor<O: AnyObject & Sendable>(
129-
_ observer: O,
130-
priority: TaskPriority? = nil,
131-
onElement: @escaping @MainActor (O, Element) async -> Void,
132-
onFailure: (@MainActor (O, Error) async -> Void)? = nil
133-
) -> AnyTaskCancellable {
134-
subscribeOnMainActor(
135-
observer,
136-
priority: priority,
137-
state: (),
138-
onElement: { observer, element, _ in await onElement(observer, element) },
139-
onFailure: { observer, error, _ in
140-
if let onFailure { await onFailure(observer, error) }
115+
#else
116+
return Task(priority: priority) { @MainActor [weak observer] in
117+
do {
118+
for try await element in self {
119+
guard let observer else { break }
120+
await onElement(observer, element)
121+
}
122+
} catch {
123+
if error is CancellationError || Task.isCancelled { return }
124+
if let observer, let onFailure {
125+
await onFailure(observer, error)
126+
}
141127
}
142-
)
128+
}.cancellable()
129+
#endif
143130
}
144131
}
145132

0 commit comments

Comments
 (0)