---
title: "SE-0526: withDeadline"
framework: swift-evolution
role: article
path: swift-evolution/0526-deadline
---

# SE-0526: withDeadline

* Proposal: [SE-0526](0526-deadline.md)
* Authors: [Franz Busch](https://github.com/FranzBusch), [Philippe Hausler](https://github.com/phausler), [Konrad Malawski](https://github.com/ktoso)
* Status: **Active Review (May 18th...May 31st, 2026)**
* Implementation: https://github.com/swiftlang/swift/pull/88323
* Review Manager: [Freddy Kellison-Linn](https://github.com/Jumhyn)
* Review: ([pitch](https://forums.swift.org/t/pitch-withdeadline/85262)) ([review](https://forums.swift.org/t/se-0526-withdeadline/85850)) ([returned for revision](https://forums.swift.org/t/returned-for-revision-se-0526-withdeadline/86438))

## Summary of changes

This proposal introduces `withDeadline`, a function that executes asynchronous operations with a composable absolute time limit. The function accepts a  continuous clock instant representing the deadline by which the operation must  complete. If the operation completes before the deadline, the function returns  the result; if the deadline expires first, the operation is cancelled.

## Motivation

Asynchronous operations in Swift can run indefinitely, which creates several problems in real-world applications:

1. Network operations may not complete when servers become unresponsive,    consuming resources and degrading user experience. 2. Server-side applications need predictable request handling times to maintain    service level agreements and prevent resource exhaustion. 3. Batch processing requires mechanisms to prevent individual tasks from    blocking entire workflows. 4. Resource management becomes difficult when operations lack time bounds,    leading to connection pool exhaustion and memory leaks. 5. Coordinating multiple operations to complete by a shared deadline requires    passing absolute instants, not relative durations that drift through the call    stack.

Currently, developers must implement timeout logic manually using task groups and clock sleep operations, resulting in verbose, error-prone code that's difficult to compose with surrounding async contexts. Each implementation must carefully handle cancellation, error propagation, and race conditions between the operation and timer.

## Proposed solution

This proposal introduces `withDeadline`, a function that executes an asynchronous operation with an absolute time limit specified as a clock instant. This builds upon the clock, instant, and duration types introduced in [SE-0329](0329-clock-instant-duration.md), the structured concurrency and cooperative cancellation model from [SE-0304](0304-structured-concurrency.md), and composes naturally with the task cancellation shields from [SE-0504](0504-task-cancellation-shields.md). The solution provides a clean,  composable API that handles cancellation and error propagation automatically:

```swift let clock = ContinuousClock()

do {     let result = try await withDeadline(clock.now.advanced(by: .seconds(5)), clock: clock) {         try await fetchDataFromServer()     }     print("Data received: \(result)") } catch {     print("Request failed: \(error)") } ```

The solution is safer than manual implementations because it handles all race conditions between the operation and deadline timer, ensures proper cleanup through structured concurrency, and provides clear semantics for cancellation behavior.

## Detailed design

#### Executing work with a given deadline

The fundamental entry point for working with deadlines is a single function: `withDeadline`.

```swift /// Executes an asynchronous operation with a specified deadline. /// /// Use this function to limit the execution time of an asynchronous operation to a specific instant. /// If the operation completes before the deadline expires, this function returns the result. If the /// deadline expires first, this function cancels the operation. The `withDeadline` function will /// return or throw according to how the operation returns or throws as a response to the cancellation. /// /// The following example demonstrates using a deadline to limit a network request: /// /// ```swift /// let clock = ContinuousClock() /// let deadline = clock.now.advanced(by: .seconds(5)) /// do { ///     let result = try await withDeadline(deadline, clock: clock) { ///         try await fetchDataFromServer() ///     } ///     print("Data received: \(result)") /// } catch { ///     print("Operation failed") /// } /// ``` /// /// ## Behavior /// /// The function exhibits the following behavior based on deadline and operation completion: /// /// - If the operation completes successfully before deadline: Returns the operation result. /// - If the operation throws an error before deadline: Throws the operation error. /// - If deadline expires and operation completes successfully: Returns the operation result /// - If deadline expires and operation throws an error: Throws the operation error. /// /// ## Coordinating multiple operations /// /// Use `withDeadline` when coordinating multiple operations to complete by the same instant: /// /// ```swift /// let clock = ContinuousClock() /// let deadline = clock.now.advanced(by: .seconds(10)) /// /// async let result1 = withDeadline(deadline, clock: clock) { ///     try await fetchUserData() /// } /// async let result2 = withDeadline(deadline) { ///     try await fetchPreferences() /// } /// /// let (user, prefs) = try await (result1, result2) /// ``` /// /// This ensures both operations share the same absolute deadline, avoiding duration drift that can occur /// when timeouts are passed through multiple call layers. /// /// - Important: This function cancels the operation when the deadline expires, but waits for the /// operation to return. The function may run longer than the time until the deadline if the operation /// doesn't respond to cancellation immediately. /// /// - Parameters: ///   - deadline: The instant by which the operation must complete. ///   - tolerance: The tolerance used for the sleep. ///   - clock: The clock to use for measuring time. ///   - body: The asynchronous operation to complete before the deadline. /// /// - Returns: The result of the operation if it completes successfully before or after the deadline expires. /// /// - Throws: The error thrown by the operation nonisolated(nonsending) public func withDeadline<Return: ~Copyable, Failure: Error, C: Clock>(   _ expiration: C.Instant,   tolerance: C.Instant.Duration? = nil,   clock: C = ContinuousClock(),   body: nonisolated(nonsending) () async throws(Failure) -> Return ) async throws(Failure) -> Return ```

The deadline-based API accepts a generic `Clock.Instant`, allowing multiple operations to share the same absolute deadline:

```swift let clock = ContinuousClock() let deadline = clock.now.advanced(by: .seconds(10))

async let user = withDeadline(deadline, clock: clock) {     try await fetchUser() } async let prefs = withDeadline(deadline, clock: clock) {     try await fetchPreferences() }

let (userData, prefsData) = try await (user, prefs) ```

These absolute deadlines are composable and nestable to any set scope of a deadline. This means that when more than  one `withDeadline` is nested the minimum of the expiration is taken. If any nested cases are differing clocks the  deadline expires determined by the clock, so no inter-clock conversions need to be computed. This nesting case works by the outer executing with a given deadline expiration while the inner also executes with its own given deadline expiration. These two expirations will execute independently to whichever cancels the operation first. Practically this means that the expiration then is the minimum of the two deadlines, without needing to compare or calculate  between them.

```swift let clock = ContinuousClock() let userAndPrefsDeadline = clock.now.advanced(by: .seconds(5))

let userAndPrefs = try await withDeadline(userAndPrefsDeadline, clock: clock) {   let user = try await fetchUser()   let prefs = try await fetchPrefs() }

func fetchPrefs() async throws(FetchFailure) -> Prefs {   let prefsDeadline = clock.now.advanced(by: .seconds(10))   do {     return try await withDeadline(prefsDeadline, clock: clock) {       try await fetchPreferences()     }   } catch {     throw error.underlyingError   } } ```

Particularly in this case the composition can be made such that two independent regions can participate in a composed  deadline across library boundaries and still result in the correct deadline for the composed expectation of the caller.  This is achieved due to the fact that each nesting of `withDeadline` will independently apply a deadline expiration. The first to cancel will be the composition of the effective minimum no matter the clock specified. This means that  there is no need for a current deadline for the service of calculating which is the minimum execution deadline.

#### Shorthand for quickly using common deadline construction

Constructing an instant every time is not per se the most terse; so a simple extension offers the ease of construction  with the same compositional advantage as the primary entry point.

```swift nonisolated(nonsending) public func withDeadline<Return: ~Copyable, Failure: Error, C: Clock>(   in timeout: C.Instant.Duration,   tolerance: C.Instant.Duration? = nil,   clock: C = ContinuousClock(),   body: nonisolated(nonsending) () async throws(Failure) -> Return ) async throws(Failure) -> Return

nonisolated(nonsending) public func withDeadline<Return: ~Copyable, Failure: Error>(   in timeout: ContinuousClock.Instant.Duration,   tolerance: ContinuousClock.Instant.Duration? = nil,   body: nonisolated(nonsending) () async throws(Failure) -> Return ) async throws(Failure) -> Return ```

The implementation of this is trivially:

```swift try await withDeadline(clock.now.advanced(by: timeout), tolerance: tolerance, body: body) ```

#### Non-escaping nonisolated(nonsending) operation closure

Many existing deadline/timeout implementations require a `@Sendable` and `@escaping` closure which makes it hard to compose in isolated context and use non-Sendable types. This design ensures that the closure is both non-escaping and nonisolated(nonsending) for composability:

```swift actor DataProcessor {     var cache: [String: Data] = [:]

func fetchWithDeadline(url: String) async throws {         // The closure can access actor-isolated state because it's nonisolated(nonsending)         let data = try await withDeadline(in: .seconds(5)) {             if let cached = cache[url] {                 return cached             }             return try await URLSession.shared.data(from: URL(string: url)!)         }         cache[url] = data     } } ```

If the closure were `@Sendable`, it couldn't access actor-isolated state like `cache`. The `nonisolated(nonsending)` annotation allows the closure to compose with surrounding code regardless of isolation context, while maintaining safety guarantees.

#### Cancellation

This API uses the base cancellation to communicate the expiration of the deadline. The information to differentiate a cancellation due to normal task cancellation is expanded to handle two new forms of cancellation; a cancellation due to deadline expiration, and a custom cancellation with a specified string for a reason. Since this is not a closed set of possible reasons for future development, this reason is left as an open enumeration.

Today `CancellationError` is an empty type with no payload or information conveyed to indicate the reasoning for cancellation. [SE-0304](0304-structured-concurrency.md) originally noted that "no information is passed to the task about why it was cancelled," treating cancellation as a lightweight, uniform signal. With the introduction of deadlines, however, differentiating between a cancellation due to deadline expiration and a cancellation from an explicit `Task.cancel()` call becomes practically necessary for correct error reporting and recovery. A new sub-type will be  added to represent the reason for the cancellation, a new initializer for `CancellationError` will be added for constructing a `CancellationError` with a given reason, and a new property will be  added for determining what the reason of the cancellation was. This modification not only allows  for developers to express the difference between a cancellation due to deadline expiration versus  normal task cancellation, but also express a custom reason for indicating why something might be  cancelled.

```swift public struct CancellationError: Error {   @nonexhaustive   public enum Reason {     case taskCancelled     case deadlineExpired     case custom(String)   }

public var reason: Reason { get }   public init(reason: Reason)

// This is shorthand for `CancellationError(reason: .taskCancelled)`   public init() } ```

Switching upon the reason specifically will require the developer to handle unknown cases since there may be situations in which additional cases may be added at a future point. Because  `CancellationError.Reason` is defined in the Concurrency module (which ships as part of the  standard library and is a resilient module), the enum is non-frozen by default and switch  statements require an `@unknown default` case. Since previous cancellation was something that  has been already written the developer already has handled the cases of cancellation without a  given reason; this will continue to be the case.

To aid in the population of cancellation errors, new APIs will be added. These will all be cases where a task or child task is cancelled and a CancellationError would normally be created.

```swift extension Task {   public func cancel(reason: CancellationError.Reason) }

extension UnsafeCurrentTask {   public func cancel(reason: CancellationError.Reason) }

extension TaskGroup {   public func cancelAll(reason: CancellationError.Reason) }

extension ThrowingTaskGroup {   public func cancelAll(reason: CancellationError.Reason) }

extension DiscardingTaskGroup {   public func cancelAll(reason: CancellationError.Reason) }

extension ThrowingDiscardingTaskGroup {   public func cancelAll(reason: CancellationError.Reason) } ```

#### Failures and expiration

The withDeadline throwing behavior is that of the operation's throwing behavior. If the operation throws a specific type then the withDeadline will throw that same type, this permits the case where a cancellation aware throwing behavior is then respected with the most information possible and specifically does not throw away the potential failure information. This means that if a developer wishes to communicate a failure solely due to deadline expiration, the cancellation error that is thrown should then contain the reason of `.deadlineExpired`.

This error is propagated from whenever the task (or child task) is cancelled via the `cancel(reason:)` method. The reason specified will then be available to the `CancellationError` and can be retrieved from the `reason` property on the cancellation error.

### Behavioral Details

1. The user specified closure runs concurrently to the timing of the expiration  of the deadline. 2. The first event between the closure and the timing determines the result. 3. When either the expiration happens such that the deadline is hit or the user  specified closure is done, the unfinished part of the execution is cancelled. 4. If the deadline expires first, the operation is cancelled but the function waits  for it to return. 5. The function handles both the operation's result and any errors thrown.

The function cancels the operation when the deadline expires, but waits for the  operation to return. This means `withDeadline` may run longer than the time until  the deadline if the operation doesn't respond to cancellation immediately. This  design ensures proper cleanup and prevents resource leaks from abandoned tasks.

Users who wish to adjust behaviors can use the task cancellation shields and/or  task cancellation handlers to alter the behavior of the return values. These in  conjunction with manual processing of do/catch clauses can compose to complex  behaviors needed for many specialized scenarios.

#### Behaviors for Cancellation and Expiration

The following examples outline common composition and cancellation behaviors.

- **Example 0**: Operation completes before deadline - returns successfully with no error. - **Example 1**: Operation throws before deadline - the thrown error propagates. - **Example 2**: Inner deadline (2s) expires before outer deadline (3s) - only the inner cancellation handler fires, and the operation's thrown error propagates. - **Example 3**: Outer deadline (2s) expires before inner deadline (3s) - both cancellation handlers fire because cancellation propagates inward through the task tree. - **Example 4**: Outer deadline (2s) expires before inner deadline (10s), but the sleep is shorter (3s) - both handlers still fire at the 2s mark because the outer deadline governs. - **Example 5**: Demonstrates that `withDeadline` waits for the operation to return even after cancellation. The busy-loop ignores cancellation and runs for the full 10 seconds despite the 2s inner deadline.

```swift struct LocalError: Error { }

print("====== EXAMPLE 0 ======") do {   let value = try await withDeadline(in: .seconds(2), tolerance: .microseconds(2)) {     return "Success"   } } catch {   print("caught \(error)") } // ====== EXAMPLE 0 ======

print("====== EXAMPLE 1 ======") do {   try await withDeadline(in: .seconds(2), tolerance: .microseconds(2)) {     throw LocalError()   } } catch {   print("caught \(error)") } // ====== EXAMPLE 1 ====== // caught LocalError()

print("====== EXAMPLE 2 ======") do {   try await withDeadline(in: .seconds(3), tolerance: .microseconds(2)) {     try await withTaskCancellationHandler {       try await withDeadline(in: .seconds(2), tolerance: .microseconds(2)) {         try await withTaskCancellationHandler {           let elapsed = await ContinuousClock().measure {             try? await Task.sleep(for: .seconds(10))           }           print("\(elapsed) elapsed")           throw LocalError()         } onCancel: {           print("cancel inner")         }       }     } onCancel: {       print("cancel outer")     }   } } catch {   print("caught \(error)") } // ====== EXAMPLE 2 ====== // cancel inner // 2.001315 seconds elapsed // caught LocalError()

print("====== EXAMPLE 3 ======") do {   try await withDeadline(in: .seconds(2), tolerance: .microseconds(2)) {     try await withTaskCancellationHandler {       try await withDeadline(in: .seconds(3), tolerance: .microseconds(2)) {         try await withTaskCancellationHandler {           let elapsed = await ContinuousClock().measure {             try? await Task.sleep(for: .seconds(10))           }           print("\(elapsed) elapsed")           throw LocalError()         } onCancel: {           print("cancel inner")         }       }     } onCancel: {       print("cancel outer")     }   } } catch {   print("caught \(error)") } // ====== EXAMPLE 3 ====== // cancel inner // cancel outer // 2.00507375 seconds elapsed // caught LocalError()

print("====== EXAMPLE 4 ======") do {   try await withDeadline(in: .seconds(2), tolerance: .microseconds(2)) {     try await withTaskCancellationHandler {       try await withDeadline(in: .seconds(10), tolerance: .microseconds(2)) {         try await withTaskCancellationHandler {           let elapsed = await ContinuousClock().measure {             try? await Task.sleep(for: .seconds(3))           }           print("\(elapsed) elapsed")           throw LocalError()         } onCancel: {           print("cancel inner")         }       }     } onCancel: {       print("cancel outer")     }   } } catch {   print("caught \(error)") } // ====== EXAMPLE 4 ====== // cancel inner // cancel outer // 2.005246625 seconds elapsed // caught LocalError()

print("====== EXAMPLE 5 ======") do {   try await withDeadline(in: .seconds(3), tolerance: .microseconds(2)) {     try await withTaskCancellationHandler {       try await withDeadline(in: .seconds(2), tolerance: .microseconds(2)) {         try await withTaskCancellationHandler {           let clock = ContinuousClock()           let elapsed = await clock.measure {             let start = clock.now             while clock.now < start + .seconds(10) {               await Task.yield()             }           }           print("\(elapsed) elapsed")           throw LocalError()         } onCancel: {           print("cancel inner")         }       }     } onCancel: {       print("cancel outer")     }   } } catch {   print("caught \(error)") } // ====== EXAMPLE 5 ====== // cancel inner // cancel outer // 10.000002291000001 seconds elapsed // caught LocalError() ```

## Source compatibility

The proposed APIs are additive and the behavior of deadlines are composed  without a need for intermediary participation. Existing systems that handle cancellation or throwing of errors will compose with this without the need to adjust for the new deadline semantics.

## Effect on ABI compatibility

Since this is an additive proposal there is no change to any existing ABI. The modification to `CancellationError` adds a new stored property and initializer  but preserves the existing default initializer with identical behavior - existing  code that constructs `CancellationError()` will continue to produce an error with  the equivalent of `.taskCancelled` as its reason. The proposed APIs are capable of  being implemented in less performant manners prior to the introduction of typed throws.  Back porting this feature is not a proposed part of the pitch but no technical  limitation is added except the burden of making the implementation fragmented upon  deployment.

## Effect on API resilience

This is an additive API and no existing systems are changed, however it will introduce a few new types that will need to be maintained as ABI interfaces.

## Location and availability

Previously this feature was pitched for swift-async-algorithms. However due to the large demand and existing requests for this feature it was considered  perhaps not specialized enough to live in that particular package. It would  be a fairly common occurrence to need this functionality and it would be better served living in the Concurrency module.

The availability has particular consideration listed in the ABI section.

## Future directions

This can have an impact upon executors. The current implementation does not  need executors to do anything different than they do as this is pitched, but some modification around cancellation of jobs could be added to allow executors to more efficiently handle deadlines.

There are potentials of exposing the underlying structured concurrency primitives to enable APIs like `withDeadline`. This has a precedent in other languages and is often called `race`. Introducing the `withDeadline` API does not preclude that as an eventuality and lends credence to the utility of having that as  a general purpose feature, however offering the more primitive functionality  would still likely have the same considerations and motivation for introducing a `withDeadline` API. So these concepts are not mutually exclusive or blocking. If at some point in time the concurrency library grows a new `race` type primitive, then  `withDeadline` would likely be a strong candidate for using that.

## Alternatives considered

### Timeout-based API instead of Deadline-based API

An earlier design considered naming the primary API `withTimeout` and having it accept a duration parameter instead of focusing on deadline-based (instant-based) semantics:

```swift public func withTimeout<Return, Failure: Error>(   in duration: Duration,   body: () async throws(Failure) -> Return ) async throws(TimeoutError<Failure>) -> Return ```

This approach was rejected because deadline-based APIs provide better composability and semantics. Duration-based timeouts accumulate drift when passed through multiple call layers, making it impossible to guarantee that nested operations complete within a precise time window, whereas absolute deadlines allow multiple operations to coordinate on the same completion instant. Consider a function that applies a 10-second timeout and then calls  two sub-operations each with the remaining time: the overhead of each call  layer (scheduling, argument evaluation, function prologues) silently erodes  the budget, and the second sub-operation receives a shorter effective timeout  than intended. With an absolute deadline, every layer in the stack sees the  same instant and no time is lost in translation.

This is the same reasoning behind Go's `context.WithDeadline` - Go provides both `WithTimeout` (relative) and `WithDeadline` (absolute), but recommends  deadlines for composable, multi-layer operations because the absolute instant  propagates without drift. Kotlin's `withTimeout` is duration-based, but  Kotlin's coroutine scope carries a single deadline internally and computes the  minimum against any new timeout, which is effectively what the nested  `withDeadline` composition in this proposal achieves explicitly.

The rejection however does not apply when the funnel point of the deadline functionality is sent to an entry point handling the composition by using  instants and composing with the current deadline by a minimum function.

### @Sendable and @escaping Closure

An earlier design considered using `@Sendable` and `@escaping` for the closure parameter. This approach was rejected because it severely limited composability. The `@Sendable` requirement prevented accessing actor-isolated state, making it difficult to use in isolated contexts. The final design uses `nonisolated(nonsending)` to enable better composition while maintaining safety.

### Naming

The naming of this API has a notable lineage: during the development of  [SE-0329](0329-clock-instant-duration.md), the type now called `Instant` was  originally named `Deadline` (v1.1), and was later renamed to `Instant` because  that name better describes a general-purpose point in time. The name `Deadline`  is now reclaimed for its original intended purpose - expressing a temporal bound  by which work must complete - while `Instant` serves as the underlying type that  represents the point in time.

Some feedback was posed to name this function around the cancellation behavior; along the lines of `withAutomaticTaskCancellation`. This naming does not focus  upon the time related qualities of the concept of deadlines, which is the primary behavioral aspect of this API. The cancellation behavior is part of the realities of how the language level concept of cooperative cancellation works and in reading the code at a potential call site it is more meaningful to convey the temporal nature of a deadline than to convey the cancellation being automatic. Immediately the question that would be posed by folks unaware of this new API would be: "What automatic mechanism makes that cancellation happen?" rather than realizing without ambiguity that a concept of time is involved by knowing it is a deadline.

Since the closure may itself use `withTaskCancellationHandler` or catch cancellation errors to return a nullable result or some other partial result it then makes the most sense to even avoid names like `withCancellationDeadline`.

One proposed name that does make some sense to infer the cooperative cancellation nature  of `withDeadline` was a name of `withTaskDeadline` to infer the interoperation with the Concurrency primitive Task (and TaskGroup's child tasks). Even though that naming wise this has more appeal than other alternative names the major issue is that there is no real potential of any other deadline being introduced. So the `Task` portion of that name is extraneous.

From a nomenclature standpoint, `withDeadline` would be a term of art for Swift. By its nature has an implication of cooperative cancellation due to the design of Swift's  concurrency runtime and by that implication also interacts solely with tasks. This  follows suit with other languages like Kotlin - the naming in that case is withTimeout because the timeout in that case is an elapsed duration instead of a deadline instant. The name `withDeadline` also reads naturally at the call site - `try await withDeadline(...)`  immediately communicates to the reader that a temporal bound is in effect, which aids code  review and debugging. Names centered on the mechanism (`withAutomaticTaskCancellation`)  require the reader to infer the temporal aspect, while names centered on the concept  (`withDeadline`) let the reader infer the mechanism from context.

### Previous Incarnations

The clock was originally suggested as a generic clock originally, however when  moving to a composable interface the clock was made to be concrete to the  `ContinuousClock`. This ended up being too restrictive so that was relaxed to where a generic clock was used but restricted to a clock with the `Instant.Duration` that is `Swift.Duration`. This constraint allows for the composition of expirations and in the cases of differing clocks an approximation of the expiry is made by using the delta from now as an offset.

### Separate DeadlineExceededError type

An alternative design would introduce a distinct `DeadlineExceededError` type rather than extending `CancellationError` with a `Reason`. This was considered and rejected for several reasons:

1. **Typed throws compatibility**: Because `withDeadline` preserves the typed failure     of the operation closure via `throws(Failure)`, introducing a new error type would     require a wrapper like `TimeoutError<Failure>` that conflates two concerns - the     deadline expiration and the operation's own error domain. This forces every caller     to destructure a wrapper type even in the common case where they simply want to     know whether the operation failed. 2. **Composability with existing cancellation handlers**: Code that already uses     `withTaskCancellationHandler` or checks `Task.isCancelled` would not observe a     `DeadlineExceededError` - it would appear as an ordinary error rather than a     cancellation. By expressing deadline expiration as a reason on `CancellationError`,     all existing cancellation-aware code automatically participates in deadline behavior. 3. **Consistency with the cooperative cancellation model**: Deadline expiration is     mechanically a cancellation - the task is cancelled and the operation responds     cooperatively. Using the same error type with an enriched reason preserves this     semantic identity rather than introducing a parallel concept.

### Task-installed deadlines

[SE-0304](0304-structured-concurrency.md) originally envisioned that "a deadline can  be installed on a task and naturally propagate through arbitrary levels of API, including  to child tasks." An alternative design following this model would attach a deadline  directly to the task, making it implicitly visible to all child tasks without explicit  nesting. This approach was not taken because:

1. Implicit propagation through task-local state would make it difficult to reason about     which deadline is in effect at any given point, especially when library code installs     its own deadlines. 2. The explicit nesting model composes transparently - each `withDeadline` scope is     visible in the source code, and the minimum-expiration composition rule is easy to     reason about. 3. Nothing in this proposal precludes a future task-installed deadline mechanism; the     explicit `withDeadline` API would remain useful even if such a mechanism were added.

## Changelog

- 1.1 Returned for revision   - The typed throws signature was altered to avoid an extra error type   - Removed the restriction around the instant requiring the duration type to be `Swift.Duration`   - The accessor for the current deadline was removed due to difficulty for using any InstantProtocol   - A new interface on CancellationError was added to handle the reasons for why a task or child task is cancelled (including a deadline exceeded reason).  - 1.0 Initial revision
