Skip to content

Commit 1830773

Browse files
authored
Merge pull request #37303 from amartini51/continuation_doc_comments_75894995
2 parents 70cd356 + 3aa3ca2 commit 1830773

File tree

2 files changed

+189
-105
lines changed

2 files changed

+189
-105
lines changed

stdlib/public/Concurrency/CheckedContinuation.swift

Lines changed: 78 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -83,49 +83,60 @@ internal final class CheckedContinuationCanary {
8383
}
8484
}
8585

86-
/// A wrapper class for `UnsafeContinuation` that logs misuses of the
87-
/// continuation, logging a message if the continuation is resumed
88-
/// multiple times, or if an object is destroyed without its continuation
89-
/// ever being resumed.
86+
/// A mechanism to interface
87+
/// between synchronous and asynchronous code,
88+
/// logging correctness violations.
9089
///
91-
/// Raw `UnsafeContinuation`, like other unsafe constructs, requires the
92-
/// user to apply it correctly in order to maintain invariants. The key
93-
/// invariant is that the continuation must be resumed exactly once,
94-
/// and bad things happen if this invariant is not upheld--if a continuation
95-
/// is abandoned without resuming the task, then the task will be stuck in
96-
/// the suspended state forever, and conversely, if the same continuation is
97-
/// resumed multiple times, it will put the task in an undefined state.
90+
/// A *continuation* is an opaque representation of program state.
91+
/// To create a continuation in asynchronous code,
92+
/// call the `withUnsafeContinuation(function:_:)` or
93+
/// `withUnsafeThrowingContinuation(function:_:)` function.
94+
/// To resume the asynchronous task,
95+
/// call the `resume(returning:)`,
96+
/// `resume(throwing:)`,
97+
/// `resume(with:)`,
98+
/// or `resume()` method.
9899
///
99-
/// `UnsafeContinuation` avoids enforcing these invariants at runtime because
100-
/// it aims to be a low-overhead mechanism for interfacing Swift tasks with
101-
/// event loops, delegate methods, callbacks, and other non-`async` scheduling
102-
/// mechanisms. However, during development, being able to verify that the
103-
/// invariants are being upheld in testing is important.
100+
/// - Important: You must call a resume method exactly once
101+
/// on every execution path throughout the program.
102+
///
103+
/// Resuming from a continuation more than once is undefined behavior.
104+
/// Never resuming leaves the task in a suspended state indefinitely,
105+
/// and leaks any associated resources.
106+
/// `CheckedContinuation` logs a message
107+
/// if either of these invariants is violated.
104108
///
105-
/// `CheckedContinuation` is designed to be a drop-in API replacement for
106-
/// `UnsafeContinuation` that can be used for testing purposes, at the cost of
107-
/// an extra allocation and indirection for the wrapper object. Changing a call
108-
/// of `withUnsafeContinuation` or `withUnsafeThrowingContinuation` into a call
109-
/// of `withCheckedContinuation` or `withCheckedThrowingContinuation` should be
110-
/// enough to obtain the extra checking without further source modification in
111-
/// most circumstances.
109+
/// `CheckedContinuation` performs runtime checks
110+
/// for missing or multiple resume operations.
111+
/// `UnsafeContinuation` avoids enforcing these invariants at runtime
112+
/// because it aims to be a low-overhead mechanism
113+
/// for interfacing Swift tasks with
114+
/// event loops, delegate methods, callbacks,
115+
/// and other non-`async` scheduling mechanisms.
116+
/// However, during development, the ability to verify that the
117+
/// invariants are being upheld in testing is important.
118+
/// Because both types have the same interface,
119+
/// you can replace one with the other in most circumstances,
120+
/// without making other changes.
112121
@available(SwiftStdlib 5.5, *)
113122
public struct CheckedContinuation<T, E: Error> {
114123
private let canary: CheckedContinuationCanary
115124

116-
/// Initialize a `CheckedContinuation` wrapper around an
117-
/// `UnsafeContinuation`.
125+
/// Creates a checked continuation from an unsafe continuation.
118126
///
119-
/// In most cases, you should use `withCheckedContinuation` or
120-
/// `withCheckedThrowingContinuation` instead. You only need to initialize
127+
/// Instead of calling this initializer,
128+
/// most code calls the `withCheckedContinuation(function:_:)` or
129+
/// `withCheckedThrowingContinuation(function:_:)` function instead.
130+
/// You only need to initialize
121131
/// your own `CheckedContinuation<T, E>` if you already have an
122132
/// `UnsafeContinuation` you want to impose checking on.
123133
///
124134
/// - Parameters:
125-
/// - continuation: a fresh `UnsafeContinuation` that has not yet
126-
/// been resumed. The `UnsafeContinuation` must not be used outside of
127-
/// this object once it's been given to the new object.
128-
/// - function: a string identifying the declaration that is the notional
135+
/// - continuation: An instance of `UnsafeContinuation`
136+
/// that hasn't yet been resumed.
137+
/// After passing the unsafe continuation to this initializer,
138+
/// don't use it outside of this object.
139+
/// - function: A string identifying the declaration that is the notional
129140
/// source for the continuation, used to identify the continuation in
130141
/// runtime diagnostics related to misuse of this continuation.
131142
public init(continuation: UnsafeContinuation<T, E>, function: String = #function) {
@@ -141,10 +152,10 @@ public struct CheckedContinuation<T, E: Error> {
141152
///
142153
/// A continuation must be resumed exactly once. If the continuation has
143154
/// already been resumed through this object, then the attempt to resume
144-
/// the continuation again will trap.
155+
/// the continuation will trap.
145156
///
146-
/// After `resume` enqueues the task, control is immediately returned to
147-
/// the caller. The task will continue executing when its executor is
157+
/// After `resume` enqueues the task, control immediately returns to
158+
/// the caller. The task continues executing when its executor is
148159
/// able to reschedule it.
149160
public func resume(returning x: __owned T) {
150161
if let c: UnsafeContinuation<T, E> = canary.takeContinuation() {
@@ -161,10 +172,10 @@ public struct CheckedContinuation<T, E: Error> {
161172
///
162173
/// A continuation must be resumed exactly once. If the continuation has
163174
/// already been resumed through this object, then the attempt to resume
164-
/// the continuation again will trap.
175+
/// the continuation will trap.
165176
///
166-
/// After `resume` enqueues the task, control is immediately returned to
167-
/// the caller. The task will continue executing when its executor is
177+
/// After `resume` enqueues the task, control immediately returns to
178+
/// the caller. The task continues executing when its executor is
168179
/// able to reschedule it.
169180
public func resume(throwing x: __owned E) {
170181
if let c: UnsafeContinuation<T, E> = canary.takeContinuation() {
@@ -186,10 +197,10 @@ extension CheckedContinuation {
186197
///
187198
/// A continuation must be resumed exactly once. If the continuation has
188199
/// already been resumed through this object, then the attempt to resume
189-
/// the continuation again will trap.
200+
/// the continuation will trap.
190201
///
191-
/// After `resume` enqueues the task, control is immediately returned to
192-
/// the caller. The task will continue executing when its executor is
202+
/// After `resume` enqueues the task, control immediately returns to
203+
/// the caller. The task continues executing when its executor is
193204
/// able to reschedule it.
194205
@_alwaysEmitIntoClient
195206
public func resume<Er: Error>(with result: Result<T, Er>) where E == Error {
@@ -210,10 +221,10 @@ extension CheckedContinuation {
210221
///
211222
/// A continuation must be resumed exactly once. If the continuation has
212223
/// already been resumed through this object, then the attempt to resume
213-
/// the continuation again will trap.
224+
/// the continuation will trap.
214225
///
215-
/// After `resume` enqueues the task, control is immediately returned to
216-
/// the caller. The task will continue executing when its executor is
226+
/// After `resume` enqueues the task, control immediately returns to
227+
/// the caller. The task continues executing when its executor is
217228
/// able to reschedule it.
218229
@_alwaysEmitIntoClient
219230
public func resume(with result: Result<T, E>) {
@@ -230,17 +241,26 @@ extension CheckedContinuation {
230241
///
231242
/// A continuation must be resumed exactly once. If the continuation has
232243
/// already been resumed through this object, then the attempt to resume
233-
/// the continuation again will trap.
244+
/// the continuation will trap.
234245
///
235-
/// After `resume` enqueues the task, control is immediately returned to
236-
/// the caller. The task will continue executing when its executor is
246+
/// After `resume` enqueues the task, control immediately returns to
247+
/// the caller. The task continues executing when its executor is
237248
/// able to reschedule it.
238249
@_alwaysEmitIntoClient
239250
public func resume() where T == Void {
240251
self.resume(returning: ())
241252
}
242253
}
243254

255+
/// Suspends the current task,
256+
/// then calls the given closure with a checked continuation for the current task.
257+
///
258+
/// - Parameters:
259+
/// - function: A string identifying the declaration that is the notional
260+
/// source for the continuation, used to identify the continuation in
261+
/// runtime diagnostics related to misuse of this continuation.
262+
/// - body: A closure that takes an `UnsafeContinuation` parameter.
263+
/// You must resume the continuation exactly once.
244264
@available(SwiftStdlib 5.5, *)
245265
public func withCheckedContinuation<T>(
246266
function: String = #function,
@@ -251,6 +271,18 @@ public func withCheckedContinuation<T>(
251271
}
252272
}
253273

274+
/// Suspends the current task,
275+
/// then calls the given closure with a checked throwing continuation for the current task.
276+
///
277+
/// - Parameters:
278+
/// - function: A string identifying the declaration that is the notional
279+
/// source for the continuation, used to identify the continuation in
280+
/// runtime diagnostics related to misuse of this continuation.
281+
/// - body: A closure that takes an `UnsafeContinuation` parameter.
282+
/// You must resume the continuation exactly once.
283+
///
284+
/// If `resume(throwing:)` is called on the continuation,
285+
/// this function throws that error.
254286
@available(SwiftStdlib 5.5, *)
255287
public func withCheckedThrowingContinuation<T>(
256288
function: String = #function,

0 commit comments

Comments
 (0)