Skip to content

Commit 3cfda35

Browse files
committed
Remove the unused swift_asyncLet_{start,end,wait,wait_throwing} runtime
functions. These were introduced in an early draft implementation of async let, but never used by a released compiler. They are not used as symbols by any app binaries. There's no reason to keep carrying them. While I'm at it, dramatically improve the documentation of the remaining async let API functions.
1 parent cd67912 commit 3cfda35

File tree

17 files changed

+182
-457
lines changed

17 files changed

+182
-457
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2910,9 +2910,9 @@ enum class TaskOptionRecordKind : uint8_t {
29102910
InitialSerialExecutor = 0,
29112911
/// Request a child task to be part of a specific task group.
29122912
TaskGroup = 1,
2913-
/// DEPRECATED. AsyncLetWithBuffer is used instead.
2913+
/// UNUSED. AsyncLetWithBuffer is used instead.
29142914
/// Request a child task for an 'async let'.
2915-
AsyncLet = 2,
2915+
// AsyncLet = 2,
29162916
/// Request a child task for an 'async let'.
29172917
AsyncLetWithBuffer = 3,
29182918
/// Information about the result type of the task, used in embedded Swift.

include/swift/ABI/TaskOptions.h

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -166,25 +166,6 @@ class InitialSerialExecutorTaskOptionRecord : public TaskOptionRecord {
166166
}
167167
};
168168

