|
3 | 3 | * Proposal: [SE-0430](0430-transferring-parameters-and-results.md)
|
4 | 4 | * Authors: [Michael Gottesman](https://github.com/gottesmm), [Holly Borla](https://github.com/hborla), [John McCall](https://github.com/rjmccall)
|
5 | 5 | * Review Manager: [Becca Royal-Gordon](https://github.com/beccadax)
|
6 |
| -* Status: **Implemented (Swift 6.0)** |
| 6 | +* Status: **Active Review (June 21 ... 28, 2024)** |
| 7 | +* Implementation: Implemented in Swift 6.0 except for amendment under review |
7 | 8 | * Previous Proposal: [SE-0414: Region-based isolation](/proposals/0414-region-based-isolation.md)
|
8 |
| -* Review: ([pitch](https://forums.swift.org/t/pitch-transferring-isolation-regions-of-parameter-and-result-values/70240)) ([first review](https://forums.swift.org/t/se-0430-transferring-isolation-regions-of-parameter-and-result-values/70830)) ([returned for revision](https://forums.swift.org/t/returned-for-revision-se-0430-transferring-isolation-regions-of-parameter-and-result-values/71297)) ([second review](https://forums.swift.org/t/se-0430-second-review-sendable-parameter-and-result-values/71685)) ([acceptance with modifications](https://forums.swift.org/t/accepted-with-modifications-se-0430-second-review-sendable-parameter-and-result-values/71850)) |
| 9 | +* Previous Revisions: [1](https://github.com/apple/swift-evolution/blob/87943205551af43682ef50260816f3ff2ef9b7ea/proposals/0430-transferring-parameters-and-results.md) [2](https://github.com/apple/swift-evolution/blob/4dded8ed382b526a5a301c225a1d45018f8d556b/proposals/0430-transferring-parameters-and-results.md) |
| 10 | +* Review: ([pitch](https://forums.swift.org/t/pitch-transferring-isolation-regions-of-parameter-and-result-values/70240)) ([first review](https://forums.swift.org/t/se-0430-transferring-isolation-regions-of-parameter-and-result-values/70830)) ([returned for revision](https://forums.swift.org/t/returned-for-revision-se-0430-transferring-isolation-regions-of-parameter-and-result-values/71297)) ([second review](https://forums.swift.org/t/se-0430-second-review-sendable-parameter-and-result-values/71685)) ([acceptance with modifications](https://forums.swift.org/t/accepted-with-modifications-se-0430-second-review-sendable-parameter-and-result-values/71850)) ([amendment pitch](https://forums.swift.org/t/pitch-revise-se-0430-to-adopt-sending-on-unsafecontinuation/72289)) ([amendment review](https://forums.swift.org/t/amendment-se-0430-sending-parameter-and-result-values/72653)) |
9 | 11 |
|
10 | 12 |
|
11 | 13 | ## Introduction
|
@@ -370,12 +372,12 @@ struct Y2: P1 {
|
370 | 372 | }
|
371 | 373 | ```
|
372 | 374 |
|
373 |
| -### `sending inout` parameters |
| 375 | +### `inout sending` parameters |
374 | 376 |
|
375 | 377 | A `sending` parameter can also be marked as `inout`, meaning that the argument
|
376 | 378 | value must be in a disconnected region when passed to the function, and the
|
377 | 379 | parameter value must be in a disconnected region when the function
|
378 |
| -returns. Inside the function, the `sending inout` parameter can be merged with |
| 380 | +returns. Inside the function, the `inout sending` parameter can be merged with |
379 | 381 | actor-isolated callees or further sent as long as the parameter is
|
380 | 382 | re-assigned a value in a disconnected region upon function exit.
|
381 | 383 |
|
@@ -404,17 +406,15 @@ so there is no way to change the default ownership convention of a
|
404 | 406 | ### Adoption in the Concurrency library
|
405 | 407 |
|
406 | 408 | There are several APIs in the concurrency library that send a parameter across
|
407 |
| -isolation boundaries and don't need the full guarnatees of `Sendable`. These |
| 409 | +isolation boundaries and don't need the full guarantees of `Sendable`. These |
408 | 410 | APIs will instead adopt `sending` parameters:
|
409 | 411 |
|
410 | 412 | * `CheckedContinuation.resume(returning:)`
|
| 413 | +* `UnsafeContinuation.resume(returning:)` |
411 | 414 | * `Async{Throwing}Stream.Continuation.yield(_:)`
|
412 | 415 | * `Async{Throwing}Stream.Continuation.yield(with:)`
|
413 | 416 | * The `Task` creation APIs
|
414 | 417 |
|
415 |
| -Note that this list does not include `UnsafeContinuation.resume(returning:)`, |
416 |
| -because `UnsafeContinuation` deliberately opts out of correctness checking. |
417 |
| - |
418 | 418 | ## Source compatibility
|
419 | 419 |
|
420 | 420 | In the Swift 5 language mode, `sending` diagnostics are suppressed under
|
@@ -481,3 +481,66 @@ It was also suggested that perhaps instead of renaming `transferring` to
|
481 | 481 | authors since it runs into the same problem as `transferring` namely that it is
|
482 | 482 | suggesting that the value is actively being moved to another isolation domain,
|
483 | 483 | when we are expressing a latent capability of the value.
|
| 484 | + |
| 485 | +### Exclude `UnsafeContinuation` |
| 486 | + |
| 487 | +An earlier version of this proposal excluded |
| 488 | +`UnsafeContinuation.resume(returning:)` from the list of standard library |
| 489 | +APIs that adopt `sending`. This meant that `UnsafeContinuation` didn't |
| 490 | +require either the return type to be `Sendable` or the return value to be |
| 491 | +`sending`. Since `UnsafeContinuation` is unconditionally `Sendable`, this |
| 492 | +effectively made it a major hole in sendability checking. |
| 493 | + |
| 494 | +This was an intentional choice. The reasoning was that `UnsafeContinuation` |
| 495 | +was already an explicitly unsafe type, and so it's not illogical for it |
| 496 | +to also work as an unsafe opt-out from sendability checks. There are some |
| 497 | +uses of continuations that do need an opt-out like this. For example, it |
| 498 | +is not uncommon for a continuation to be resumed from a context that's |
| 499 | +isolated to the same actor as the context that called `withUnsafeContinuation`. |
| 500 | +In this situation, the data flow through the continuation is essentially |
| 501 | +internal to the actor. This means there's no need for any sendability |
| 502 | +restrictions; both `sending` and `Sendable` would be over-conservative. |
| 503 | + |
| 504 | +However, the nature of the unsafety introduced by this exclusion is very |
| 505 | +different from the normal unsafety of an `UnsafeContinuation`. |
| 506 | +Continuations must be resumed exactly once; that's the condition that |
| 507 | +`CheckedContinuation` checks. If a programmer can prove that |
| 508 | +they will do that to their own satisfaction, they should be able to use |
| 509 | +`UnsafeContinuation` instead of `CheckedContinuation` in full confidence. |
| 510 | +Making `UnsafeContinuation` *also* a potential source of concurrency-safety |
| 511 | +holes is likely to be surprising to programmers. |
| 512 | + |
| 513 | +Conversely, if a programmer needs to opt out of sendability checks but |
| 514 | +is *not* confident about how many times their continuation will be |
| 515 | +resumed --- for example, if it's resumed from an arbitrary callback --- |
| 516 | +forcing them to adopt `UnsafeContinuation` in order to achieve their |
| 517 | +goal is actively undesirable. |
| 518 | + |
| 519 | +Not requiring `sending` in `UnsafeContinuation` also makes the high-level |
| 520 | +interfaces of `UnsafeContinuation` and `CheckedContinuation` inconsistent. |
| 521 | +This means that programmers cannot always easily move from an unsafe to a |
| 522 | +checked continuation. That is a common need, for example when fixing |
| 523 | +a bug and trying to prove that the unsafe continuation is not implicated. |
| 524 | + |
| 525 | +Swift has generally resisted adding new dimensions of unsafety to unsafe |
| 526 | +types this way. For example, `UnsafePointer` was originally specified as |
| 527 | +unconditionally `Sendable` in [SE-0302][], but that conformance was |
| 528 | +removed in [SE-0331][], and pointers are now unconditionally |
| 529 | +non-`Sendable`. The logic in both of those proposals closely parallels |
| 530 | +this one: at first, `UnsafePointer` was seen as an unsafe type that should |
| 531 | +not be burdened with partial safety checks, and then the community |
| 532 | +recognized that this was actually adding a new dimension of unsafety to |
| 533 | +how the type interacted with concurrency. |
| 534 | + |
| 535 | +Finally, there is already a general unsafe opt-out from sendability |
| 536 | +checking: `nonisolated(unsafe)`. It is better for Swift to encourage |
| 537 | +consistent use of a single unsafe opt-out than to build *ad hoc* |
| 538 | +opt-outs into many different APIs, because it is much easier to find, |
| 539 | +recognize, and audit uses of the former. |
| 540 | + |
| 541 | +For these reasons, `UnsafeContinuation.resume(returning:)` now requires |
| 542 | +its argument to be `sending`, and the result of `withUnsafeContinuation` |
| 543 | +is correspondingly now marked as `sending`. |
| 544 | + |
| 545 | +[SE-0302]: https://github.com/apple/swift-evolution/blob/main/proposals/0302-concurrent-value-and-concurrent-closures.md |
| 546 | +[SE-0331]: https://github.com/apple/swift-evolution/blob/main/proposals/0331-remove-sendable-from-unsafepointer.md |
0 commit comments