Conversation
📝 WalkthroughWalkthroughAdds a Swift 6 strict-concurrency skill package: one skill definition and four new reference guides covering actors, async sequences, Sendable, and structured concurrency, including patterns, triage rules, and verification checklists. Changes
Sequence Diagram(s)(omitted) Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@skills/swift-concurrency/references/actors.md`:
- Around line 171-188: The markdown code block opened for the Swift examples
(showing DispatchQueue.main.async, await MainActor.run, and the `@MainActor` func
updateUI()) is missing a closing triple-backtick, which breaks the document
structure; fix it by adding a closing ``` immediately after the updateUI()
function example so the code fence is properly closed before the "### Custom
global actor" heading (locate the block containing DispatchQueue.main.async,
MainActor.run, and updateUI to insert the closing fence).
- Around line 21-31: The actor example assigns to a non-existent property
currentUserId in methods logIn and logOut while the declared property is userId;
update logIn and logOut to set userId (and leave or add any intended
isAuthenticated handling consistently) so the code compiles, and also add a
closing code fence after the block ending at line 187 to fix the broken Markdown
rendering.
In `@skills/swift-concurrency/references/async-sequences.md`:
- Around line 113-133: The AsyncThrowingStream builder closure is synchronous so
you must not call await directly; wrap any async work (e.g., calls to fetch) in
a child Task (or Task.detached) inside the AsyncThrowingStream initializer and
perform continuation.yield / continuation.finish(throwing:) from that Task;
similarly, move defer { continuation.finish() } into the Task or ensure every
async exit path calls continuation.finish()/finish(throwing:) from the Task
context to guarantee proper completion while avoiding await in the outer
(Continuation) -> Void closure.
In `@skills/swift-concurrency/references/structured-concurrency.md`:
- Around line 185-196: The onCancel closure in your withTaskCancellationHandler
cannot see the local request declared inside withCheckedThrowingContinuation;
move the request declaration to an outer scope (e.g., var request:
URLSessionDataTask? before calling withCheckedThrowingContinuation), assign the
task to that variable inside the continuation block, and then call
request?.cancel() in the onCancel handler so the legacy data task can be
cancelled safely; ensure continuation resumes only once and consider clearing
request after resume to avoid leaks.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 380244de-a9ed-45d0-9bf2-b4ad041d3811
📒 Files selected for processing (5)
skills/swift-concurrency/SKILL.mdskills/swift-concurrency/references/actors.mdskills/swift-concurrency/references/async-sequences.mdskills/swift-concurrency/references/sendability.mdskills/swift-concurrency/references/structured-concurrency.md
ducbm051291
left a comment
There was a problem hiding this comment.
Please check and resolve coderabittai comments
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@skills/swift-concurrency/references/structured-concurrency.md`:
- Around line 185-197: The code mutates and reads the shared variable `request`
from both the operation passed to `withTaskCancellationHandler` and the
`onCancel` closure, which can run concurrently; to fix it make access to
`request` concurrency-safe by moving it into a synchronization boundary (for
example an actor or a simple lock/Mutex) and use that boundary from both
`withCheckedThrowingContinuation` (the operation that calls
`legacySession.dataTask`) and the `onCancel` closure so reads/writes to
`request` are serialized; update references to `request`,
`withTaskCancellationHandler`, `onCancel`, and `withCheckedThrowingContinuation`
accordingly so cancellation calls `cancel()` via the synchronized container.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: afdc34d0-ebcf-4d38-9c8f-9fca8eb4883b
📒 Files selected for processing (3)
skills/swift-concurrency/references/actors.mdskills/swift-concurrency/references/async-sequences.mdskills/swift-concurrency/references/structured-concurrency.md
| var request: URLSessionDataTask? | ||
| try await withTaskCancellationHandler { | ||
| try await withCheckedThrowingContinuation { continuation in | ||
| request = legacySession.dataTask(with: url) { data, _, error in | ||
| if let data { continuation.resume(returning: data) } | ||
| else { continuation.resume(throwing: error ?? URLError(.unknown)) } | ||
| } | ||
| request?.resume() | ||
| } | ||
| } onCancel: { | ||
| // Called synchronously on cancellation | ||
| request?.cancel() // Cancel the legacy task | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Swift 6 withTaskCancellationHandler captured var in operation and onCancel closure data race diagnostic
💡 Result:
In Swift 6's strict concurrency checking, using withTaskCancellationHandler(operation:onCancel:isolation:) can trigger data race diagnostics when the onCancel closure (which is @Sendable -> Void) captures mutable variables (var) from the surrounding scope. This is because the cancellation handler may execute concurrently with the operation closure, as explicitly noted in Apple's official documentation: "This onCancel closure might execute concurrently with the operation." The diagnostic is typically "Reference to captured var in concurrently-executing code" or a variant like "Capture of 'X' with non-sendable type in a @Sendable closure", enforced in Swift 6 language mode. Swift prevents mutable state from being shared unsafely across concurrency domains. To resolve: - Change captured var to let if immutable after capture. - Use explicit capture lists to shadow with let, e.g., onCancel: { [weak capturedVar] in ... }. - Ensure captured types conform to Sendable if shared. - Use actor isolation or restructure to avoid sharing mutable state. Official docs confirm the concurrent execution model (source 1). General diagnostics for captured vars in concurrent closures are documented across sources, including fixes via capture lists (sources 7,15,23). No specific open bug for this exact diagnostic in withTaskCancellationHandler, but it aligns with region-based isolation checks.
Citations:
- 1: https://developer.apple.com/documentation/swift/withtaskcancellationhandler(operation:oncancel:isolation:)
- 2: False positive data races in TSAN with task cancellation handler onCancel swiftlang/swift#59068
- 3: https://forums.swift.org/t/swift-6-withtaskcancellationhandler-withcheckedcontinuation/74083
- 4: https://www.donnywals.com/solving-reference-to-captured-var-in-concurrently-executing-code-in-swift/
- 5: https://stackoverflow.com/questions/78649298/swift-6-capture-of-self-with-non-sendable-type-in-a-sendable-closure
- 6: https://stackoverflow.com/questions/78835480/concurrency-reference-to-captured-var-in-concurrently-executing-code
🏁 Script executed:
# Verify the file exists and check the exact lines mentioned
file_path="skills/swift-concurrency/references/structured-concurrency.md"
if [ -f "$file_path" ]; then
echo "=== File exists. Checking line range 185-197 ==="
sed -n '180,200p' "$file_path" | cat -n
else
echo "File not found at: $file_path"
# Try to find similar files
find . -name "*structured-concurrency*" -type f 2>/dev/null | head -20
fiRepository: nimblehq/ios-templates
Length of output: 966
🏁 Script executed:
# Check broader context around the code section (more lines before and after)
file_path="skills/swift-concurrency/references/structured-concurrency.md"
echo "=== Context: Lines 170-210 ==="
sed -n '170,210p' "$file_path" | cat -nRepository: nimblehq/ios-templates
Length of output: 1620
Avoid unsynchronized mutable capture between operation and onCancel closures.
request is mutated in the operation closure and read in onCancel; in Swift 6 strict concurrency this pattern triggers captured-mutable-state data-race diagnostics. Per Apple's documentation, the onCancel closure may execute concurrently with the operation. Wrap this shared state with a synchronization primitive (e.g., Mutex) or another concurrency-safe container.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/swift-concurrency/references/structured-concurrency.md` around lines
185 - 197, The code mutates and reads the shared variable `request` from both
the operation passed to `withTaskCancellationHandler` and the `onCancel`
closure, which can run concurrently; to fix it make access to `request`
concurrency-safe by moving it into a synchronization boundary (for example an
actor or a simple lock/Mutex) and use that boundary from both
`withCheckedThrowingContinuation` (the operation that calls
`legacySession.dataTask`) and the `onCancel` closure so reads/writes to
`request` are serialized; update references to `request`,
`withTaskCancellationHandler`, `onCancel`, and `withCheckedThrowingContinuation`
accordingly so cancellation calls `cancel()` via the synchronized container.
67dec10 to
f3a952d
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
skills/swift-concurrency/references/structured-concurrency.md (1)
185-197:⚠️ Potential issue | 🟠 MajorAvoid mutable shared capture between operation and
onCancel.Line 185’s
requestis mutated in the operation closure and accessed inonCancel; in Swift 6 this can be flagged as unsafe concurrent capture. Store/cancel through a synchronization boundary (e.g.,Mutexor actor wrapper).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/swift-concurrency/references/structured-concurrency.md` around lines 185 - 197, The closure captures and mutates the local var `request` in the operation passed to `withTaskCancellationHandler` while `onCancel` reads/calls `request?.cancel()`, which creates an unsafe concurrent capture in Swift 6; fix by introducing a synchronization boundary (e.g., wrap access to the task in a small actor or Mutex) and use that wrapper from both the `withCheckedThrowingContinuation` body (where you assign the result of `legacySession.dataTask`) and the `onCancel` closure (where you call `cancel()`), keeping `request` itself non-mutated outside the actor/Mutex and referencing the actor/Mutex methods instead in `withTaskCancellationHandler`/`onCancel`.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@skills/swift-concurrency/references/actors.md`:
- Around line 103-106: Update the rule for nonisolated to emphasize access
restrictions rather than type constraints: state that nonisolated members
(computed properties and methods) must not access any actor-isolated state and
may only use nonisolated/static data or values captured/created locally; mention
that reading a Sendable value does not by itself make access to isolated state
safe, and keep the existing notes that nonisolated is safe for let stored
properties but never allowed on var stored properties (compiler rejects it).
In `@skills/swift-concurrency/references/async-sequences.md`:
- Around line 164-165: Update the sentence that says "`@Sendable` is required"
to a softer, conditional recommendation: explain that the `onTermination`
closure is already declared `@Sendable` in the API type signature and that
explicitly adding `@Sendable` on the closure is recommended only when the
compiler cannot infer it (or emits a warning), rather than being strictly
required; reference the `onTermination` parameter and the `@Sendable` annotation
in this wording so readers can locate the API signature and understand when to
add the annotation.
In `@skills/swift-concurrency/references/structured-concurrency.md`:
- Around line 88-91: The async sequence iteration is using a synchronous for
loop which bypasses async backpressure; in the withDiscardingTaskGroup closure
replace the plain "for event in eventStream" with an asynchronous iteration "for
await event in eventStream" so each element is awaited before scheduling
group.addTask { await process(event) }, ensuring correct bounded concurrency for
eventStream and preserving the intended behavior of withDiscardingTaskGroup and
process(event).
---
Duplicate comments:
In `@skills/swift-concurrency/references/structured-concurrency.md`:
- Around line 185-197: The closure captures and mutates the local var `request`
in the operation passed to `withTaskCancellationHandler` while `onCancel`
reads/calls `request?.cancel()`, which creates an unsafe concurrent capture in
Swift 6; fix by introducing a synchronization boundary (e.g., wrap access to the
task in a small actor or Mutex) and use that wrapper from both the
`withCheckedThrowingContinuation` body (where you assign the result of
`legacySession.dataTask`) and the `onCancel` closure (where you call
`cancel()`), keeping `request` itself non-mutated outside the actor/Mutex and
referencing the actor/Mutex methods instead in
`withTaskCancellationHandler`/`onCancel`.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 30cdd27f-b80d-4d2e-a45b-7d004f427e0a
📒 Files selected for processing (5)
skills/swift-concurrency/SKILL.mdskills/swift-concurrency/references/actors.mdskills/swift-concurrency/references/async-sequences.mdskills/swift-concurrency/references/sendability.mdskills/swift-concurrency/references/structured-concurrency.md
| Rules for `nonisolated`: | ||
| - Safe on `let` stored properties (immutable — no data race possible). | ||
| - Safe on computed properties and methods that only read immutable or `Sendable` values. | ||
| - **Never** apply `nonisolated` to a `var` stored property — the compiler will reject it. |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's verify the exact content at the specified lines
head -120 skills/swift-concurrency/references/actors.md | tail -25Repository: nimblehq/ios-templates
Length of output: 943
🌐 Web query:
Swift nonisolated Sendable actor isolation semantics rules
💡 Result:
In Swift concurrency, actors provide isolation for their mutable state. By default, all instance members (methods, properties, subscripts) of an actor are isolated to that actor, meaning they execute on the actor's executor and can access isolated state synchronously. The nonisolated keyword opts out of this isolation for actor members, making them synchronously callable from any context without hopping to the actor's executor. Nonisolated members cannot synchronously access the actor's isolated state (e.g., other isolated properties or methods); attempts to do so result in compiler errors. Key semantics and rules for nonisolated in actors: - Access to state: Nonisolated members can only reference nonisolated state or global/nonisolated data. Accessing isolated self members requires await. Examples include nonisolated let properties (immutable, safe to share) or computed properties based solely on nonisolated data. - Sendable requirements: Since nonisolated members can be called concurrently from multiple isolation domains (e.g., different actors or nonisolated contexts), all types used within them (parameters, return types, captured values in closures) must conform to Sendable. The compiler enforces this to prevent data races. Non-Sendable types in nonisolated contexts trigger errors like "Sending 'nonSendable' risks causing data races". - nonisolated(unsafe): Allows synchronous access to isolated state from nonisolated contexts, bypassing safety checks. Use only when you manually ensure thread-safety (e.g., no data races). This opts out of compiler enforcement, similar to @unchecked Sendable. - Protocol conformance: Nonisolated members enable actors to conform to synchronous protocols (e.g., Hashable, CustomStringConvertible) by implementing requirements using only nonisolated state. - Stored properties: - nonisolated let of Sendable type: Safe, accessible synchronously from anywhere. - nonisolated var: Allowed if Sendable; for global-actor-isolated value types (e.g., @MainActor struct), nonisolated inference applies within-module for Sendable vars without (unsafe). - Non-Sendable stored properties cannot be nonisolated unless the enclosing type ensures exclusive access. - Functions/closures: Nonisolated functions in actors are synchronous by default unless async. @Sendable may be inferred or required for escaping closures. In Swift 6+, region-based isolation (SE-0414) refines checks for safe non-Sendable passing if no overlapping lifetimes. Examples: actor Counter { private var value = 0 // isolated nonisolated let id: Int // OK: immutable Sendable nonisolated func getId -> Int { id } // OK: uses nonisolated state nonisolated(unsafe) var unsafeValue: Int { value } // Unsafe: bypasses isolation } These rules (from SE-0306, SE-0313) ensure nonisolated access is safe when state is immutable/Sendable, while isolated access protects mutable state. Prioritize official Swift Evolution proposals and Apple docs for latest details, as concurrency evolves (e.g., Swift 6.2 introduces nonisolated(nonsending) defaults).
Citations:
- 1: https://developer.apple.com/documentation/Swift/Sendable
- 2: https://github.com/apple/swift-evolution/blob/b62b35d3ac173ae0010767c8b18e8fd3225e31a9/proposals/nnnn-actors.md
- 3: https://github.com/apple/swift-evolution/blob/main/proposals/0306-actors.md
- 4: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0306-actors.md
- 5: https://github.com/apple/swift-evolution/blob/main/proposals/0313-actor-isolation-control.md
- 6: https://github.com/apple/swift-evolution/blob/main/proposals/0434-global-actor-isolated-types-usability.md
- 7: https://avanderlee.com/swift/nonisolated-isolated
- 8: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0313-actor-isolation-control.md
Clarify nonisolated rule for computed properties and methods to avoid Sendable-only misinterpretation.
The current wording "only read immutable or Sendable values" focuses on type constraints but obscures the core safety rule. The fundamental requirement is that nonisolated members must not access actor-isolated state at all—they can only use nonisolated or static data. Clarifying this prevents readers from incorrectly thinking that merely reading Sendable values is sufficient for nonisolated safety.
Suggested wording
-- Safe on computed properties and methods that only read immutable or `Sendable` values.
+- Safe on computed properties and methods that do not access actor-isolated stored state (they may use only nonisolated/static data).📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Rules for `nonisolated`: | |
| - Safe on `let` stored properties (immutable — no data race possible). | |
| - Safe on computed properties and methods that only read immutable or `Sendable` values. | |
| - **Never** apply `nonisolated` to a `var` stored property — the compiler will reject it. | |
| Rules for `nonisolated`: | |
| - Safe on `let` stored properties (immutable — no data race possible). | |
| - Safe on computed properties and methods that do not access actor-isolated stored state (they may use only nonisolated/static data). | |
| - **Never** apply `nonisolated` to a `var` stored property — the compiler will reject it. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/swift-concurrency/references/actors.md` around lines 103 - 106, Update
the rule for nonisolated to emphasize access restrictions rather than type
constraints: state that nonisolated members (computed properties and methods)
must not access any actor-isolated state and may only use nonisolated/static
data or values captured/created locally; mention that reading a Sendable value
does not by itself make access to isolated state safe, and keep the existing
notes that nonisolated is safe for let stored properties but never allowed on
var stored properties (compiler rejects it).
| The `@Sendable` annotation on the closure is required because `onTermination` can be called from any concurrency domain. | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate and read the file at the specified lines
fd -e md -path "*async-sequences.md"Repository: nimblehq/ios-templates
Length of output: 234
🏁 Script executed:
# Read lines 160-170 to get context around line 164-165
sed -n '160,170p' "skills/swift-concurrency/references/async-sequences.md"Repository: nimblehq/ios-templates
Length of output: 378
🌐 Web query:
Swift AsyncStream.Continuation.onTermination closure Sendable annotation API
💡 Result:
The onTermination property of Swift.AsyncStream.Continuation is declared as: var onTermination: (@Sendable (AsyncStream.Continuation.Termination) -> Void)? { get nonmutating set } This API requires the closure assigned to onTermination to conform to the @Sendable protocol, meaning it must be safe to call from any concurrency domain (actor-isolated or non-isolated context). The @Sendable annotation ensures thread-safety for the callback, which is invoked when the stream iteration is cancelled or finished. The same applies to AsyncThrowingStream.Continuation.onTermination: var onTermination: (@Sendable (AsyncThrowingStream<Element, Failure>.Continuation.Termination) -> Void)? { get nonmutating set } When assigning a closure, if the compiler warns about converting a non-concurrent closure to @Sendable, use @Sendable in the closure signature, e.g.: continuation.onTermination = { @Sendable termination in // Handle .finished or .cancelled } This is the official API design for cleanup during stream termination, as documented in Apple's Swift documentation (current as of 2026).
Citations:
- 1: https://developer.apple.com/documentation/swift/asyncstream/continuation
- 2: https://developer.apple.com/documentation/swift/asyncstream/continuation/ontermination
- 3: https://developer.apple.com/documentation/swift/asyncthrowingstream/continuation/ontermination
- 4: https://developer.apple.com/documentation/swift/asyncthrowingstream
- 5: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0314-async-stream.md
Soften "required" to "recommended for clarity" in the @Sendable explanation.
Line 164 incorrectly states the @Sendable annotation is required, but the onTermination closure parameter is already declared as @Sendable in the API type signature. Explicit annotation is only necessary if the compiler warns about type inference, not unconditionally. Suggest updating to reflect this conditional nature:
Suggested wording
-The `@Sendable` annotation on the closure is required because `onTermination` can be called from any concurrency domain.
+`onTermination` closures are `@Sendable` (explicit annotation is recommended for clarity) because they can be called from any concurrency domain.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| The `@Sendable` annotation on the closure is required because `onTermination` can be called from any concurrency domain. | |
| `onTermination` closures are `@Sendable` (explicit annotation is recommended for clarity) because they can be called from any concurrency domain. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/swift-concurrency/references/async-sequences.md` around lines 164 -
165, Update the sentence that says "`@Sendable` is required" to a softer,
conditional recommendation: explain that the `onTermination` closure is already
declared `@Sendable` in the API type signature and that explicitly adding
`@Sendable` on the closure is recommended only when the compiler cannot infer it
(or emits a warning), rather than being strictly required; reference the
`onTermination` parameter and the `@Sendable` annotation in this wording so
readers can locate the API signature and understand when to add the annotation.
| await withDiscardingTaskGroup { group in | ||
| for event in eventStream { | ||
| group.addTask { await process(event) } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n skills/swift-concurrency/references/structured-concurrency.md | sed -n '80,100p'Repository: nimblehq/ios-templates
Length of output: 892
🏁 Script executed:
cat -n skills/swift-concurrency/references/structured-concurrency.md | head -90 | tail -40Repository: nimblehq/ios-templates
Length of output: 1415
🏁 Script executed:
grep -n "eventStream" skills/swift-concurrency/references/structured-concurrency.mdRepository: nimblehq/ios-templates
Length of output: 99
🏁 Script executed:
cat -n skills/swift-concurrency/references/structured-concurrency.md | sed -n '83,110p'Repository: nimblehq/ios-templates
Length of output: 1030
🏁 Script executed:
cat -n skills/swift-concurrency/references/structured-concurrency.md | head -1
wc -l skills/swift-concurrency/references/structured-concurrency.mdRepository: nimblehq/ios-templates
Length of output: 163
🏁 Script executed:
cat skills/swift-concurrency/references/structured-concurrency.mdRepository: nimblehq/ios-templates
Length of output: 7364
🌐 Web query:
Swift AsyncSequence for await syntax requirements
💡 Result:
To use the for await-in syntax with Swift's AsyncSequence, a type must conform to the AsyncSequence protocol. This requires: 1. Defining an associated type Element for the type of values produced. 2. Defining an associated type AsyncIterator that conforms to AsyncIteratorProtocol where AsyncIterator.Element == Element. 3. Implementing the required method: func makeAsyncIterator -> AsyncIterator The AsyncIteratorProtocol requires: mutating func next async throws -> Element? This next method asynchronously returns the next element or nil to end the sequence. The for await-in loop (e.g., for await element in asyncSequence { ... }) is only valid in an async context and handles throws appropriately with try if needed. In Swift 6+, AsyncSequence<Element, Failure> and AsyncIteratorProtocol<Element, Failure> support typed throws with Failure: Error, and an optional next(isolation:) overload for actor isolation, but existing conformances remain compatible via defaults. Example conformance: struct Counter: AsyncSequence { typealias Element = Int let howHigh: Int struct AsyncIterator: AsyncIteratorProtocol { let howHigh: Int var current = 1 mutating func next async -> Int? { guard current <= howHigh else { return nil } let result = current current += 1 return result } } func makeAsyncIterator -> AsyncIterator { AsyncIterator(howHigh: howHigh) } } // Usage in async context: for await number in Counter(howHigh: 10) { print(number) }
Citations:
- 1: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0298-asyncsequence.md
- 2: https://developer.apple.com/documentation/Swift/AsyncSequence
- 3: https://hackingwithswift.com/swift/5.5/async-sequences
- 4: https://developer.apple.com/documentation/swift/asynciteratorprotocol
- 5: https://github.com/apple/swift-evolution/blob/main/proposals/0421-generalize-async-sequence.md
Fix async sequence iteration to use for await.
The example (line 89) uses synchronous for iteration, but with eventStream as an async sequence, this pattern would not provide the intended backpressure (bounded concurrency). It should be for await event in eventStream to properly iterate through the async stream.
Suggested fix
await withDiscardingTaskGroup { group in
- for event in eventStream {
+ for await event in eventStream {
group.addTask { await process(event) }
}
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/swift-concurrency/references/structured-concurrency.md` around lines
88 - 91, The async sequence iteration is using a synchronous for loop which
bypasses async backpressure; in the withDiscardingTaskGroup closure replace the
plain "for event in eventStream" with an asynchronous iteration "for await event
in eventStream" so each element is awaited before scheduling group.addTask {
await process(event) }, ensuring correct bounded concurrency for eventStream and
preserving the intended behavior of withDiscardingTaskGroup and process(event).
| AsyncThrowingStream { continuation in | ||
| Task { | ||
| defer { continuation.finish() } | ||
|
|
||
| guard let data = try? await fetch() else { return } | ||
| continuation.yield(data) | ||
| } | ||
| } |
There was a problem hiding this comment.
This is an AsyncThrowingStream but it doesn't propagate the throwing error. It just always finish?
| - Callers outside the actor must `await` to access isolated members. | ||
| - No two tasks can be inside the actor concurrently. | ||
|
|
There was a problem hiding this comment.
No two tasks can be inside the actor concurrently. and the below section Actor reentrancy contradict to each other. Another task can enter while the actor is suspended as stated on Actor reentrancy is correct I believe 🙏
| let task = Task { | ||
| try await networkSession.data(from: url).0 | ||
| } |
There was a problem hiding this comment.
This child task is not structured under the parent. Can you check again if it's really that later parent cancellation is automatically propagated to it?
| --- | ||
| name: swift6-concurrency | ||
| description: > |
There was a problem hiding this comment.
Is the skill name swift6-concurrency or swift-concurrency? Either way, I think the name of the skill and that of its directory should match.
What happened 👀
Defined a base skills set for swift concurrency, which covered the following areas
Sendable,@unchecked Sendable, sending parametersInsight 📝
This adds a Swift 6 Concurrency AI agent skill to help Claude Code assist developers writing correct concurrent Swift code, only forward-looking patterns aligned with Swift 6's strict data-race-safety model.
Propagate task cancellation correctly through long-running operations
Summary by CodeRabbit