169-
/// DEPRECATED. AsyncLetWithBufferTaskOptionRecord is used instead.
170-
/// Task option to specify that the created task is for an 'async let'.
171-
class AsyncLetTaskOptionRecord : public TaskOptionRecord {
172-
AsyncLet *asyncLet;
173-
174-
public:
175-
AsyncLetTaskOptionRecord(AsyncLet *asyncLet)
176-
: TaskOptionRecord(TaskOptionRecordKind::AsyncLet),
177-
asyncLet(asyncLet) {}
178-
179-
AsyncLet *getAsyncLet() const {
180-
return asyncLet;
181-
}
182-
183-
static bool classof(const TaskOptionRecord *record) {
184-
return record->getKind() == TaskOptionRecordKind::AsyncLet;
185-
}
186-
};
187-
188169
class AsyncLetWithBufferTaskOptionRecord : public TaskOptionRecord {
189170
AsyncLet *asyncLet;
190171
void *resultBuffer;

include/swift/Runtime/Concurrency.h

Lines changed: 134 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -351,24 +351,11 @@ bool swift_taskGroup_isCancelled(TaskGroup *group);
351351
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
352352
bool swift_taskGroup_isEmpty(TaskGroup *group);
353353

354-
/// DEPRECATED. swift_asyncLet_begin is used instead.
355-
/// Its Swift signature is
354+
/// Enter the scope of an async let binding, creating a child task of the
355+
/// current task to run the given function.
356356
///
357-
/// \code
358-
/// func swift_asyncLet_start<T>(
359-
/// asyncLet: Builtin.RawPointer,
360-
/// options: Builtin.RawPointer?,
361-
/// operation: __owned @Sendable () async throws -> T
362-
/// )
363-
/// \endcode
364-
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
365-
void swift_asyncLet_start(AsyncLet *alet,
366-
TaskOptionRecord *options,
367-
const Metadata *futureResultType,
368-
void *closureEntryPoint, HeapObject *closureContext);
369-
370-
/// Begin an async let child task.
371-
/// Its Swift signature is
357+
/// Behaves approximately like a Swift function with the following
358+
/// signature, except the generic argument is in a different position:
372359
///
373360
/// \code
374361
/// func swift_asyncLet_start<T>(
@@ -378,64 +365,24 @@ void swift_asyncLet_start(AsyncLet *alet,
378365
/// resultBuffer: Builtin.RawPointer
379366
/// )
380367
/// \endcode
368+
///
369+
/// Previous versions of the concurrency runtime also provided a
370+
/// \c swift_asyncLet_start which did not take a result buffer. This
371+
/// function was never used by a released version of the compiler,
372+
/// and it has been removed.
381373
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
382374
void swift_asyncLet_begin(AsyncLet *alet,
383375
TaskOptionRecord *options,
384376
const Metadata *futureResultType,
385377
void *closureEntryPoint, HeapObject *closureContext,
386378
void *resultBuffer);
387379

388-
/// This matches the ABI of a closure `<T>(Builtin.RawPointer) async -> T`
389-
using AsyncLetWaitSignature =
390-
SWIFT_CC(swiftasync)
391-
void(OpaqueValue *,
392-
SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncTask *, Metadata *);
393-
394-
/// DEPRECATED. swift_asyncLet_get is used instead.
395-
/// Wait for a non-throwing async-let to complete.
380+
/// Get the value of a non-throwing async let, awaiting the result
381+
/// if necessary.
396382
///
397-
/// This can be called from any thread. Its Swift signature is
383+
/// This must be called from the parent task of the async let.
398384
///
399-
/// \code
400-
/// func swift_asyncLet_wait(
401-
/// _ asyncLet: _owned Builtin.RawPointer
402-
/// ) async -> Success
403-
/// \endcode
404-
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
405-
void swift_asyncLet_wait(OpaqueValue *,
406-
SWIFT_ASYNC_CONTEXT AsyncContext *,
407-
AsyncLet *, TaskContinuationFunction *,
408-
AsyncContext *);
409-
410-
/// DEPRECATED. swift_asyncLet_get_throwing is used instead.
411-
/// Wait for a potentially-throwing async-let to complete.
412-
///
413-
/// This can be called from any thread. Its Swift signature is
414-
///
415-
/// \code
416-
/// func swift_asyncLet_wait_throwing(
417-
/// _ asyncLet: _owned Builtin.RawPointer
418-
/// ) async throws -> Success
419-
/// \endcode
420-
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
421-
void swift_asyncLet_wait_throwing(OpaqueValue *,
422-
SWIFT_ASYNC_CONTEXT AsyncContext *,
423-
AsyncLet *,
424-
ThrowingTaskFutureWaitContinuationFunction *,
425-
AsyncContext *);
426-
427-
/// DEPRECATED. swift_asyncLet_finish is used instead.
428-
/// Its Swift signature is
429-
///
430-
/// \code
431-
/// func swift_asyncLet_end(_ alet: Builtin.RawPointer)
432-
/// \endcode
433-
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
434-
void swift_asyncLet_end(AsyncLet *alet);
435-
436-
/// Get the value of a non-throwing async-let, awaiting the result if necessary.
437-
///
438-
/// This can be called from any thread. Its Swift signature is
385+
/// Behaves like a Swift async function with the signature:
439386
///
440387
/// \code
441388
/// func swift_asyncLet_get(
@@ -444,21 +391,31 @@ void swift_asyncLet_end(AsyncLet *alet);
444391
/// ) async
445392
/// \endcode
446393
///
447-
/// \c result points at the variable storage for the binding. It is
448-
/// uninitialized until the first call to \c swift_asyncLet_get or
449-
/// \c swift_asyncLet_get_throwing. That first call initializes the storage
450-
/// with the result of the child task. Subsequent calls do nothing and leave
451-
/// the value in place.
394+
/// except that it uses the special calling convention in which the
395+
/// continuation function, parent context, and child context are all
396+
/// passed in separately rather than being stored in the child context.
397+
/// The child async context has a fixed size of 5 * sizeof(void*).
398+
///
399+
/// \c resultBuffer must be the same result buffer that was passed to
400+
/// swift_asyncLet_begin. After asynchronous return, it is guaranteed
401+
/// to be initialized.
402+
///
403+
/// Previous versions of the concurrency runtime also provided a
404+
/// \c swift_asyncLet_wait which was meant to be paired with
405+
/// \c swift_asyncLet_start. This function was never used by
406+
/// a released version of the compiler, and it has been removed.
452407
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
453-
void swift_asyncLet_get(SWIFT_ASYNC_CONTEXT AsyncContext *,
454-
AsyncLet *,
455-
void *,
456-
TaskContinuationFunction *,
457-
AsyncContext *);
408+
void swift_asyncLet_get(SWIFT_ASYNC_CONTEXT AsyncContext *parentContext,
409+
AsyncLet *alet,
410+
void *resultBuffer,
411+
TaskContinuationFunction *continuation,
412+
AsyncContext *childContext);
458413

459-
/// Get the value of a throwing async-let, awaiting the result if necessary.
414+
/// Get the value of a throwing async let, awaiting the result if necessary.
460415
///
461-
/// This can be called from any thread. Its Swift signature is
416+
/// This must be called from the parent task of the async let.
417+
///
418+
/// Behaves like a Swift async function with the signature:
462419
///
463420
/// \code
464421
/// func swift_asyncLet_get_throwing(
@@ -467,42 +424,75 @@ void swift_asyncLet_get(SWIFT_ASYNC_CONTEXT AsyncContext *,
467424
/// ) async throws
468425
/// \endcode
469426
///
470-
/// \c result points at the variable storage for the binding. It is
471-
/// uninitialized until the first call to \c swift_asyncLet_get or
472-
/// \c swift_asyncLet_get_throwing. That first call initializes the storage
473-
/// with the result of the child task. Subsequent calls do nothing and leave
474-
/// the value in place. A pointer to the storage inside the child task is
475-
/// returned if the task completes successfully, otherwise the error from the
476-
/// child task is thrown.
427+
/// except that it uses the special calling convention in which the
428+
/// continuation function, parent context, and child context are all
429+
/// passed in separately rather than being stored in the child context.
430+
/// The child async context has a fixed size of 5 * sizeof(void*).
431+
///
432+
/// \c resultBuffer must be the same result buffer that was passed to
433+
/// swift_asyncLet_begin. After asynchronous return, it is guaranteed
434+
/// to be initialized unless the operation throws by passing an error
435+
/// to the continuation function.
436+
///
437+
/// Previous versions of the concurrency runtime also provided a
438+
/// \c swift_asyncLet_wait_throwing which was meant to be paired with
439+
/// \c swift_asyncLet_start. This function was never used by
440+
/// a released version of the compiler, and it has been removed.
477441
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
478-
void swift_asyncLet_get_throwing(SWIFT_ASYNC_CONTEXT AsyncContext *,
479-
AsyncLet *,
480-
void *,
481-
ThrowingTaskFutureWaitContinuationFunction *,
482-
AsyncContext *);
442+
void swift_asyncLet_get_throwing(SWIFT_ASYNC_CONTEXT AsyncContext *parentContext,
443+
AsyncLet *alet,
444+
void *resultBuffer,
445+
ThrowingTaskFutureWaitContinuationFunction *
446+
continuation,
447+
AsyncContext *childContext);
483448

484-
/// Exit the scope of an async-let binding. If the task is still running, it
485-
/// is cancelled, and we await its completion; otherwise, we destroy the
486-
/// value in the variable storage.
449+
/// Exit the scope of an async let binding that was created with
450+
/// swift_asyncLet_begin. If the child task is still running, it is
451+
/// cancelled, and the current task is suspended to await its completion.
487452
///
488-
/// Its Swift signature is
453+
/// This must be called from the parent task of the async let.
454+
///
455+
/// Behaves like a Swift async function with the signature:
489456
///
490457
/// \code
491458
/// func swift_asyncLet_finish(_ asyncLet: Builtin.RawPointer,
492459
/// _ resultBuffer: Builtin.RawPointer) async
493460
/// \endcode
461+
///
462+
/// except that it uses the special calling convention in which the
463+
/// continuation function, parent context, and child context are all
464+
/// passed in separately rather than being stored in the child context.
465+
/// The child async context has a fixed size of 5 * sizeof(void*).
466+
///
467+
/// \c resultBuffer must be the same result buffer that was passed to
468+
/// swift_asyncLet_begin.
469+
///
470+
/// Prior to asynchronous return, the value in the result buffer is
471+
/// destroyed (if present) and any memory initially allocated for the
472+
/// task is deallocated. Because swift_asyncLet_begin potentially
473+
/// allocates memory on the parent task's task allocator, the call to
474+
/// this function must be properly paired with the begin.
475+
///
476+
/// The async let is invalid after this call and cannot be used again.
477+
///
478+
/// Previous versions of the concurrency runtime also provided a
479+
/// \c swift_asyncLet_end which was not asynchronous and was meant
480+
/// to be paired with \c swift_asyncLet_start. This function was never
481+
/// used by a released version of the compiler, and it has been removed.
494482
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
495483
void swift_asyncLet_finish(SWIFT_ASYNC_CONTEXT AsyncContext *,
496484
AsyncLet *,
497485
void *,
498486
TaskContinuationFunction *,
499487
AsyncContext *);
500488

501-
/// Get the value of a non-throwing async-let, awaiting the result if necessary,
502-
/// and then destroy the child task. The result buffer is left initialized after
503-
/// returning.
489+
/// Get the value of a non-throwing async let binding that was created
490+
/// with \c swift_asyncLet_begin, awaiting the task's completion if
491+
/// necessary, and then destroy the task and the binding.
504492
///
505-
/// This can be called from any thread. Its Swift signature is
493+
/// This must be called from the parent task of the async let.
494+
///
495+
/// Behaves like a Swift async function with the signature:
506496
///
507497
/// \code
508498
/// func swift_asyncLet_get(
@@ -511,22 +501,34 @@ void swift_asyncLet_finish(SWIFT_ASYNC_CONTEXT AsyncContext *,
511501
/// ) async
512502
/// \endcode
513503
///
514-
/// \c result points at the variable storage for the binding. It is
515-
/// uninitialized until the first call to \c swift_asyncLet_get or
516-
/// \c swift_asyncLet_get_throwing. The child task will be invalidated after
517-
/// this call, so the `async let` can not be gotten or finished afterward.
504+
/// except that it uses the special calling convention in which the
505+
/// continuation function, parent context, and child context are all
506+
/// passed in separately rather than being stored in the child context.
507+
/// The child async context has a fixed size of 5 * sizeof(void*).
508+
///
509+
/// \c resultBuffer must be the same result buffer that was passed to
510+
/// swift_asyncLet_begin. After asynchronous return, this is guaranteed
511+
/// to be initialized.
512+
///
513+
/// The async let is invalid after this call and cannot be used again.
514+
/// Any memory initially allocated for the task is deallocated. Because
515+
/// \c swift_asyncLet_begin potentially allocates memory on the parent
516+
/// task's task allocator, the call to this function must be properly
517+
/// paired with the begin.
518518
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
519-
void swift_asyncLet_consume(SWIFT_ASYNC_CONTEXT AsyncContext *,
520-
AsyncLet *,
521-
void *,
522-
TaskContinuationFunction *,
523-
AsyncContext *);
519+
void swift_asyncLet_consume(SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
520+
AsyncLet *alet,
521+
void *resultBuffer,
522+
TaskContinuationFunction *continuation,
523+
AsyncContext *callContext);
524524

525-
/// Get the value of a throwing async-let, awaiting the result if necessary,
526-
/// and then destroy the child task. The result buffer is left initialized after
527-
/// returning.
525+
/// Get the value of a throwing async let binding that was created
526+
/// with \c swift_asyncLet_begin, awaiting the task's completion if
527+
/// necessary, and then destroy the task and the binding.
528528
///
529-
/// This can be called from any thread. Its Swift signature is
529+
/// This must be called from the parent task of the async let.
530+
///
531+
/// Behaves like a Swift async function with the signature:
530532
///
531533
/// \code
532534
/// func swift_asyncLet_get_throwing(
@@ -535,18 +537,28 @@ void swift_asyncLet_consume(SWIFT_ASYNC_CONTEXT AsyncContext *,
535537
/// ) async throws
536538
/// \endcode
537539
///
538-
/// \c result points at the variable storage for the binding. It is
539-
/// uninitialized until the first call to \c swift_asyncLet_get or
540-
/// \c swift_asyncLet_get_throwing. That first call initializes the storage
541-
/// with the result of the child task. Subsequent calls do nothing and leave
542-
/// the value in place. The child task will be invalidated after
543-
/// this call, so the `async let` can not be gotten or finished afterward.
540+
/// except that it uses the special calling convention in which the
541+
/// continuation function, parent context, and child context are all
542+
/// passed in separately rather than being stored in the child context.
543+
/// The child async context has a fixed size of 5 * sizeof(void*).
544+
///
545+
/// \c resultBuffer must be the same result buffer that was passed to
546+
/// swift_asyncLet_begin. After asynchronous return, it is guaranteed
547+
/// to be initialized unless the operation throws by passing an error
548+
/// to the continuation function.
549+
///
550+
/// The async let is invalid after this call and cannot be used again.
551+
/// Any memory initially allocated for the task is deallocated. Because
552+
/// \c swift_asyncLet_begin potentially allocates memory on the parent
553+
/// task's task allocator, the call to this function must be properly
554+
/// paired with the begin.
544555
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
545-
void swift_asyncLet_consume_throwing(SWIFT_ASYNC_CONTEXT AsyncContext *,
546-
AsyncLet *,
547-
void *,
548-
ThrowingTaskFutureWaitContinuationFunction *,
549-
AsyncContext *);
556+
void swift_asyncLet_consume_throwing(SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
557+
AsyncLet *alet,
558+
void *resultBuffer,
559+
ThrowingTaskFutureWaitContinuationFunction *
560+
continuation,
561+
AsyncContext *callContext);
550562

551563
/// Returns true if the currently executing AsyncTask has a
552564
/// 'TaskGroupTaskStatusRecord' present.

0 commit comments

Comments
 (0)